Geometric Series
A geometric series is simple to sum. However we do something slightly more general. We sum a series that satifies the ratio test.
The definition of what we are calling a GeometricSeries: a series
that satifies the ratio test.
err_bound is a bound on how the series could be in terms of its
head elemement.
err_prop: is err an bound on the series s?
Let err_prop (err:Q) (s:Stream Q) : bool :=
match ((err_bound s) ?= err) with
Gt => false
|_ => true
end.
Lemma err_prop_prop : forall e s, err_prop e s <-> err_bound s <= e.
match ((err_bound s) ?= err) with
Gt => false
|_ => true
end.
Lemma err_prop_prop : forall e s, err_prop e s <-> err_bound s <= e.
The key lemma bout error bounds.
Lemma err_prop_key : forall (e:Q) (s: Stream Q) (x:Q),
err_prop e s -> Qabs x <= a*e -> Qabs (Qplus' (hd s) x) <= e.
Lemma err_prop_key' : forall (e:Q) (s: Stream Q),
GeometricSeries s -> err_prop e s -> err_prop (a*e) (tl s).
Lemma err_prop_monotone : forall (e0 e1:Q) (s: Stream Q), (e0 <= e1) -> err_prop e0 s -> err_prop e1 s.
Lemma err_prop_monotone' : forall (e:Q) (s: Stream Q), GeometricSeries s -> err_prop e s -> err_prop e (tl s).
err_prop e s -> Qabs x <= a*e -> Qabs (Qplus' (hd s) x) <= e.
Lemma err_prop_key' : forall (e:Q) (s: Stream Q),
GeometricSeries s -> err_prop e s -> err_prop (a*e) (tl s).
Lemma err_prop_monotone : forall (e0 e1:Q) (s: Stream Q), (e0 <= e1) -> err_prop e0 s -> err_prop e1 s.
Lemma err_prop_monotone' : forall (e:Q) (s: Stream Q), GeometricSeries s -> err_prop e s -> err_prop e (tl s).
InfiniteSum is sums the series s.
InfiniteSum_raw_F is the body of the fixpoint. It tests the error of the partial sum and bails out early if the error becomes small enough.
InfiniteSum_raw_F is the body of the fixpoint. It tests the error of the partial sum and bails out early if the error becomes small enough.
Definition InfiniteSum_raw_F rec (err_prop:Stream Q -> bool) (s:Stream Q) : Q :=
if (err_prop s) then 0 else (Qplus' (hd s) (rec err_prop (tl s))).
if (err_prop s) then 0 else (Qplus' (hd s) (rec err_prop (tl s))).
By carefully using continuations, we can efficently compute n
iterations of InfiniteSum_raw_F with call-by-value.
Fixpoint InfiniteSum_raw_N (n:positive) (cont: (Stream Q -> bool) -> Stream Q -> Q) {struct n} : (Stream Q -> bool) -> Stream Q -> Q :=
match n with
| xH => InfiniteSum_raw_F cont
| xO n' => InfiniteSum_raw_N n' (fun err s => InfiniteSum_raw_N n' cont err s)
| xI n' => InfiniteSum_raw_F (fun err s =>
(InfiniteSum_raw_N n' (fun err s => InfiniteSum_raw_N n' cont err s)) err s)
end.
match n with
| xH => InfiniteSum_raw_F cont
| xO n' => InfiniteSum_raw_N n' (fun err s => InfiniteSum_raw_N n' cont err s)
| xI n' => InfiniteSum_raw_F (fun err s =>
(InfiniteSum_raw_N n' (fun err s => InfiniteSum_raw_N n' cont err s)) err s)
end.
Lemmas for reasoning about InfiniteSum_raw_N.
Lemma InfiniteSum_raw_N_F : forall p c,
InfiniteSum_raw_N p (fun err s => InfiniteSum_raw_F c err s)=
InfiniteSum_raw_F (fun err s => InfiniteSum_raw_N p c err s).
Lemma InfiniteSum_raw_N_Psucc : forall p c,
InfiniteSum_raw_N (Psucc p) c =
InfiniteSum_raw_F (fun err s => InfiniteSum_raw_N p c err s).
Lemma InfiniteSum_raw_N_extend' : forall (p q:positive) s (err : Stream Q -> bool),
(err (Str_nth_tl (nat_of_P p) s)) -> (p <= q)%Z ->
InfiniteSum_raw_N p (fun _ _ => 0) err s = InfiniteSum_raw_N q (fun _ _ => 0) err s.
Lemma InfiniteSum_raw_N_extend : forall (p:positive) s (err : Stream Q -> bool),
(err (Str_nth_tl (nat_of_P p) s)) ->
InfiniteSum_raw_N p (fun _ _ => 0) err s = InfiniteSum_raw_N (Psucc p) (fun _ _ => 0) err s.
Lemma InfiniteSum_raw_N_ind : forall (err:Stream Q -> bool) (P:Stream Q -> Q -> Prop),
(forall s, (err s) -> P s 0) ->
(forall s rec, ~(err s) -> P (tl s) rec -> P s (Qplus' (hd s) rec)) ->
forall (p:positive) s, (err (Str_nth_tl (nat_of_P p) s)) -> P s (InfiniteSum_raw_N p (fun err s => 0) err s).
InfiniteSum_raw_N p (fun err s => InfiniteSum_raw_F c err s)=
InfiniteSum_raw_F (fun err s => InfiniteSum_raw_N p c err s).
Lemma InfiniteSum_raw_N_Psucc : forall p c,
InfiniteSum_raw_N (Psucc p) c =
InfiniteSum_raw_F (fun err s => InfiniteSum_raw_N p c err s).
Lemma InfiniteSum_raw_N_extend' : forall (p q:positive) s (err : Stream Q -> bool),
(err (Str_nth_tl (nat_of_P p) s)) -> (p <= q)%Z ->
InfiniteSum_raw_N p (fun _ _ => 0) err s = InfiniteSum_raw_N q (fun _ _ => 0) err s.
Lemma InfiniteSum_raw_N_extend : forall (p:positive) s (err : Stream Q -> bool),
(err (Str_nth_tl (nat_of_P p) s)) ->
InfiniteSum_raw_N p (fun _ _ => 0) err s = InfiniteSum_raw_N (Psucc p) (fun _ _ => 0) err s.
Lemma InfiniteSum_raw_N_ind : forall (err:Stream Q -> bool) (P:Stream Q -> Q -> Prop),
(forall s, (err s) -> P s 0) ->
(forall s rec, ~(err s) -> P (tl s) rec -> P s (Qplus' (hd s) rec)) ->
forall (p:positive) s, (err (Str_nth_tl (nat_of_P p) s)) -> P s (InfiniteSum_raw_N p (fun err s => 0) err s).
The infinite sum is indeed bounded by an error bound.
Lemma err_prop_correct : forall (e:Qpos) s, (GeometricSeries s) -> (err_prop e s) ->
forall (p:positive) (e':Stream Q -> bool),
(e' (Str_nth_tl (nat_of_P p) s)) -> Qabs (InfiniteSum_raw_N p (fun err s => 0) e' s) <= e.
forall (p:positive) (e':Stream Q -> bool),
(e' (Str_nth_tl (nat_of_P p) s)) -> Qabs (InfiniteSum_raw_N p (fun err s => 0) e' s) <= e.
This lemma tells us how to compute an upper bound on the number of
terms we will need to compute. It is okay for this error to be loose
because the partial sums will bail out early when it sees that its
estimate of the error is small enough.
Lemma GeometricCovergenceLemma : forall (n:positive) (e:Qpos),
/(e*(1 - a)) <= n -> a^n <= e.
Definition InfiniteGeometricSum_maxIter series (err:Qpos) : positive :=
let x := (1-a) in
let (n,d) := (Qabs (hd series))/(err*x*x) in
match Zsucc (Zdiv n d) with
| Zpos p => p
| _ => 1%positive
end.
Lemma InfiniteGeometricSum_maxIter_monotone : forall series (err:Qpos),
GeometricSeries series ->
(InfiniteGeometricSum_maxIter (tl series) err <= InfiniteGeometricSum_maxIter series err)%Z.
Lemma InfiniteGeometricSum_maxIter_correct : forall series (err:Qpos), GeometricSeries series ->
err_prop err (Str_nth_tl (nat_of_P (InfiniteGeometricSum_maxIter series err)) series).
/(e*(1 - a)) <= n -> a^n <= e.
Definition InfiniteGeometricSum_maxIter series (err:Qpos) : positive :=
let x := (1-a) in
let (n,d) := (Qabs (hd series))/(err*x*x) in
match Zsucc (Zdiv n d) with
| Zpos p => p
| _ => 1%positive
end.
Lemma InfiniteGeometricSum_maxIter_monotone : forall series (err:Qpos),
GeometricSeries series ->
(InfiniteGeometricSum_maxIter (tl series) err <= InfiniteGeometricSum_maxIter series err)%Z.
Lemma InfiniteGeometricSum_maxIter_correct : forall series (err:Qpos), GeometricSeries series ->
err_prop err (Str_nth_tl (nat_of_P (InfiniteGeometricSum_maxIter series err)) series).
The implemenation of InfiniteGeometricSum.
Definition InfiniteGeometricSum_raw series (e:QposInf) : Q :=
match e with
| ∞ => 0
| Qpos2QposInf err => InfiniteSum_raw_N (InfiniteGeometricSum_maxIter series err)
(fun err s => 0) (err_prop err) series
end.
Lemma InfiniteGeometricSum_raw_prf : forall series, GeometricSeries series ->
is_RegularFunction (InfiniteGeometricSum_raw series).
Definition InfiniteGeometricSum series (Gs:GeometricSeries series) : CR :=
Build_RegularFunction (InfiniteGeometricSum_raw_prf Gs).
match e with
| ∞ => 0
| Qpos2QposInf err => InfiniteSum_raw_N (InfiniteGeometricSum_maxIter series err)
(fun err s => 0) (err_prop err) series
end.
Lemma InfiniteGeometricSum_raw_prf : forall series, GeometricSeries series ->
is_RegularFunction (InfiniteGeometricSum_raw series).
Definition InfiniteGeometricSum series (Gs:GeometricSeries series) : CR :=
Build_RegularFunction (InfiniteGeometricSum_raw_prf Gs).
The InfiniteGeometricSum is correct.
Lemma InfiniteGeometricSum_step : forall series (Gs:GeometricSeries series),
(InfiniteGeometricSum Gs ==
('(hd series))+(InfiniteGeometricSum (ForAll_Str_nth_tl 1%nat Gs)))%CR.
Lemma InfiniteGeometricSum_bound : forall series
(Gs:GeometricSeries series),
AbsSmall (R:=CRasCOrdField) ('(err_bound series))%CR (InfiniteGeometricSum Gs).
Lemma InfiniteGeometricSum_small_tail : forall series (e : Q+),
GeometricSeries series ->
{n : N & forall Gs : GeometricSeries (Str_nth_tl n series),
AbsSmall (R:=CRasCOrdField) (' e)%CR (InfiniteGeometricSum Gs)}.
Lemma GeometricSeries_convergent : forall (series:Stream Q),
GeometricSeries series ->
convergent (fun n => inj_Q IR (Str_nth n series)).
Lemma InfiniteGeometricSum_correct : forall (series:Stream Q) (x:nat -> IR),
(forall n:nat, inj_Q IR (Str_nth n series)%Q[=]x n) ->
forall (Gs:GeometricSeries series) H,
(InfiniteGeometricSum Gs==IRasCR (∑0∞ x H))%CR.
Lemma InfiniteGeometricSum_correct' : forall (series:Stream Q),
forall (Gs:GeometricSeries series),
(InfiniteGeometricSum Gs == IRasCR (∑0∞ _ (GeometricSeries_convergent Gs)))%CR.
End GeometricSeries.
(InfiniteGeometricSum Gs ==
('(hd series))+(InfiniteGeometricSum (ForAll_Str_nth_tl 1%nat Gs)))%CR.
Lemma InfiniteGeometricSum_bound : forall series
(Gs:GeometricSeries series),
AbsSmall (R:=CRasCOrdField) ('(err_bound series))%CR (InfiniteGeometricSum Gs).
Lemma InfiniteGeometricSum_small_tail : forall series (e : Q+),
GeometricSeries series ->
{n : N & forall Gs : GeometricSeries (Str_nth_tl n series),
AbsSmall (R:=CRasCOrdField) (' e)%CR (InfiniteGeometricSum Gs)}.
Lemma GeometricSeries_convergent : forall (series:Stream Q),
GeometricSeries series ->
convergent (fun n => inj_Q IR (Str_nth n series)).
Lemma InfiniteGeometricSum_correct : forall (series:Stream Q) (x:nat -> IR),
(forall n:nat, inj_Q IR (Str_nth n series)%Q[=]x n) ->
forall (Gs:GeometricSeries series) H,
(InfiniteGeometricSum Gs==IRasCR (∑0∞ x H))%CR.
Lemma InfiniteGeometricSum_correct' : forall (series:Stream Q),
forall (Gs:GeometricSeries series),
(InfiniteGeometricSum Gs == IRasCR (∑0∞ _ (GeometricSeries_convergent Gs)))%CR.
End GeometricSeries.