CoRN.model.structures.QnnInf


Require QnonNeg.
Import QnonNeg.notations.

Require Import QposInf.

Inductive T: Set := Infinite | Finite (q: QnonNeg).

Definition eq (x y: T): Prop :=
  match x, y with
  | Finite x', Finite y' ⇒ (x' == y')%Qnn
  | Infinite, InfiniteTrue
  | _, _False
  end.

Global Instance: Equivalence eq.
Proof with intuition.
 unfold eq.
 split; repeat intro.
   destruct x...
  destruct x, y...
 destruct x, y, z...
 transitivity q0...
Qed.

Local Infix "==" := eq.

Definition bind (x: T) (f: QnonNegT): T :=
  match x with
  | Finite x'f x'
  | InfiniteInfinite
  end.

Section liftM2.

  Context
    (f: QnonNegQnonNegQnonNeg)
    {p: Proper (QnonNeg.eq ==> QnonNeg.eq ==> QnonNeg.eq) f}.

  Definition liftM2 (x y: T): T := bind x (fun x'bind y (fun y'Finite (f x' y'))).

  Global Instance liftM2_Proper: Proper (eq ==> eq ==> eq) liftM2.
  Proof with intuition. intros [] [] ? [] [] ?... simpl. apply p... Qed.

  Lemma assoc:
    ( x y z, f x (f y z) == f (f x y) z)%Qnn
    ( x y z, liftM2 x (liftM2 y z) == liftM2 (liftM2 x y) z).
  Proof. intros H [] [] []; simpl; auto. Qed.

  Lemma comm:
    ( x y, f x y == f y x)%Qnn
    ( x y, liftM2 x y == liftM2 y x).
  Proof. intros H [] []; simpl; auto. Qed.

End liftM2.

Definition mult := liftM2 QnonNeg.mult.
Definition plus := liftM2 QnonNeg.plus.

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

Lemma plus_comm: x y, x + y == y + x.
Proof comm QnonNeg.plus QnonNeg.plus_comm.
Lemma mult_comm: x y, x × y == y × x.
Proof comm QnonNeg.mult QnonNeg.mult_comm.
Lemma plus_assoc: x y z, x + (y + z) == (x + y) + z.
Proof assoc QnonNeg.plus QnonNeg.plus_assoc.
Lemma mult_assoc: x y z, x × (y × z) == (x × y) × z.
Proof assoc QnonNeg.mult QnonNeg.mult_assoc.

Global Instance: Proper (eq ==> eq ==> eq) plus.
Proof liftM2_Proper _.

Global Instance: Proper (eq ==> eq ==> eq) mult.
Proof liftM2_Proper _.

Definition le (x y: T): Prop :=
  match y with
  | InfiniteTrue
  | Finite y'
    match x with
    | InfiniteFalse
    | Finite x' ⇒ (x' y')
    end
  end.

Global Instance: Proper (eq ==> eq ==> iff) le.
Proof with intuition.
 unfold eq, QnonNeg.eq, le.
 repeat intro.
 destruct x0, y0, y, x...
  rewrite <- H.
  rewrite <- H0...
 unfold QnonNeg.to_Q.
 rewrite H.
 rewrite H0...
Qed.

Global Program Coercion from_QposInf (q: QposInf): T :=
  match q with
  | Qpos2QposInf q'Finite q'
  | QposInfinityInfinite
  end.

Global Coercion Finite: QnonNeg >-> T.

Global Instance Finite_Proper: Proper (QnonNeg.eq ==> eq) Finite.
Proof. repeat intro. assumption. Qed.

Module notations.

  Delimit Scope QnnInf_scope with QnnInf.

  Global Infix "==" := eq: QnnInf_scope.
  Global Infix "≤" := le: QnnInf_scope.
  Global Infix "+" := plus: QnnInf_scope.
  Global Infix "×" := mult: QnnInf_scope.
  Global Notation QnnInf := T.

End notations.