CoRN.model.structures.NNUpperR


Require Import
  Qabs Qordfield Qpossec Qminmax Ring Program.

Require QnonNeg.
Import QnonNeg.notations.

Local Hint Resolve Qle_refl.

Open Local Scope Q_scope.


Definition pred_eq {X} (p q: XProp): Prop := x, p x q x.

Instance: X, Equivalence (@pred_eq X) := {}.


Lemma Qplus_wiggle (x y z : Q):
  0 x → 0 yx + y < z e: Qpos, x + e + y < z.
Proof with auto.
 intros ?? E.
 destruct (Qpos_lt_plus E) as [e F].
  ((1#2) × e)%Qpos.
 rewrite F.
 simpl. ring_simplify.
 apply Qplus_lt_l.
 do 2 rewrite (Qplus_comm x).
 apply Qplus_lt_l.
 rewrite <- (Qmult_1_l e) at 2.
 apply Qmult_lt_compat_r...
 reflexivity.
Qed.

Lemma Qmult_wiggle (x y z : Q):
  0 x → 0 yx × y < z e : Qpos, (x + e) × y < z.
Proof with auto with ×.
 intros xnn ynn xyz.
 destruct (Qdec_sign y) as [[A|B]|C].
   exfalso. apply Qle_not_lt with 0 y...
  destruct (Qpos_lt_plus xyz) as [e E].
   (e / ((2#1) × exist (Qlt 0) y B))%Qpos.
  rewrite E.
  rewrite Qmult_plus_distr_l.
  do 2 rewrite (Qplus_comm (x × y)).
  apply Qplus_lt_l.
  simpl.
  setoid_replace (e × / ((2 # 1) × y) × y) with (/ (2 # 1) × e) by (simpl; field)...
  rewrite <- (Qmult_1_l e) at 2.
  apply Qmult_lt_compat_r...
  (1#1)%Qpos. revert xyz.
 rewrite C, Qmult_0_r, Qmult_0_r...
Qed.

Lemma Qmid (x y: Q): x < y
 let mid := (1#2)%Qpos*(x+y) in
  x < mid mid < y.
Proof with auto; try reflexivity.
 intros. subst mid.
 split.
  setoid_replace x with (x × (1#2) + x × (1#2)) at 1 by (simpl; ring).
  setoid_replace ((1 # 2) × (x + y)) with (y × (1 # 2) + x × (1 # 2)) by (simpl; ring).
  apply Qplus_lt_l.
  apply Qmult_lt_compat_r...
 setoid_replace y with (y × (1#2) + y × (1#2)) at 2 by (simpl; ring).
 setoid_replace ((1 # 2) × (x + y)) with (x × (1 # 2) + y × (1 # 2)) by (simpl; ring).
 apply Qplus_lt_l.
 apply Qmult_lt_compat_r...
Qed.

Lemma QnonNeg_mid (x y: QnonNeg): ` x < ` y
 let mid := ((1#2) × (x + y))%Qnn in
  ` x < ` mid ` mid < ` y.
Proof.
 intros. subst mid. simpl.
 apply Qmid. assumption.
Qed.

Lemma Qmult_le_compat: x y x' y' : Q, 0 x x' → 0 y y'x × y x' × y'.
Proof.
 intros.
 apply Qle_trans with (x × y').
  do 2 rewrite (Qmult_comm x).
  apply Qmult_le_compat_r; intuition.
 apply Qmult_le_compat_r. intuition.
 apply Qle_trans with y; intuition.
Qed.

Local Hint Resolve Qlt_le_weak.


Record T := make
  { is_bound: QnonNegProp
  ; bound: QnonNeg
  ; closed_le: q q', `q `q'is_bound qis_bound q'
  ; bound_is_bound: is_bound bound }.



Hint Immediate bound_is_bound.

Instance is_bound_Proper: (x: T), Proper (QnonNeg.eq ==> iff) (is_bound x).
Proof with auto.
 unfold QnonNeg.eq. intros x y z E.
 split; intro.
  apply closed_le with y... rewrite E...
 apply closed_le with z... rewrite E...
Qed.

Definition le (x y: T): Prop := q, is_bound y q r, `q < `ris_bound x r.

Local Infix "≤" := le.

Lemma le_refl (x: T): x x.
Proof. repeat intro. apply closed_le with q; auto. Qed.

Lemma le_trans (x y z: T): x yy zx z.
Proof with auto.
 intros xley ylez q zq r qr.
 destruct (QnonNeg_mid q r qr).
 apply (xley ((1#2)*(q+r))%Qnn)...
 apply (ylez q)...
Qed.

Definition eq (x y: T): Prop := x y y x.

Local Infix "==" := eq.

Global Instance: Proper (eq ==> eq ==> iff) le.
Proof with intuition.
 unfold eq. intros x y ? a b ?.
 split; intro.
  apply le_trans with x...
  apply le_trans with a...
 apply le_trans with y...
 apply le_trans with b...
Qed.

Global Instance: Equivalence eq.
Proof with intuition.
 unfold eq.
 split; repeat intro...
    apply le_refl.
   apply le_refl.
  apply le_trans with y...
 apply le_trans with y...
Qed.

Global Program Coercion inject_Qnn (q: QnonNeg): T := make (Qle q) q _ _.

Next Obligation. apply Qle_trans with (q0); assumption. Qed.

Global Instance: Proper (QnonNeg.eq ==> eq) inject_Qnn.
Proof with auto.
 unfold eq, le.
 intros ?? H.
 split; simpl; intros.
  rewrite H. apply Qle_trans with (`q)...
 rewrite <- H. apply Qle_trans with (`q)...
Qed.

Definition bound_doesnt_matter (q: QnonNeg) b H H' U U':
  make (Qle q) b H U == make (Qlt q) b H' U'.
Proof with auto.
 unfold eq, le in ×. simpl.
 split; intros e ???.
  apply Qle_trans with (`e)...
 apply Qle_lt_trans with (`e)...
Qed.

Section binop.
  Variables
    (o: QQQ) (u: Q) (u_ok: (0 u)%Q)
    (o_ok: ( x y, 0 x → 0 y → 0 o x y)%Q)
    (o_comm: ( x y, o x y == o y x)%Q)
    (o_assoc: ( x y z, o x (o y z) == o (o x y) z)%Q)
    (o_le_compat: ( x y x' y', 0 x x' → 0 y y'o x y o x' y')%Q)
    (o_u_left: ( x, o u x == x)%Q)
    (o_sneaky: ( (x y z: Q), 0 x → 0 yo x y < z e: Qpos, o (x + e) y < z)%Q).

  Definition u_nn: QnonNeg := exist _ _ u_ok.

  Definition o_nn := QnonNeg.binop o o_ok.

  Inductive BinopBound (x y: QnonNegProp): (QnonNegProp) :=
    is_binop_bound (q q': QnonNeg): x qy q'
       (r: QnonNeg), (o (` q) (` q') ` r)%QBinopBound x y r.

  Lemma BinopBound_le x y a b: (`a `b)%QBinopBound x y aBinopBound x y b.
  Proof with auto.
   intros E B. revert B E.
   intros [v w xv yw r F] E.
   apply (is_binop_bound x y v w)...
   apply Qle_trans with (`r)...
  Qed.

  Instance BinopBound_Proper: Proper (pred_eq ==> pred_eq ==> QnonNeg.eq ==> iff) BinopBound.
  Proof with auto.
   unfold Proper, respectful.
   cut ( x y x0 y0 x1 y1, pred_eq x ypred_eq x0 y0
     (`x1 == `y1)%QBinopBound x x0 x1BinopBound y y0 y1).
    split; apply H; auto; symmetry...
   intros ?????? U V A B. revert B A.
   intros [v w xv yw r F] E.
   apply (is_binop_bound _ _ v w).
     apply U...
    apply V...
   apply Qle_trans with (`r)...
   rewrite E...
  Qed.

  Lemma BinopBound_sym x y: pred_eq (BinopBound x y) (BinopBound y x).
  Proof with auto.
   split; intros [a b xa yb r E].
    apply (is_binop_bound y x b a yb xa). rewrite o_comm...
   apply (is_binop_bound x y b a yb xa). rewrite o_comm...
  Qed.

  Lemma BinopBound_assoc (n m p: T) (q: QnonNeg):
    BinopBound (is_bound n) (BinopBound (is_bound m) (is_bound p)) q
    BinopBound (BinopBound (is_bound n) (is_bound m)) (is_bound p) q.
  Proof with auto.
   intros [a b na [v w z x y E] c F].
   apply BinopBound_le with (o_nn (o_nn a v) w).
    simpl.
    apply Qle_trans with (o (`a) (`y))...
    rewrite <- o_assoc.
    apply o_le_compat; split...
   apply is_binop_bound with (o_nn a v) w...
   apply is_binop_bound with a v...
  Qed.

  Program Definition binop (x y: T): T :=
    make (BinopBound (is_bound x) (is_bound y)) (o_nn (bound x) (bound y)) _ _.

  Next Obligation.    apply BinopBound_le with (exist _ q H2); auto.
  Qed.

  Next Obligation.    apply (is_binop_bound (is_bound x) (is_bound y) (bound x) (bound y)); auto.
  Qed.

  Lemma binop_comm (x y: T): binop x y == binop y x.
  Proof with auto.
   cut ( a b, binop a b binop b a).
    intro H. split; apply H.
   unfold eq, le. simpl. intros.
   inversion H. subst. clear H.
   apply BinopBound_sym.
   apply is_binop_bound with q0 q'...
   apply Qle_trans with (`q)...
  Qed.

  Lemma binop_le_compat_l (x y z: T): x ybinop x z binop y z.
  Proof with auto.
   unfold le. simpl. intros H q [v w yv zw r E s rs].
   specialize (H _ yv).
   assert (o (`v) (`w) < `s) as os. apply Qle_lt_trans with (`r)...
   destruct (o_sneaky _ _ _ (proj2_sig _) (proj2_sig _) os).
   apply (is_binop_bound (is_bound x) (is_bound z)) with (v + x0)%Qnn w...
   apply H. simpl.
   rewrite Qplus_comm. rewrite <- Qplus_0_l at 1. apply Qplus_lt_l...
  Qed.

  Lemma binop_le_compat (x y: T) (v w: T): x yv wbinop x v binop y w.
  Proof.
   intros. apply le_trans with (binop x w);
    [do 2 rewrite (binop_comm x) |]; apply binop_le_compat_l; auto.
  Qed.

  Global Instance binop_Proper: Proper (eq ==> eq ==> eq) binop.
  Proof. unfold eq. repeat intro. split; apply binop_le_compat; intuition. Qed.

  Lemma binop_assoc (n m p: T): binop n (binop m p) == binop (binop n m) p.
  Proof with auto.
   unfold eq, le. simpl.
   split; intros.
    apply BinopBound_sym.
    apply BinopBound_assoc.
    apply BinopBound_sym.
    apply BinopBound_assoc.
    apply BinopBound_sym...
    apply BinopBound_le with q...
   apply BinopBound_assoc.
   apply BinopBound_le with q...
  Qed.

  Lemma binop_unit_left (x: T): binop u_nn x == x.
  Proof with auto.
   unfold eq, le. simpl.
   split.
    intros.
    apply (is_binop_bound) with u_nn q...
    simpl. rewrite o_u_left...
   intros q [q0 q' H1 H2 v H3] r vr.
   apply closed_le with q'...
   apply Qle_trans with (`v)...
   rewrite <- (o_u_left (`q')).
   apply Qle_trans with (o (`q0) (`q'))...
  Qed.

End binop.

Definition plus := binop Qplus QnonNeg.Qplus_nonneg.
Definition mult := binop Qmult Qmult_le_0_compat.

Local Infix "+" := plus.
Local Infix "×" := mult.

Instance: Proper (eq ==> eq ==> eq) plus.
Proof binop_Proper Qplus QnonNeg.Qplus_nonneg Qplus_comm Qplus_wiggle.

Instance: Proper (eq ==> eq ==> eq) mult.
Proof binop_Proper Qmult Qmult_le_0_compat Qmult_comm Qmult_wiggle.

Lemma plus_0_l: x, 0%Qnn + x == x.
Proof.
 refine (binop_unit_left Qplus 0 (Qle_refl _) QnonNeg.Qplus_nonneg _ Qplus_0_l).
 intros. apply Qplus_le_compat; intuition.
Qed.

Lemma plus_comm: x y, x + y == y + x.
Proof binop_comm Qplus QnonNeg.Qplus_nonneg Qplus_comm.

Lemma plus_assoc: n m p, n + (m + p) == (n + m) + p.
Proof.
 apply (binop_assoc Qplus QnonNeg.Qplus_nonneg Qplus_comm Qplus_assoc).
 intros. apply Qplus_le_compat; intuition.
Qed.

Lemma plus_le_compat: x y a b, x ya bx + a y + b.
Proof binop_le_compat Qplus QnonNeg.Qplus_nonneg Qplus_comm Qplus_wiggle.

Lemma Qle_0_1: (0 1)%Q.
Proof. discriminate. Qed.

Lemma mult_1_l: x, 1%Qnn × x == x.
Proof binop_unit_left Qmult 1 Qle_0_1 Qmult_le_0_compat Qmult_le_compat Qmult_1_l.

Lemma mult_comm: x y, x × y == y × x.
Proof binop_comm Qmult Qmult_le_0_compat Qmult_comm.

Lemma mult_assoc: n m p, n × (m × p) == (n × m) × p.
Proof binop_assoc Qmult Qmult_le_0_compat Qmult_comm Qmult_assoc Qmult_le_compat.

Lemma mult_plus_distr n m p: (n + m) × p == n × p + m × p.
Proof with auto; simpl.
 unfold eq. split.
  intros _ [_ _ [e d ?? b ?][g f ?? c ?]a ?] r H0...
  apply BinopBound_le with (e × d + g × f)%Qnn...
   apply Qle_trans with (`b + `c)%Q...
    apply Qplus_le_compat...
   apply Qle_trans with (`a)...
  apply is_binop_bound with (e + g)%Qnn (QnonNeg.min d f)...
    apply is_binop_bound with e g...
   apply QnonNeg.min_case...
   apply (is_bound_Proper p)...
  rewrite Qmult_plus_distr_l.
  apply Qplus_le_compat...
   do 2 rewrite (Qmult_comm (`e)).
   apply Qmult_le_compat_r...
   apply Q.le_min_l.
  do 2 rewrite (Qmult_comm (`g)).
  apply Qmult_le_compat_r...
  apply Q.le_min_r.
 intros q [a b [c d ?? e ?] ? r1 ?] r E...
 apply BinopBound_le with ((c + d) × b)%Qnn...
  apply Qle_trans with (`e × `b)%Q...
   apply Qmult_le_compat_r...
  apply Qle_trans with (`r1)...
 apply is_binop_bound with (c × b)%Qnn (d × b)%Qnn.
   apply is_binop_bound with c b...
  apply is_binop_bound with d b...
 simpl. ring_simplify...
Qed.

Lemma le_closed (e x: T): ( d: Qpos, x e + d) → x e.
Proof with auto.
 unfold le. simpl. intros H q H0 r qr.
 destruct (Qpos_lt_plus qr) as [d E].
 apply (H ((1#2)*d)%Qpos (q + (2#3)*d)%Qnn).
  apply (is_binop_bound Qplus) with q ((1#2)*d)%Qnn...
  simpl.
  apply Qplus_le_compat...
  apply Qmult_le_compat_r...
  discriminate.
 simpl.
 rewrite E.
 do 2 rewrite (Qplus_comm (`q)).
 apply Qplus_lt_l.
 simpl.
 rewrite <- (Qmult_1_l d).
 apply Qmult_lt_compat_r...
 reflexivity.
Qed.

Lemma le_0 x: 0%Qnn x.
Proof. unfold le. simpl. auto. Qed.

Hint Immediate le_0.

Lemma le_0_eq x: x 0%Qnnx == 0%Qnn.
Proof. split. assumption. apply le_0. Qed.

Lemma mult_0_l (x: T): 0%Qnn × x == 0%Qnn.
Proof with auto.
 split... unfold le. simpl. intros.
 apply (is_binop_bound) with 0%Qnn (bound x)...
 simpl. rewrite Qmult_0_l...
Qed.

Lemma plus_homo (x y: QnonNeg): (x + y)%Qnn == x + y.
Proof with auto.
 unfold eq, le. simpl.
 split; intros.
  inversion H. subst. clear H.
  apply Qle_trans with (`q)...
  apply Qle_trans with (`q0 + `q')%Q...
  apply Qplus_le_compat...
 apply (is_binop_bound Qplus) with x y...
 apply Qle_trans with (`q)...
Qed.

Lemma semi_ring: semi_ring_theory (R:=T) 0%Qnn 1%Qnn plus mult eq.
Proof.
 constructor.
        apply plus_0_l.
       apply plus_comm.
      apply plus_assoc.
     apply mult_1_l.
    apply mult_0_l.
   apply mult_comm.
  apply mult_assoc.
 apply mult_plus_distr.
Qed.

Add Ring cut_ring: semi_ring.

Module notations.

  Delimit Scope NNUpperR_scope with Rnnu.

  Global Infix "≤" := le: NNUpperR_scope.
  Global Infix "==" := eq: NNUpperR_scope.
  Global Infix "+" := plus: NNUpperR_scope.
  Global Infix "×" := mult: NNUpperR_scope.

  Global Notation NNUpperR := T.

End notations.


Program Definition sqrt2: T :=
  make (fun x(2#1) x×x)%Q (2#1)%Qnn _ _.

Next Obligation. Proof with auto.
 simpl in ×.
 apply Qle_trans with (q × q)%Q...
 apply Qmult_le_compat...
Qed.


Lemma sqrt2_correct
  (Qsqrt_overapprox: (x: QnonNeg) (e: Qpos), { r: QnonNeg | ` x ` r × ` r ` r × ` r < ` x + e }%Q):
    sqrt2 × sqrt2 == (2#1)%Qnn.
Proof with auto.
 unfold eq, le. simpl.
 split; intros.
  destruct (Qpos_lt_plus H0).
  destruct (Qsqrt_overapprox (2#1)%Qnn x).
  destruct a.
  apply (is_binop_bound Qmult) with x0 x0...
  rewrite q0.
  apply Qle_trans with ((2 # 1)%Q + x)%Q...
  apply Qplus_le_compat...
 inversion_clear H.
 destruct (Qlt_le_dec (`q0) (`q')).
  apply Qle_trans with (`q0×`q0)%Q...
  apply Qle_trans with (`q0×`q')%Q...
   apply Qmult_le_compat...
  apply Qle_trans with (`q)...
 apply Qle_trans with (`q'×`q')%Q...
 apply Qle_trans with (`q0×`q')%Q...
  apply Qmult_le_compat...
 apply Qle_trans with (`q)...
Qed.