Module IdealIntervalsNonrel


Require Import Utf8.
Require Import IdealExpr.
Require Import AbIdealNonrel.
Require Import ZArith.
Require Import Coqlib.
Require Import ZIntervals FloatIntervals FloatIntervalsBackward.
Require Import FloatIntervalsForward IdealIntervals.
Require Import ZCongruences_defs.
Require Import Integers.
Require Import AdomLib.
Require Import AbIdealEnv IdealBoxDomain ShareTree Util FastArith.

Existing Instance FloatIntervals.gamma.

Definition forward_binop (op:i_binary_operation) (x y:iitv+⊤) : iitv+⊤+⊥ :=
  do x <-
    match op return match op with IOadd => _ | _ => _ end+⊥ with
    | IOadd | IOsub | IOmul | IOdiv | IOmod | IOand | IOor
    | IOxor | IOshl | IOshr | IOcmp _ => in_z x
    | IOaddf | IOsubf | IOmulf | IOdivf | IOcmpf _ => in_f x
    end;
  do y <-
    match op return match op with IOadd => _ | _ => _ end+⊥ with
    | IOadd | IOsub | IOmul | IOdiv | IOmod | IOand | IOor
    | IOxor | IOshl | IOshr | IOcmp _ => in_z y
    | IOaddf | IOsubf | IOmulf | IOdivf | IOcmpf _ => in_f y
    end;
  (match op return match op with IOadd => _ | _ => _ end ->
                  match op with IOadd => _ | _ => _ end -> _ with
  | IOadd => fun x y =>
    match x, y with
    | Just (ZITV mx Mx), Just (ZITV my My) =>
      ret (Just (Az (ZITV (Zfastadd mx my) (Zfastadd Mx My))))
    | _, _ => ret All
    end
  | IOsub => fun x y =>
    match x, y with
    | Just (ZITV mx Mx), Just (ZITV my My) =>
      ret (Just (Az (ZITV (Zfastsub mx My) (Zfastsub Mx my))))
    | _, _ => ret All
    end
  | IOmul => fun x y => fmap (fmap Az) (forward_mult x y)
  | IOdiv => fun x y => fmap (fmap Az) (forward_div x y)
  | IOmod => fun x y => fmap (fmap Az) (forward_mod x y)

  | IOand => fun x y => fmap (fmap Az) (forward_land x y)
  | IOor => fun x y => fmap (fmap Az) (forward_lor x y)
  | IOxor => fun x y => fmap (fmap Az) (forward_lxor x y)
  | IOshl => fun x y => fmap (fmap Az) (forward_shl x y)
  | IOshr => fun x y => fmap (fmap Az) (forward_shr x y)

  | IOcmp c => fun x y =>
    let hasOne := is_bot (backward_cmp_l c x y) in
    let hasZero := is_bot (backward_cmp_l (negate_comparison c) x y) in
    match hasOne, hasZero with
    | false, false => NotBot (Just (Az (ZITV F0 F1)))
    | true, false => NotBot (Just (Az (ZITV F0 F0)))
    | false, true => NotBot (Just (Az (ZITV F1 F1)))
    | true, true => Bot
    end
  | IOcmpf c => fun x y =>
    let hasOne := is_bot (backward_cmpf_l c x y trueNotBot x) in
    let hasZero := is_bot (backward_cmpf_l c x y falseNotBot x) in
    match hasOne, hasZero with
      | false, false => NotBot (Just (Az (ZITV F0 F1)))
      | true, false => NotBot (Just (Az (ZITV F0 F0)))
      | false, true => NotBot (Just (Az (ZITV F1 F1)))
      | true, true => Bot
    end

  | IOaddf => fun x y => fmap (fmap Af) (forward_fadd x y)
  | IOsubf => fun x y => fmap (fmap Af) (forward_fsub x y)
  | IOmulf => fun x y => fmap (fmap Af) (forward_fmult x y)
  | IOdivf => fun x y => fmap (fmap Af) (forward_fdiv x y)
  end x y:iitv+⊤+⊥).

Lemma forward_binop_correct:
  ∀ op,
  ∀ x x_ab, x ∈ γ x_ab ->
  ∀ y y_ab, y ∈ γ y_ab ->
  eval_ibinop op x y ⊆ γ (forward_binop op x_ab y_ab).
Proof.
  intros [] x x_ab Hx y y_ab Hy z EVAL; try reflexivity; inversion EVAL; clear EVAL; subst;
    try eapply botbind_spec; eauto; intros;
    try eapply botbind_spec; eauto; intros;
    try eapply botmap_spec; eauto; intros;
    try eapply toplift_lift_spec; eauto.

  - destruct a as [|[[][]]], a0 as [|[[][]]]; try easy.
    destruct H, H0; split; simpl in *; omega.
  - destruct a as [|[[][]]], a0 as [|[[][]]]; try easy.
    destruct H, H0; split; simpl in *; omega.
  - eapply botbind_spec, forward_mult_correct; eauto. intros.
    eapply toplift_bind_spec. intros. apply H2. auto.
  - eapply botbind_spec, forward_div_correct; eauto. intros.
    eapply toplift_bind_spec. intros. apply H3. auto.
  - eapply botbind_spec, forward_mod_correct; eauto. intros.
    eapply toplift_bind_spec. intros. apply H3. auto.
  - eapply botbind_spec, forward_land_correct; eauto. intros.
    eapply toplift_bind_spec. intros. apply H2. auto.
  - eapply botbind_spec, forward_lor_correct; eauto. intros.
    eapply toplift_bind_spec. intros. apply H2. auto.
  - eapply botbind_spec, forward_lxor_correct; eauto. intros.
    eapply toplift_bind_spec. intros. apply H2. auto.
  - eapply botbind_spec, forward_shl_correct; eauto. intros.
    eapply toplift_bind_spec. intros. apply H2. auto.
  - eapply botbind_spec, forward_shr_correct; eauto. intros.
    eapply toplift_bind_spec. intros. apply H2. auto.
  - destruct (Zcmp c i1 i2) eqn:?.
    erewrite (is_bot_spec _ (backward_cmp_l c a a0)).
    destruct @is_bot; split; simpl; omega.
    eapply backward_cmp_l_correct; eauto.
    erewrite (is_bot_spec _ (backward_cmp_l (negate_comparison c) a a0)).
    destruct @is_bot; split; simpl; omega.
    eapply backward_cmp_l_correct; eauto.
    destruct c; simpl in Heqb |- *; destruct Z.compare; congruence.
  - eapply botbind_spec, forward_fadd_correct; eauto. intros.
    eapply toplift_bind_spec. intros. apply H2. auto.
  - eapply botbind_spec, forward_fsub_correct; eauto. intros.
    eapply toplift_bind_spec. intros. apply H2. auto.
  - eapply botbind_spec, forward_fmult_correct; eauto. intros.
    eapply toplift_bind_spec. intros. apply H2. auto.
  - eapply botbind_spec, forward_fdiv_correct; eauto. intros.
    eapply toplift_bind_spec. intros. apply H2. auto.
  - destruct (Floats.Float.cmp c f1 f2) eqn:?.
    + erewrite (is_bot_spec _ (backward_cmpf_l c a a0 trueNotBot a)).
      destruct @is_bot; split; simpl; omega.
      apply meet_correct. split. eapply backward_cmpf_l_correct; eauto. auto.
    + erewrite (is_bot_spec _ (backward_cmpf_l c a a0 falseNotBot a)).
      destruct @is_bot; split; simpl; omega.
      apply meet_correct. split. eapply backward_cmpf_l_correct; eauto. auto.
Qed.

Definition forward_unop (op:i_unary_operation) (x:iitv+⊤) : iitv+⊤+⊥ :=
  do x <-
    match op return match op with IOneg => _ | _ => _ end+⊥ with
    | IOneg | IOnot | IOfloatofz | IOsingleofz => in_z x
    | IOnegf | IOabsf | IOsingleoffloat | IOzoffloat => in_f x
    end;
  ret (match op return match op with IOneg => _ | _ => _ end -> _ with
          | IOneg => fun x => fmap Az (forward_neg x)
          | IOnot => fun x => fmap Az (forward_lnot x)
          | IOnegf => fun x => fmap Af (forward_fneg x)
          | IOabsf => fun x => fmap Af (forward_fabs x)
          | IOsingleoffloat => fun x => fmap Af (forward_singleoffloat x)
          | IOfloatofz => fun x => fmap Af (forward_floatofz x)
          | IOsingleofz => fun x => fmap Af (forward_singleofz x)
          | IOzoffloat => fun x => fmap Az (forward_zoffloat x)
          end x).

Lemma forward_unop_correct:
  ∀ op,
  ∀ x x_ab, x ∈ γ x_ab ->
  eval_iunop op x ⊆ γ (forward_unop op x_ab).
Proof.
  intros [] x x_ab Hx z EVAL; inversion EVAL; clear EVAL; subst;
  eapply botbind_spec; intros;
  try apply in_z_correct; try apply in_f_correct; eauto.
  - eapply toplift_bind_spec, forward_neg_correct, H. auto.
  - eapply toplift_bind_spec, forward_lnot_correct, H. auto.
  - eapply toplift_bind_spec, forward_fneg_correct, H. auto.
  - eapply toplift_bind_spec, forward_fabs_correct, H. auto.
  - eapply toplift_bind_spec, forward_singleoffloat_correct, H. auto.
  - eapply toplift_bind_spec, forward_floatofz_correct, H. auto.
  - eapply toplift_bind_spec, forward_singleofz_correct, H. auto.
  - eapply toplift_bind_spec, forward_zoffloat_correct, H; auto.
Qed.

Definition backward_binop (op:i_binary_operation) (res x y:iitv+⊤) : (iitv+⊤*iitv+⊤)+⊥ :=
  do x <-
    match op return match op with IOadd => _ | _ => _ end+⊥ with
    | IOadd | IOsub | IOmul | IOdiv | IOmod | IOand | IOor
    | IOxor | IOshl | IOshr | IOcmp _ => in_z x
    | IOaddf | IOsubf | IOmulf | IOdivf | IOcmpf _ => in_f x
    end;
  do y <-
    match op return match op with IOadd => _ | _ => _ end+⊥ with
    | IOadd | IOsub | IOmul | IOdiv | IOmod | IOand | IOor
    | IOxor | IOshl | IOshr | IOcmp _ => in_z y
    | IOaddf | IOsubf | IOmulf | IOdivf | IOcmpf _ => in_f y
    end;
  do res <-
    match op return match op with IOadd => _ | _ => _ end+⊥ with
    | IOadd | IOsub | IOmul | IOdiv | IOmod | IOand | IOor
    | IOxor | IOshl | IOshr | IOcmp _ | IOcmpf _ => in_z res
    | IOaddf | IOsubf | IOmulf | IOdivf => in_f res
    end;
  match op return match op with IOadd => _ | _ => _ end ->
                  match op with IOadd => _ | _ => _ end ->
                  match op with IOadd => _ | _ => _ end -> _ with
  | IOadd => fun x y res =>
    let x' :=
      match y, res with
        | Just (ZITV my My), Just (ZITV mres Mres) =>
          Just (ZITV (Zfastsub mres My) (Zfastsub Mres my))
        | _, _ => All
      end
    in
    let y' :=
      match x, res with
        | Just (ZITV mx Mx), Just (ZITV mres Mres) =>
          Just (ZITV (Zfastsub mres Mx) (Zfastsub Mres mx))
        | _, _ => All
      end
    in
    ret (fmap Az x', fmap Az y')
  | IOsub => fun x y res =>
    let x' :=
      match y, res with
        | Just (ZITV my My), Just (ZITV mres Mres) =>
          Just (ZITV (Zfastadd mres my) (Zfastadd Mres My))
        | _, _ => All
      end
    in
    let y' :=
      match x, res with
        | Just (ZITV mx Mx), Just (ZITV mres Mres) =>
          Just (ZITV (Zfastsub mx Mres) (Zfastsub Mx mres))
        | _, _ => All
      end
    in
    ret (fmap Az x', fmap Az y')
  | IOmul => fun x y res =>
    do x' <- backward_mul_l res x y;
    do y' <- backward_mul_l res y x;
    ret (fmap Az x', fmap Az y')
  | IOcmp c => fun x y res =>
    match res with
    | Just (ZITV m M) =>
      match (Zfastleb m F1 && Zfastleb F1 M)%bool,
            (Zfastleb m F0 && Zfastleb F0 M)%bool with
      | true, true => NotBot (fmap Az x, fmap Az y)
      | true, false =>
        do x' <- backward_cmp_l c x y;
        do y' <- backward_cmp_l (swap_comparison c) y x;
        ret (fmap Az x', fmap Az y')
      | false, true =>
        do x' <- backward_cmp_l (negate_comparison c) x y;
        do y' <- backward_cmp_l (swap_comparison (negate_comparison c)) y x;
        ret (fmap Az x', fmap Az y')
      | false, false => Bot
      end
    | All =>
      ret (fmap Az x, fmap Az y)
    end
  | IOor => fun x y res =>
    do (x', y') <- backward_or res x y;
    ret (fmap Az x', fmap Az y')
  | IOdiv | IOmod | IOand | IOxor | IOshl | IOshr => fun _ _ _ =>
    ret (All, All)
  | IOaddf => fun x y res =>
    do x' <- backward_addf_l res y;
    do y' <- backward_addf_r res x;
    ret (fmap Af x', fmap Af y')
  | IOsubf => fun x y res =>
    do x' <- backward_subf_l res y;
    do y' <- backward_subf_r res x;
    ret (fmap Af x', fmap Af y')
  | IOmulf | IOdivf => fun _ _ _ =>
    ret (All, All)
  | IOcmpf c => fun x y res =>
    match res with
    | Just (ZITV m M) =>
      match (Zfastleb m F1 && Zfastleb F1 M)%bool,
            (Zfastleb m F0 && Zfastleb F0 M)%bool with
      | true, true => ret (fmap Af x, fmap Af y)
      | true, false =>
        do x' <- backward_cmpf_l c x y true;
        do y' <- backward_cmpf_l (swap_comparison c) y x true;
        ret (fmap Af x', fmap Af y')
      | false, true =>
        do x' <- backward_cmpf_l c x y false;
        do y' <- backward_cmpf_l (swap_comparison c) y x false;
        ret (fmap Af x', fmap Af y')
      | false, false => Bot
      end
    | All =>
      ret (fmap Af x, fmap Af y)
    end
  end x y res.

Lemma backward_binop_correct:
  ∀ op x x_ab, x ∈ γ x_ab ->
  ∀ y y_ab, y ∈ γ y_ab ->
  ∀ res res_ab, res ∈ γ res_ab ->
    eval_ibinop op x y res ->
    (x, y) ∈ γ (backward_binop op res_ab x_ab y_ab).
Proof.
Opaque backward_subf_r.
Hint Resolve backward_or_correct.
  intros op x x_ab Hx y y_ab Hy res res_ab Hres EVAL.
  destruct op;
    inv EVAL;
    repeat (eapply botbind_spec; eauto; intros);
    try (split; simpl; auto; eapply toplift_bind_spec; simpl in *; eauto).
  - destruct a0 as [|[]], a1 as [|[]]; try easy. simpl in *. omega.
  - destruct a as [|[]], a1 as [|[]]; try easy. simpl in *. omega.
  - destruct a0 as [|[]], a1 as [|[]]; try easy. simpl in *. omega.
  - destruct a as [|[]], a1 as [|[]]; try easy. simpl in *. omega.
  - eapply backward_mul_l_correct; eauto. rewrite Zmult_comm. auto.
  - eapply backward_mul_l_correct; eauto.
  - destruct a2 as [x y]. destruct H2. split. destruct x; eauto. destruct y; eauto.
  - destruct a1 as [|[]]. split; eapply toplift_bind_spec; simpl in *; eauto. fastunwrap.
    assert ((z <=? 1) && (1 <=? z0) = false -> Zcmp c i1 i2 = false)%bool.
    { rewrite Bool.andb_false_iff, -> !Z.leb_gt. simpl in H1. destruct Zcmp.
      fastunwrap. omega. auto. }
    simpl. assert ((z <=? 0) && (0 <=? z0) = false -> Zcmp c i1 i2 = true)%bool.
    { rewrite Bool.andb_false_iff, -> !Z.leb_gt. simpl in H1. destruct Zcmp. auto.
      fastunwrap. omega. }
    destruct ((z <=? 1) && (1 <=? z0))%bool eqn:Hres1,
             ((z <=? 0) && (0 <=? z0))%bool eqn:Hres0;
      (specialize (H2 eq_refl) || clear H2); (specialize (H3 eq_refl) || clear H3).
    + split; eapply toplift_bind_spec; simpl in *; eauto.
    + eapply botbind_spec. intros. eapply botbind_spec. intros.
      split; eapply toplift_bind_spec; simpl in *; eauto.
      eapply backward_cmp_l_correct; eauto.
      destruct c; simpl in *; destruct (Zcompare_spec i1 i2), (Zcompare_spec i2 i1);
        try congruence; exfalso; omega.
      eapply backward_cmp_l_correct; eauto.
    + eapply botbind_spec. intros. eapply botbind_spec. intros.
      split; eapply toplift_bind_spec; simpl in *; eauto.
      eapply backward_cmp_l_correct; eauto.
      destruct c; simpl in *; destruct (Zcompare_spec i1 i2), (Zcompare_spec i2 i1);
        try congruence; exfalso; omega.
      eapply backward_cmp_l_correct; eauto.
      destruct c; simpl in *; destruct (i1 ?= i2); congruence.
    + congruence.
  - eapply backward_addf_r_correct; eauto.
  - eapply backward_addf_l_correct; eauto.
  - eapply backward_subf_r_correct; eauto.
  - eapply backward_subf_l_correct; eauto.
  - destruct a1 as [|[]]. split; eapply toplift_bind_spec; simpl in *; eauto. fastunwrap.
    assert ((z <=? 1) && (1 <=? z0) = false -> Floats.Float.cmp c f1 f2 = false)%bool.
    { rewrite Bool.andb_false_iff, -> !Z.leb_gt. simpl in H1.
      destruct Floats.Float.cmp. fastunwrap. omega. auto. }
    assert ((z <=? 0) && (0 <=? z0) = false -> Floats.Float.cmp c f1 f2 = true)%bool.
    { rewrite Bool.andb_false_iff, -> !Z.leb_gt. simpl in H1.
      destruct Floats.Float.cmp. auto. fastunwrap. omega. }
    simpl.
    destruct ((z <=? 1) && (1 <=? z0))%bool eqn:Hres1,
             ((z <=? 0) && (0 <=? z0))%bool eqn:Hres0;
      (specialize (H2 eq_refl) || clear H2); (specialize (H3 eq_refl) || clear H3).
    + split; eapply toplift_bind_spec; simpl in *; eauto.
    + eapply botbind_spec. intros. eapply botbind_spec.
      split; eapply toplift_bind_spec; simpl in *; eauto.
      eapply backward_cmpf_l_correct; eauto.
      rewrite Floats.Float.cmp_swap. auto.
      eapply backward_cmpf_l_correct; eauto.
    + eapply botbind_spec. intros. eapply botbind_spec.
      split; eapply toplift_bind_spec; simpl in *; eauto.
      eapply backward_cmpf_l_correct; eauto.
      rewrite Floats.Float.cmp_swap. auto.
      eapply backward_cmpf_l_correct; eauto.
    + congruence.
Qed.

Definition backward_unop (op:i_unary_operation) (res x:iitv+⊤) : iitv+⊤+⊥ :=
  do res <-
    match op return match op with IOneg => _ | _ => _ end+⊥ with
    | IOneg | IOnot | IOzoffloat => in_z res
    | IOnegf | IOabsf | IOsingleoffloat | IOfloatofz | IOsingleofz => in_f res
    end;
  match op return match op with IOneg => _ | _ => _ end -> _ with
  | IOneg => fun res =>
    NotBot (fmap Az (forward_neg res))
  | IOnot => fun res =>
    NotBot (fmap Az (forward_lnot res))
  | IOnegf => fun res =>
    NotBot (fmap Af (forward_fneg res))
  | IOabsf => fun res =>
    fmap (fmap Af) (backward_absf res)
  | IOsingleoffloat => fun res =>
    fmap (fmap Af) (backward_singleoffloat res)
  | IOzoffloat => fun res =>
    NotBot (fmap Af (backward_zoffloat res))
  | IOfloatofz => fun res =>
    do x <- in_z x;
    fmap (fmap Az) (backward_floatofz res x)
  | IOsingleofz => fun res =>
    do x <- in_z x;
    fmap (fmap Az) (backward_singleofz res x)
  end res.

Lemma backward_unop_correct:
  ∀ op,
    ∀ x x_ab, x ∈ γ x_ab ->
    ∀ res res_ab, res ∈ γ res_ab ->
      eval_iunop op x res ->
      x ∈ γ (backward_unop op res_ab x_ab).
Proof.
  intros op x x_ab Hx res res_ab Hres EVAL.
  destruct op; inv EVAL;
    repeat (eapply botbind_spec; eauto; intros);
    try (eapply toplift_bind_spec; eauto);
    try now (intros ? HH; apply HH).
  - rewrite <- Z.opp_involutive. apply forward_neg_correct; auto.
  - rewrite <- Z.lnot_involutive. apply forward_lnot_correct; auto.
  - apply forward_fneg_correct in H. destruct f as [[]|[]|[]|[]]; easy.
  - apply backward_absf_correct; auto.
  - apply backward_singleoffloat_correct; auto.
  - apply backward_floatofz_correct; auto.
  - apply backward_singleofz_correct; auto.
  - eapply backward_zoffloat_correct; eauto.
Qed.

Definition extract_msgs (x:var) v : messages_chan :=
  match singleton v with
  | Some v => Broadcasted_msg (Known_value_msg x v)::nil
  | None => Itv_msg x v::nil
  end.

Lemma extract_msgs_correct:
  ∀ x v ρ,
    γ vx) → γ (extract_msgs x v) ρ.
Proof.
  intros. unfold extract_msgs. pose proof (singleton_correct v).
  destruct singleton; (constructor; [|constructor]).
  - apply H0; auto.
  - apply H.
Qed.

Definition enrich_query_chan fev (chan:query_chan) : query_chan :=
  {| get_var_ty := chan.(get_var_ty);
     get_itv expr :=
       do ab <- fev expr;
       do ab' <- chan.(get_itv) expr;
       match ab with
       | All => NotBot ab'
       | Just (Az i1) => do i2 <- in_z ab'; fmap (fmap Az) (Just i1i2)
       | Just (Af i1) => do i2 <- in_f ab'; fmap (fmap Af) (Just i1i2)
       end;
     get_congr := chan.(get_congr);
     get_eq_expr := chan.(get_eq_expr);
     linearize_expr := chan.(linearize_expr) |}.

Definition reduce_itv_congr (zc:zcongr) (itv:zitv) : zitv+⊥ :=
  let 'ZITV a b := itv in
  let m := zc.(zc_mod) in
  if Nfastleb m F0 then
    let x := zc.(zc_rem) in meet itv (ZITV x x)
  else if Nfastleb m F1 then NotBot itv
  else
    let b := Zfastsub b (Zfastmod (Zfastsub b zc.(zc_rem)) (Zfast_of_Nfast m)) in
    let a := Zfastadd a (Zfastmod (Zfastsub zc.(zc_rem) a) (Zfast_of_Nfast m)) in
    if Zfastleb a b then NotBot (ZITV a b)
    else Bot.

Lemma reduce_itv_congr_correct:
  ∀ zc itv v,
    v ∈ γ zc -> v ∈ γ itv ->
    v ∈ γ (reduce_itv_congr zc itv).
Proof.
  intros. destruct itv as [[a][b]]. destruct zc as [[][]]. simpl. fastunwrap.
  destruct (N.leb_spec x0 0); [|destruct (N.leb_spec x0 1)].
  - apply meet_correct. split. auto. assert (x0 = 0%N) by Psatz.lia. subst.
    destruct H. simpl in H. rewrite H. simpl. omega.
  - auto.
  - destruct H0, H. simpl in *.
    assert (v = x - x1 * Z.of_N x0) by omega. subst v. clear H.
    assert (x1 * Z.of_N x0 <= x - a) by omega.
    assert (-x1 * Z.of_N x0 <= b - x) by (rewrite <- Zopp_mult_distr_l; omega).
    apply Zdiv_le_lower_bound, Zmult_le_compat_l with (p:=Z.of_N x0) in H; try (zify; omega).
    apply Zdiv_le_lower_bound, Zmult_le_compat_l with (p:=Z.of_N x0) in H4; try (zify; omega).
    rewrite Z.mul_opp_r in H4.
    destruct x0 as [|[]]; try congruence; fastunwrap;
    rewrite !Z.mod_eq by Psatz.lia;
    match goal with
    | |- context [Z.leb ?x ?y] => destruct (Z.leb_spec x y)
    end; try split; fastunwrap; Psatz.lia.
Qed.

Definition process_msg fev {AB} bev (msg:message) (abenv:AB*query_chan)
           : (AB*messages_chan)+⊥ :=
  match msg with
  | Congr_msg x zc =>
    do ab <- fev (IEvar INTz x);
    match ab with
    | Just (Az itv0) =>
      do itv <- reduce_itv_congr zc itv0;
      let 'ZITV a b := itv in
      let msgs :=
        if Zfastleb b a then Broadcasted_msg (Known_value_msg x (INz a))::nil
        else if itv0itv then msg::nil
             else msg::Itv_msg x (Az itv)::nil
      in
      do abenv <- bev (IEvar INTz x) (Az itv) abenv;
      NotBot (abenv, msgs)
    | _ => NotBot (fst abenv, msg::nil)
    end
  | Itv_msg x itv =>
    let ty := match itv with Az _ => INTz | Af _ => INTf end in
    do abenv <- bev (IEvar ty x) itv abenv;
    NotBot (abenv, msg::nil)
  | _ => NotBot (fst abenv, msg::nil)
  end.

Lemma process_msg_correct :
  ∀ fev AB (GAB:gamma_op AB (var -> ideal_num)) bev (msg:message) (abenv:AB * query_chan) ρ,

    (∀ e v, eval_iexpr ρ e v -> v ∈ γ (fev e)) ->
    (∀ e v abv ab, eval_iexpr ρ e v -> v ∈ γ abv -> ρ ∈ γ ab -> ρ ∈ γ (bev e abv ab)) ->

    γ msg ρ → γ abenv ρ → γ (process_msg fev bev msg abenv) ρ.
Proof.
  intros * Hfev Hbev Hmsg Habenv. unfold process_msg.
  destruct msg; try now (repeat constructor; simpl; auto; apply Habenv).
  - eapply botbind_spec. constructor. eauto. constructor. auto. constructor.
    eapply Hbev; eauto. simpl in Hmsg. constructor. auto.
    destruct i, (ρ v); try contradiction; constructor.
  - red in Hmsg. red in Hmsg. destructv) as [|[]] eqn:?. contradiction.
    eapply botbind_spec, Hfev. 2:constructor; eauto. 2:constructor. intros ab Hab.
    destruct ab as [|[itv|]]; try now (repeat constructor; simpl; try rewrite Heqi; auto; apply Habenv).
    eapply botbind_spec, reduce_itv_congr_correct; eauto.
    intros [[a'] [b']] Ha'b'. eapply botbind_spec, Hbev; eauto.
    2:constructor; eauto. 2:constructor. 2:now auto. split. now auto. fastunwrap.
    destruct (Z.leb_spec b' a'); [|destruct @leb]; simpl; repeat constructor;
    simpl; rewrite Heqi; auto. f_equal. destruct Ha'b'. fastunwrap. f_equal. Psatz.lia.
Qed.

Instance itv_dom : ab_ideal_nonrel iitv :=
  { widen := iditv_widen
  ; const n :=
      match n with
      | INz z => let z:Zfast := z in Just (Az (ZITV z z))
      | INf f => if Fappli_IEEE.is_nan f then All else Just (Af (FITV f f))
      end
  ; z_itv := @Just _Az
  ; forward_unop := forward_unop
  ; forward_binop := forward_binop
  ; backward_unop := backward_unop
  ; backward_binop := backward_binop

  ; forward_var fev x ab c := NotBot ab
  ; backward_var fev AB bev var_ref x ab abenv :=
      match ab with
      | Az itv =>
        do zc <- (snd abenv).(get_congr) (IEvar INTz x);
        do itv' <- reduce_itv_congr zc itv;
        do ab <- var_ref (Az itv') (fst abenv);
        match (snd abenv).(get_eq_expr) x with
        | Some (Leaf e) => bev e (Az itv') (ab, snd abenv)
        | _ => NotBot ab
        end
      | _ => var_ref ab (fst abenv)
      end
  ; enrich_query_chan := enrich_query_chan
  ; process_msg := process_msg
  ; assign_msgs := extract_msgs
  ; assume_msgs x v_old v := extract_msgs x v
}.

Instance itv_dom_correct : ab_ideal_nonrel_correct itv_dom _ := {}.
Proof.
  - destruct x; unfold join, iditv_join; simpl; unfold physEq; f_equal; f_equal;
    (apply ZIntervals.join_eq || apply FloatIntervals.join_eq).
  - destruct x; unfold widen, iditv_widen; simpl; unfold physEq;
    rewrite ?ZIntervals.widen_eq, ?FloatIntervals.widen_eq; auto.
  - destruct x; unfold leb, iditv_leb; simpl;
    rewrite ?ZIntervals.leb_eq, ?FloatIntervals.leb_eq; auto.
  - apply IdealIntervals.widen_incr.
  - destruct n; simpl.
    + destruct (Fappli_IEEE.is_nan f) eqn:ISNAN. constructor.
      split; apply FloatLib.Fleb_refl; auto.
    + omega.
  - auto.
  - apply forward_unop_correct.
  - apply forward_binop_correct.
  - apply backward_unop_correct.
  - apply backward_binop_correct.
  - intros. simpl. auto.
  - intros. destruct ab. 2:simpl; apply H1, H3; auto. simpl.
    destructx) eqn:?. contradiction.
    eapply botbind_spec, H3. 2:repeat constructor; eauto.
    intros. eapply botbind_spec, reduce_itv_congr_correct; eauto.
    intros i' Hi'. eapply botbind_spec with ρ, H1, H3; auto.
    intros. pose proof get_eq_expr_correct (proj2 H3) x.
    destruct @get_eq_expr as [[]|]; try apply H5.
    specialize (H6 _ eq_refl). inv H6. eapply H0. eauto. rewrite Heqi. auto.
    split. auto. apply H3.
  - constructor.
    + intros. apply H0.
    + intros.
      apply botbind_spec with (x:=a). intros.
      eapply botbind_spec. intros. 2:eapply get_itv_correct; eauto.
      destruct a0 as [|[]], a; eauto; try contradiction.
      eapply botbind_spec. intros. 2:apply in_z_correct, H3.
      eapply botbind_spec. intros. eapply toplift_bind_spec, H5. intros. apply H6.
      eapply meet_correct. auto.
      eapply botbind_spec. intros. 2:apply in_f_correct, H3.
      eapply botbind_spec. intros. eapply toplift_bind_spec, H5. intros. apply H6.
      eapply meet_correct. auto. auto.
    + intros. apply H0. auto.
    + intros. apply H0. auto.
    + intros. eapply H0; eauto.
  - apply process_msg_correct.
  - intros. apply extract_msgs_correct. auto.
  - intros. simpl. apply extract_msgs_correct. auto.
Qed.

Definition t := @IdealBoxDomain.t iitv.

Instance intervals_ideal_env : ab_ideal_env t (t+⊥) :=
  IdealBoxDomain.ideal_box_domain _ itv_dom_correct.