Module FloatIntervals


Require Import Coqlib Utf8 ToString Util.
Require Import AdomLib.
Require Import FloatLib.

Inductive fitv : Type :=
| FITV: float -> float -> fitv.

Instance FitvToString : ToString fitv :=
  { to_string i :=
      let 'FITV min max := i in
      ("[" ++ to_string min ++ "; " ++ to_string max ++ "]")%string
  }.

Instance fitv_leb : leb_op fitv := fun i1 i2 =>
  let 'FITV min1 max1 := i1 in
  let 'FITV min2 max2 := i2 in
  is_nan min1 || is_nan max1 || (Fleb min2 min1 && Fleb max1 max2).

Lemma leb_eq:
  ∀ i:fitv, ii = true.
Proof.
  destruct i; simpl. unfold leb, fitv_leb.
  destruct (is_nan f) eqn:?, (is_nan f0) eqn:?; auto.
  rewrite 2!Fleb_refl; auto.
Qed.

Instance fitv_join : join_op fitv fitv := fun i1 i2 =>
  let 'FITV min1 max1 := i1 in
  let 'FITV min2 max2 := i2 in
  FITV (if Fleb min1 min2 || is_nan min2 then min1 else min2)
       (if Fleb max2 max1 || is_nan max2 then max1 else max2).

Lemma join_eq:
  ∀ x:fitv, xx = x.
Proof.
destruct x; simpl. unfold join, fitv_join. destruct orb, orb; auto. Qed.

Instance fitv_meet : meet_op fitv (fitv+⊥) := fun i1 i2 =>
  let 'FITV min1 max1 := i1 in
  let 'FITV min2 max2 := i2 in
  let m := if Fleb min1 min2 then min2 else min1 in
  let M := if Fleb max1 max2 then max1 else max2 in
  if Fleb m M then NotBot (FITV m M)
  else Bot.

Definition fitv_widen i1 i2:=
  let 'FITV min1 max1 := i1 in
  let 'FITV min2 max2 := i2 in
  FITV (if Fleb min1 min2 || is_nan min2 then min1
        else B754_infinity true)
       (if Fleb max2 max1 || is_nan max2 then max1
        else B754_infinity false).

Lemma widen_eq:
  ∀ x:fitv, fitv_widen x x = x.
Proof.
  destruct x; simpl.
  destruct (is_nan f) eqn:?, (is_nan f0) eqn:?;
  rewrite ?orb_true_r, ?orb_false_r, ?Fleb_refl; auto.
Qed.

Instance gamma : gamma_op fitv float := fun i v =>
  let 'FITV m M := i in
  Fleb m v = true /\ Fleb v M = true.

Instance fitv_leb_correct : leb_op_correct fitv float.
Proof.
  intros [] []. intros. unfold leb, fitv_leb in H.
  rewrite 2!Bool.orb_true_iff, Bool.andb_true_iff in H.
  destruct H as [[]|[]], H0.
  destruct f; discriminate.
  destruct f0; try discriminate. destruct a as [|[]| |[]]; discriminate.
  split; eapply Fleb_trans; eauto.
Qed.

Instance fitv_join_correct : join_op_correct fitv fitv float.
Proof.
  intros x y ? ?. destruct H, x, y; simpl in *; try tauto.
  + destruct H.
    split.
    * destruct (Fleb f f1) eqn:?. auto.
      destruct (is_nan f1) eqn:?. auto. simpl.
      eapply Fleb_trans; [|eauto].
      destruct (Fleb_total _ _ f f1); eauto 3. congruence.
    * destruct (Fleb f2 f0) eqn:?. auto.
      destruct (is_nan f2) eqn:?. auto. simpl.
      eapply Fleb_trans; [eauto|].
      destruct (Fleb_total _ _ f0 f2); eauto 3. congruence.
  + destruct H.
    split.
    * eapply Fleb_trans; [|eauto].
      destruct (Fleb f f1) eqn:?. auto.
      erewrite Fleb_nan_l by eauto.
      eauto.
    * eapply Fleb_trans; [eauto|].
      destruct (Fleb f2 f0) eqn:?. auto.
      erewrite Fleb_nan_r by eauto.
      eauto.
Qed.

Instance fitv_meet_correct: meet_op_correct fitv (fitv+⊥) float.
Proof.
  intros [mx Mx] [my My] z Hz; simpl in *. unfold meet, fitv_meet.
  destruct Hz as [[] []].
  destruct (Fleb (if Fleb mx my return float then my else mx)
                 (if Fleb Mx My return float then Mx else My)) eqn:?.
  - split.
    + destruct (Fleb mx my); auto.
    + destruct (Fleb Mx My); auto.
  - erewrite Fleb_trans in Heqb. discriminate.
    + destruct (Fleb mx my); eauto.
    + destruct (Fleb Mx My); auto.
Qed.

Lemma widen_incr:
  ∀ ab1 ab2, γ ab1 ⊆ γ (fitv_widen ab1 ab2).
Proof.
  intros ab1 ab2 f Hf. unfold fitv_widen.
  destruct ab1, ab2, Hf; split.
  - destruct (Fleb f0 f2). auto.
    destruct (is_nan f2). auto.
    destruct f; auto. destruct b; auto.
  - destruct (Fleb f3 f1). auto.
    destruct (is_nan f3). auto.
    destruct f; auto. destruct b; auto. destruct b; auto.
Qed.

Definition forward_fneg (x:fitv+⊤) : fitv+⊤ :=
  match x with
  | Just (FITV mx Mx) => Just (FITV (Float.neg Mx) (Float.neg mx))
  | All => All
  end.

Lemma forward_fneg_correct:
  ∀ x x_ab, x ∈ γ x_ab -> (Float.neg x) ∈ γ (forward_fneg x_ab).
Proof.
  intros x [|[mx Mx]] Hx; simpl in *. auto.
  rewrite !fneg_decr. tauto.
Qed.