Section Limit.
Variable A : Set.
Variable eq : A -> A -> Prop.
Hypothesis eq_dec : forall (a1 a2 : A),
{eq a1 a2} + {~eq a1 a2}.
Hypothesis eq_refl : forall (a : A),
eq a a.
Hypothesis eq_symm : forall a1 a2,
eq a1 a2 ->
eq a2 a1.
Variable distance : A -> A -> A.
Hypothesis distance_comm : forall a1 a2,
eq (distance a1 a2) (distance a2 a1).
Variable half : A -> A.
Variable zero : A.
Hypothesis half_nz : forall (a : A),
~eq a zero ->
~eq (half a) zero.
Hypothesis distance_eq_zero : forall (a1 a2 : A),
eq a1 a2 <->
eq (distance a1 a2) zero.
Hypothesis distance_eq_compat : forall a1 a2 a3 a4,
eq a1 a3 ->
eq a2 a4 ->
eq (distance a1 a2) (distance a3 a4).
Variable le : A -> A -> Prop.
Hypothesis le_eq : forall (a1 a2 : A),
eq a1 a2 ->
le a1 a2.
Hypothesis le_trans : forall (a1 a2 a3 : A),
le a1 a2 ->
le a2 a3 ->
le a1 a3.
(* all numbers positive *)
Hypothesis all_pos : forall (a : A),
le zero a.
Hypothesis le_impl_eq : forall (a1 a2 : A),
le a1 a2 ->
le a2 a1 ->
eq a1 a2.
Variable plus : A -> A -> A.
Variable plus_0_eq : forall (a1 a2 : A),
eq a2 zero ->
eq a1 (plus a1 a2).
Variable plus_le_compat : forall a1 a2 a3 a4,
le a1 a2 ->
le a3 a4 ->
le (plus a1 a3) (plus a2 a4).
Hypothesis triangle_inequality : forall (a1 a2 a3 : A),
le (distance a1 a2) (plus (distance a1 a3) (distance a3 a2)).
Hypothesis half_plus : forall (a : A),
eq (plus (half a) (half a)) a.
Hypothesis le_half : forall (a : A),
le a (half a) ->
eq a zero.
intuition.
destruct (eq_dec a zero).
trivial.
exfalso.
specialize (H (half a)).
apply f.
eapply le_half.
apply H.
eapply half_nz.
trivial.
Qed.
Definition left_total(r : nat -> A -> Prop) :=
forall n, exists a, r n a.
Definition functional(r : nat -> A -> Prop) :=
forall n a1 a2,
r n a1 ->
r n a2 ->
eq a1 a2.
Definition inf_limit(f : nat -> A -> Prop)(a : A) :=
forall (epsilon : A),
~eq epsilon zero ->
exists n : nat,
forall (n' : nat),
n' >= n ->
forall a',
f n' a' ->
le (distance a' a) epsilon.
(* Note: if the codomain of the relation is empty (after any point), then we can assign any limit to it. *)
(* We could define inf_limit in terms of inf_limit_2, but inf_limit_2 only shows up in proofs, while inf_limit shows up in top-level definitions. *)
Definition inf_limit_2(f f' : nat -> A -> Prop) :=
forall (epsilon : A),
~eq epsilon zero ->
exists n : nat,
forall (n' : nat),
n' >= n ->
forall a a',
f n' a ->
f' n' a' ->
le (distance a a') epsilon.
intuition.
Abort.
(*  remember half as h. *)
intuition.
unfold inf_limit in *.
intuition.
specialize (H1 (half epsilon)).
specialize (H2 (half epsilon)).
destruct H1.
intuition.
eapply half_nz; eauto.
destruct H2.
intuition.
eapply half_nz; eauto.
destruct (H (max x x0)).
specialize (H1 (max x x0)).
specialize (H2 (max x x0)).
eapply le_trans.
eapply (triangle_inequality _ _ x1).
eapply le_trans.
eapply plus_le_compat.
eapply le_trans.
eapply le_eq.
eapply distance_comm.
eapply H1.
eapply Max.max_lub_l; eauto.
trivial.
eapply H2.
eapply Max.max_lub_r; eauto.
trivial.
eapply le_eq.
eapply half_plus.
Qed.
intuition.
eapply distance_eq_zero.
eapply le_epsilon_zero.
intuition.
eapply limit_eq_h; eauto.
Qed.
unfold inf_limit; intuition.
destruct (H epsilon).
trivial.
exists x.
intuition.
eapply H2.
eapply H3.
eapply H0.
trivial.
Qed.
End Limit.
(* limits for Rat *)
Local Open Scope rat_scope.
Definition rat_inf_limit(f : nat -> Rat -> Prop)(r : Rat) :=
inf_limit eqRat ratDistance rat0 leRat f r.
Definition rat_inf_limit_2(f1 f2 : nat -> Rat -> Prop) :=
inf_limit_2 eqRat ratDistance rat0 leRat f1 f2.
Definition rat_limits_eq :=
limits_eq eq_Rat_dec ratDistance_comm ratHalf ratHalf_ne_0 ratIdentityIndiscernables eqRat_impl_leRat leRat_trans ratAdd ratAdd_leRat_compat ratTriangleInequality ratHalf_add le_ratHalf_0.
unfold rat_inf_limit_2, inf_limit_2; intuition.
edestruct (H (ratHalf epsilon)).
eapply ratHalf_ne_0; intuition.
edestruct (H0 (ratHalf epsilon)); eauto.
eapply ratHalf_ne_0.
intuition.
exists (max x x0).
intuition.
destruct (H1 n').
eapply leRat_trans.
eapply ratDistance_le_trans.
eapply H3.
eapply Max.max_lub_l.
eapply H5.
trivial.
eapply H8.
eapply H4.
eapply Max.max_lub_r.
eapply H5.
eauto.
trivial.
eapply eqRat_impl_leRat.
eapply ratHalf_add.
Qed.
unfold rat_inf_limit, inf_limit in *.
intuition.
destruct (H epsilon); intuition.
destruct (H0 epsilon); intuition.
exists (max c (max x x0)).
intuition.
destruct (H3 n').
destruct (H4 n').
eapply leRat_trans.
eapply ratDistance_le_max.
eapply H1.
eapply Max.max_lub_l.
eauto.
eapply H9.
eapply H10.
eapply H2.
eapply Max.max_lub_l.
eauto.
eapply H9.
eapply H11.
eapply maxRat_leRat_same; eauto using Max.max_lub_l, Max.max_lub_r.
Qed.
unfold rat_inf_limit, inf_limit.
intuition.
destruct (H epsilon); intuition.
econstructor.
intuition.
specialize (H1 (div2 n')).
eapply H1.
eapply div2_ge; eauto.
eauto.
Qed.
unfold rat_inf_limit, inf_limit in *.
intuition.
edestruct (H1 (ratHalf epsilon)).
eapply ratHalf_ne_0.
intuition.
edestruct (H2 (ratHalf epsilon)).
eapply ratHalf_ne_0.
intuition.
exists (Max.max x x0).
intuition.
unfold ratAdd_rel in *.
destruct (H n').
destruct (H0 n').
rewrite H7; eauto.
eapply leRat_trans.
eapply rat_distance_of_sum.
rewrite H4.
rewrite H5.
rewrite ratHalf_add.
intuition.
eapply Max.max_lub_r.
eauto.
trivial.
eapply Max.max_lub_l.
eauto.
trivial.
Qed.
unfold rat_inf_limit, inf_limit in *.
intuition.
destruct (le_Rat_dec c1 c2).
edestruct (H1 (ratHalf epsilon)).
eapply ratHalf_ne_0.
intuition.
edestruct (H2 (ratHalf epsilon)).
eapply ratHalf_ne_0.
intuition.
exists (Max.max x x0).
intuition.
unfold ratSubtract_rel in *.
destruct (H n').
destruct (H0 n').
rewrite H7; eauto.
rewrite (ratSubtract_0 l).
eapply ratDistance_0_r_le.
eapply leRat_trans.
eapply ratSubtract_partition_leRat.
eapply ratSubtract_ratDistance_le.
2:{
rewrite H4.
rewrite ratHalf_add.
intuition.
eapply Max.max_lub_l.
eauto.
trivial.
}
eapply leRat_trans.
eapply ratSubtract_partition_leRat.
rewrite ratSubtract_0.
eapply leRat_refl.
eapply l.
eapply ratSubtract_ratDistance_le.
rewrite ratDistance_comm.
rewrite H5.
rewrite <- ratAdd_0_l.
intuition.
eapply Max.max_lub_r.
eauto.
trivial.
edestruct (H1 (minRat (ratHalf epsilon) (ratHalf (ratSubtract c1 c2)))).
intuition.
unfold minRat in *.
destruct (bleRat (ratHalf epsilon) (ratHalf (ratSubtract c1 c2))).
eapply ratHalf_ne_0 in H4;
intuition.
eapply ratHalf_ne_0 in H4;
intuition.
eapply n.
eapply ratSubtract_0_inv.
trivial.
edestruct (H2 (minRat (ratHalf epsilon) (ratHalf (ratSubtract c1 c2)))).
intuition.
unfold minRat in *.
destruct (bleRat (ratHalf epsilon) (ratHalf (ratSubtract c1 c2))).
eapply ratHalf_ne_0 in H5;
intuition.
eapply ratHalf_ne_0 in H5;
intuition.
eapply n.
eapply ratSubtract_0_inv.
trivial.
exists (Max.max x x0).
intuition.
destruct (H n').
destruct (H0 n').
unfold ratSubtract_rel in *.
rewrite H7; eauto.
assert (x2 <= x1).
eapply leRat_trans.
eapply ratDistance_le_sum.
eapply H5.
eapply Max.max_lub_r.
eauto.
trivial.
eapply leRat_trans.
eapply ratAdd_leRat_compat.
eapply leRat_refl.
eapply minRat_le_r.
eapply (leRat_ratAdd_same_r (ratHalf (ratSubtract c1 c2))).
rewrite ratAdd_assoc.
rewrite ratHalf_add.
rewrite ratSubtract_ratAdd_inverse_2.
eapply ratDistance_le_sum.
eapply leRat_trans.
rewrite ratDistance_comm.
eapply H4.
eapply Max.max_lub_l.
eauto.
trivial.
eapply minRat_le_r.
case_eq (bleRat c1 c2); intuition.
eapply bleRat_total.
trivial.
eapply leRat_trans.
eapply rat_distance_of_difference.
trivial.
case_eq (bleRat c1 c2); intuition.
eapply bleRat_total.
trivial.
eapply H4.
eapply Max.max_lub_l.
eauto.
trivial.
eapply H5.
eapply Max.max_lub_r.
eauto.
trivial.
rewrite minRat_le_l.
rewrite ratHalf_add.
intuition.
Qed.

Lemma rat_inf_limit_product : forall (f1 f2 : nat -> Rat -> Prop) c1 c2,
left_total f1 ->
left_total f2 ->
rat_inf_limit f1 c1 ->
rat_inf_limit f2 c2 ->
rat_inf_limit (fun n => (ratMult_rel (f1 n) (f2 n))) (c1 * c2).