Module PolAdomZ

This module implements the AbIdealEnv.ab_ideal_env interface of abtract domains on ideal numbers.

Require Import ZArith_base.
Require CExprPedraZ.
Import NumC ProgVar Itv.
Require Import AdomLib Util FastArith.
Require Import IdealExpr.
Require Import IdealIntervals ZIntervals.
Require Import AbIdealEnv.
Require Import FactMsgHelpers.
Require Import String.
Require Import ToString.
Require Import CellEncoding.

Instance v2p : injection var positive :=
  fun vg => Pos.pred (match vg with Real x => xO (inj x) | Ghost x => xI x end).

Instance p2v : injection positive var :=
  fun p =>
    match Pos.succ p with
    | xO x => Real (inj x)
    | xI x => Ghost x
    | xH => Ghost xH
    end.

Instance BIJ : bijection v2p p2v.
Proof.
  split; intros; unfold inj, p2v, v2p.
  - rewrite Pos.succ_pred. destruct a. rewrite forward. auto. auto.
    destruct a; discriminate.
  - destruct (Pos.succ b) eqn:EQ.
    rewrite <- EQ. apply Pos.pred_succ.
    rewrite backward, <- EQ. apply Pos.pred_succ.
    destruct b; discriminate.
Qed.

Local Open Scope Z_scope.

Local Notation zmemT := (Mem.t ZNum.t).

Definition liftN (dummy: ZNum.t) (n: ideal_num): ZNum.t
  := match n with
         | INf _ => dummy
         | INz z => z
     end.

Definition liftRho (rho: var -> ideal_num) (dummy: ZNum.t): zmemT
  := fun x => liftN dummy (rho (p2v x)).

Definition cmpTrans : Integers.comparison -> CExprPedraZ.Cmp.t
  := fun cmp =>
       match cmp with
       | Integers.Ceq => CExprPedraZ.Cmp.Eq
       | Integers.Cne => CExprPedraZ.Cmp.Neq
       | Integers.Clt => CExprPedraZ.Cmp.Lt
       | Integers.Cle => CExprPedraZ.Cmp.Le
       | Integers.Cgt => CExprPedraZ.Cmp.Gt
       | Integers.Cge => CExprPedraZ.Cmp.Ge
       end.

Import Datatypes.
Lemma CmpTransTrue : forall (cmp : Integers.comparison),
                   forall z1 z2 : Z,
                     Zcmp cmp z1 z2 = true -> CExprPedraZ.Cmp.denote (cmpTrans cmp) z1 z2.
Proof.
  intros cmp z1 z2 hyp.
  assert (fact : match z1 ?= z2 with
                   | Eq => z1 = z2
                   | Lt => z1 < z2
                   | Gt => z1 > z2
                 end).
  apply Zcompare_elim; trivial.
  destruct cmp; simpl; simpl in hyp; destruct (z1 ?= z2);
  try discriminate; try assumption.
  intro contr.
  subst.
  apply Z.lt_irrefl in fact.
  contradiction.
  intro contr.
  subst.
  apply Z.gt_lt in fact.
  apply Z.lt_irrefl in fact.
  contradiction.
  subst.
  apply Z.le_refl.
  apply Z.lt_le_incl.
  assumption.
  apply Z.gt_lt in fact.
  assumption.
  subst.
  apply Z.le_refl.
  apply Z.gt_lt in fact.
  apply Z.lt_le_incl in fact.
  assumption.
Qed.

Lemma CmpTransFalse : forall (cmp: Integers.comparison),
                      forall z1 z2 : Z,
                        Zcmp cmp z1 z2 = false ->
                        ~ CExprPedraZ.Cmp.denote (cmpTrans cmp) z1 z2.
Proof.
  intros cmp z1 z2 hyp contr.
  assert (fact : match z1 ?= z2 with
                 | Eq => z1 = z2
                 | Lt => z1 < z2
                 | Gt => z1 > z2
                 end).
  apply Zcompare_elim; trivial.
  destruct cmp; simpl in hyp; simpl in contr; destruct (z1 ?= z2); try discriminate.
  subst.
  apply Z.lt_irrefl in fact.
  contradiction.
  subst.
  apply Z.gt_lt, Z.lt_irrefl in fact.
  contradiction.
  contradiction (contr fact).
  subst.
  apply Z.lt_irrefl in contr.
  contradiction.
  apply Z.lt_asymm in contr.
  apply Z.gt_lt in fact.
  contradiction (contr fact).
  apply Z.gt_lt in fact.
  apply Zle_lt_or_eq in contr.
  destruct contr.
  apply (Z.lt_trans z1 z2 z1) in fact.
  apply Z.lt_irrefl in fact.
  contradiction.
  assumption.
  subst.
  apply Z.lt_irrefl in fact.
  contradiction.
  subst.
  apply Z.lt_irrefl in contr.
  contradiction.
  apply (Z.lt_trans z1 z2 z1) in contr.
  apply Z.lt_irrefl in contr.
  contradiction.
  assumption.
  apply Zlt_not_le in fact.
  contradiction (fact contr).
Qed.

Lemma CmpTransPreservation : forall (cmp: Integers.comparison) (z1 z2 : Z),
                               (if Zcmp cmp z1 z2 return Zfast then F1 else F0) =
                               ((if CExprPedraZ.Cmp.dec (cmpTrans cmp) z1 z2 then 1 else 0):Zfast).
Proof.
  intros cmp z1 z2.
  assert (fact1 := CmpTransTrue cmp z1 z2).
  assert (fact2 := CmpTransFalse cmp z1 z2).
  destruct (Zcmp cmp z1 z2);
  destruct (CExprPedraZ.Cmp.dec (cmpTrans cmp) z1 z2).
  reflexivity.
  contradiction n. apply fact1; reflexivity.
  refine (match fact2 _ d with end). reflexivity.
  reflexivity.
Qed.

Definition ItvTrSpec (i1: zitv) (i2: ZItv.t): Prop
  := forall z: Z.t, γ i1 z <-> ZItv.sat i2 z.

Definition itvTr (i1: zitv): {i2: ZItv.t | ItvTrSpec i1 i2}.
  refine (
      match i1
            return {i2: ZItv.t | ItvTrSpec i1 i2}
      with
        | ZITV z1 z2 =>
          exist _ (proj1_sig (ZItv.mk (ZItv.Closed z1) (ZItv.Closed z2))) _
      end);
  unfold ItvTrSpec;
  intro z;
  split;
  intro h;
  simpl; try easy.
  - destruct (ZNum.ltLeDec z2 z1) as [h1|h1].
    + assert (h2 := h1).
      apply Zlt_not_le in h2.
      destruct h2.
      apply Z.le_trans with (m := z);
        apply h.
    + simpl.
      assumption.
  - simpl in h.
    destruct (ZNum.ltLeDec z2 z1) as [h1|h1].
    + destruct h.
    + simpl in h.
      assumption.
Defined.

Fixpoint iexprTr (ie : iexpr) : CExprPedraZ.Expr.t
  := match ie with
       | IEvar INTz x => CExprPedraZ.Expr.Evar (v2p x)
       | IEvar INTf x => CExprPedraZ.Expr.Eunknown
       | IEconst (INz z) => CExprPedraZ.Expr.Econst z
       | IEconst _ => CExprPedraZ.Expr.Eunknown
       | IEZitv itv => CExprPedraZ.Expr.Eitv (proj1_sig (itvTr itv))
       | IEunop op ie' =>
         let e' := iexprTr ie' in
         match op with
           | IOneg => CExprPedraZ.Expr.Eunop CExprPedraZ.Expr.Oneg e'
           | IOnot => CExprPedraZ.Expr.Eunop CExprPedraZ.Expr.Onot e'
           | _ => CExprPedraZ.Expr.Eunknown
         end
       | IEbinop op ie1 ie2 =>
         let e1 := iexprTr ie1 in
         let e2 := iexprTr ie2 in
         match op with
           | IOadd => CExprPedraZ.Expr.Ebinop CExprPedraZ.Expr.Oadd e1 e2
           | IOsub => CExprPedraZ.Expr.Ebinop CExprPedraZ.Expr.Osub e1 e2
           | IOmul => CExprPedraZ.Expr.Ebinop CExprPedraZ.Expr.Omul e1 e2
           | IOdiv => CExprPedraZ.Expr.Ebinop CExprPedraZ.Expr.Odiv e1 e2
           | IOmod => CExprPedraZ.Expr.Ebinop CExprPedraZ.Expr.Omod e1 e2
           | IOand => CExprPedraZ.Expr.Ebinop CExprPedraZ.Expr.Oand e1 e2
           | IOor => CExprPedraZ.Expr.Ebinop CExprPedraZ.Expr.Oor e1 e2
           | IOxor => CExprPedraZ.Expr.Ebinop CExprPedraZ.Expr.Oxor e1 e2
           | IOshl => CExprPedraZ.Expr.Ebinop CExprPedraZ.Expr.Oshl e1 e2
           | IOshr => CExprPedraZ.Expr.Ebinop CExprPedraZ.Expr.Oshr e1 e2
           | IOcmp c => CExprPedraZ.Expr.Ebinop (CExprPedraZ.Expr.Ocmp (cmpTrans c)) e1 e2
           | _ => CExprPedraZ.Expr.Eunknown
         end
     end.

Lemma IExprTrPreservationInF :
  forall (ie : iexpr) (m : var -> ideal_num) (f: Floats.float),
    eval_iexpr m ie (INf f) -> iexprTr ie = CExprPedraZ.Expr.Eunknown.
Proof.
  intros ie m f hyp.
  induction ie; inversion hyp; subst.
  - destruct i; reflexivity || inversion H3.
  - reflexivity.
  - destruct i; reflexivity || inversion H3.
  - destruct i; reflexivity || inversion H5.
Qed.

Lemma IExprTrPreservationInZ :
  forall (ie : iexpr) (m : var -> ideal_num) (z : Z) (dummy : Z),
    eval_iexpr m ie (INz z) -> CExprPedraZ.Expr.denote (liftRho m dummy) (iexprTr ie) z.
Proof.
  intros ie m z dummy.
  revert z.
  induction ie; intros zz hyp; inversion hyp; subst.
  - destruct i; [|inversion H3].
    constructor.
    unfold liftRho.
    rewrite BIJ.(@forward _ _ _ _), H1.
    reflexivity.
  - constructor.
  - constructor. destruct itvTr. apply i, H1.
  - destruct n as [|[]]; [inversion H3|].
    + constructor.
    + destruct i; simpl; try constructor.
      * apply CExprPedraZ.Expr.EvalEunop with (z1 := x).
        apply IHie.
        assumption.
        inversion H3.
        constructor.
      * apply CExprPedraZ.Expr.EvalEunop with (z1 := x).
        apply IHie.
        assumption.
        inversion H3.
        constructor.
  - destruct n1 as [|[]].
    inversion H5.
    constructor.
    destruct n2 as [|[]].
    inversion H5.
    destruct i; simpl; try constructor;
    apply CExprPedraZ.Expr.EvalEbinop with (z1 := x) (z2 := x0);
    try (apply IHie1; assumption) || (apply IHie2; assumption);
    inversion H5;
    try constructor.
    assumption.
    assumption.
    rewrite CmpTransPreservation in H6. inversion H6.
    constructor.
Qed.

Lemma IExprTrPreservation :
  forall (dummy : Z) (ie : iexpr) (m : var -> ideal_num) (n : ideal_num),
    eval_iexpr m ie n -> CExprPedraZ.Expr.denote (liftRho m dummy) (iexprTr ie) (liftN dummy n).
Proof.
  intros dummy ie m n hyp.
  destruct n as [f|[z]].
  replace (iexprTr ie) with CExprPedraZ.Expr.Eunknown.
  constructor.
  symmetry.
  apply IExprTrPreservationInF with (m := m) (f := f).
  assumption.
  apply IExprTrPreservationInZ.
  assumption.
Qed.

Definition A: Type
  := CExprPedraZ.AbDom.A.

Definition B: Type
  := var -> ideal_num.

Definition gamma: A -> B -> Prop
  := fun ab rho => CExprPedraZ.AbDom.gamma ab (liftRho rho ZNum.z).

Instance PolGammaOp: gamma_op A B := gamma.

Lemma gamma_monotone: forall (ab1:A*query_chan) (ab2: A) (rho:B),
                        CExprPedraZ.AbDom.leb (fst ab1) ab2 = true ->
                        γ ab1 rho -> gamma ab2 rho.
Proof.
  unfold gamma.
  intros ab1 ab2 h rho [H _]. revert H.
  apply CExprPedraZ.AbDom.gamma_monotone.
  assumption.
Qed.

Lemma gamma_top: forall x: B, gamma CExprPedraZ.AbDom.top x.
Proof.
  unfold gamma.
  intro x.
  generalize (liftRho x ZNum.z).
  apply CExprPedraZ.AbDom.gamma_top.
Qed.

Lemma join_sound: forall (ab1 ab2: A*query_chan) (chan:query_chan) (x: B),
    γ ab1 x \/ γ ab2 x -> γ chan x ->
    γ (CExprPedraZ.AbDom.join (fst ab1) (fst ab2)) x.
Proof.
  intros ab1 ab2 chan x H _.
  destruct H as [[]|[]];
    apply CExprPedraZ.AbDom.join_sound;
    [left|right];
    assumption.
Qed.

Definition ItvConvSpec (i1: ZItv.t) (i2: zitv+⊤+⊥): Prop
  := forall z: BinInt.Z, ZItv.sat i1 z -> γ i2 z.

Definition itvConv (i1: ZItv.t): {i2: zitv+⊤+⊥ | ItvConvSpec i1 i2}.
  refine (
      match i1
            return {i2: zitv+⊤+⊥ | ItvConvSpec i1 i2}
      with
        | ZItv.Bot => exist _ Bot _
        | ZItv.NotBot low up pfi1 =>
          match low
                  return forall pf: ZItv.BndOk low up,
                           {i2: zitv+⊤+⊥ | ItvConvSpec (ZItv.NotBot low up pf) i2}
          with
            | ZItv.Infty => fun pfl => exist _ (NotBot All) _
            | ZItv.Open b1 =>
              fun pfl =>
                match up
                      return forall pf: ZItv.BndOk (ZItv.Open b1) up,
                               {i2: zitv+⊤+⊥ |
                                ItvConvSpec (ZItv.NotBot (ZItv.Open b1) up pf) i2}
                with
                  | ZItv.Infty => fun pfu => exist _ (NotBot All) _
                  | ZItv.Open b2
                  | ZItv.Closed b2 =>
                    fun pfu => exist _ (AdomLib.NotBot (Just (ZITV b1 b2))) _
                end pfl
            | ZItv.Closed b1 =>
              fun pfl =>
                match up
                      return forall pf: ZItv.BndOk (ZItv.Closed b1) up,
                               {i2: zitv+⊤+⊥ |
                                ItvConvSpec (ZItv.NotBot (ZItv.Closed b1) up pf) i2}
                with
                  | ZItv.Infty => fun pfu => exist _ (NotBot All) _
                  | ZItv.Open b2
                  | ZItv.Closed b2 =>
                    fun pfu => exist _ (NotBot (Just (ZITV b1 b2))) _
                end pfl
          end pfi1
      end);
  unfold ItvConvSpec;
  intros z h;
  simpl;
  match goal with
    | |- γ All z => constructor
    | _ => idtac
  end;
  simpl;
  unfold ZItv.sat, ZItv.satLower, ZItv.satUpper in h;
  match goal with
    | h: False |- False => destruct h
    | _ => idtac
  end; auto.
  - split; apply Zlt_le_weak, h.
  - split;
    [apply Zlt_le_weak|idtac];
    apply h.
  - split;
    [idtac|apply Zlt_le_weak];
    apply h.
Defined.
Definition get_itv: iexpr -> A -> iitv+⊤+⊥
  := fun e ab =>
       match iexpr_ty e with
         | INTz =>
           let e' := iexprTr e in
           match proj1_sig (itvConv (CExprPedraZ.AbDom.get_itv e' ab)) with
             | Bot => Bot
             | NotBot (Just itv) => NotBot (Just (Az itv))
             | NotBot All => NotBot All
           end
         | INTf => NotBot All
       end.

Lemma get_itv_correct: forall (e: iexpr) (rho: B) (ab: A),
                         gamma ab rho ->
                         (eval_iexpr rho e) ⊆ γ (get_itv e ab).
Proof.
  simpl.
  intros e rho ab hab i h.
  unfold get_itv.
  pose proof (iexpr_ty_correct _ _ _ h). destruct H. 2:constructor.
  assert (pfe := IExprTrPreservation ZNum.z e).
  destruct (itvConv (CExprPedraZ.AbDom.get_itv (iexprTr e) ab)) as [x pfx].
  simpl.
  unfold ItvConvSpec in pfx.
    destruct x as [|[]].
    + apply pfx with (z := i).
      apply CExprPedraZ.AbDom.get_itv_correct with (rho := liftRho rho 0).
      assumption.
      apply pfe with (n := INz i).
      assumption.
    + exact I.
    + simpl.
      apply pfx.
      apply CExprPedraZ.AbDom.get_itv_correct with (rho := liftRho rho 0).
      assumption.
      apply pfe with (n := INz i).
      assumption.
Qed.

Definition propagateBot : A -> A+⊥ :=
  fun ab => if CExprPedraZ.AbDom.isBottom ab then Bot else NotBot ab.

Lemma propagateBot_correct : forall (ab : A) (m : B),
                               m ∈ γ ab <-> m ∈ γ (propagateBot ab).
Proof.
  intros ab m. simpl.
  split.
  - intro hyp.
    unfold propagateBot.
    assert (pf := CExprPedraZ.AbDom.isBottom_correct ab).
    destruct (CExprPedraZ.AbDom.isBottom ab).
    apply pf with (m := liftRho m ZNum.z).
    reflexivity.
    assumption.
    assumption.
  - assert (pf := CExprPedraZ.AbDom.isBottom_correct ab).
    unfold propagateBot.
    destruct (CExprPedraZ.AbDom.isBottom ab).
    intro contr.
    destruct contr.
    intro h.
    assumption.
Qed.

Definition assume : iexpr -> bool -> A * query_chan -> A+⊥
  := fun e b ab => propagateBot (CExprPedraZ.AbDom.assume (iexprTr e) b (fst ab)).

Lemma assume_correct: forall (c: iexpr) (rho: B) (ab: A * query_chan) (b: bool),
                        rho ∈ γ ab ->
                        eval_iexpr rho c (INz (if b then F1 else F0)) ->
                        rho ∈ γ (assume c b ab).
Proof.
  intros e rho ab b hab hc.
  unfold assume.
  simpl.
  apply propagateBot_correct.
  apply CExprPedraZ.AbDom.assume_correct.
  apply hab.
  destruct b.
  apply IExprTrPreservation with (n := INz 1), hc.
  apply IExprTrPreservation with (n := INz 0), hc.
Qed.

Definition assign: var -> iexpr -> A * query_chan -> query_chan -> A+⊥
  := fun x e ab _ => propagateBot (CExprPedraZ.AbDom.assign (v2p x) (iexprTr e) (fst ab)).

Lemma assign_correct: forall (x: var) (e: iexpr) (ρ: var -> ideal_num)
                             (n: ideal_num) (ab: A*query_chan) (c:query_chan),
                        γ ab ρ -> γ c (upd ρ x n) -> eval_iexpr ρ e n ->
                        γ (assign x e ab c) (upd ρ x n).
Proof.
  simpl. unfold PolGammaOp.
  intros x e rho n ab c [h1 _] _ h2.
  unfold assign.
  assert (pf := CExprPedraZ.AbDom.assign_correct).
  specialize (pf (v2p x) (iexprTr e) (liftRho rho 0) (liftN 0 n) (fst ab) h1
                 (IExprTrPreservation _ _ _ _ h2)).
  apply propagateBot_correct. simpl.

  assert (pfm : forall x0, Mem.assign (v2p x) (liftN 0 n) (liftRho rho 0) x0 =
                          liftRho (upd rho x n) ZNum.z x0).
  intro x0.
  unfold Mem.assign, upd, liftRho, liftN.
  destruct (eq_dec (p2v x0) x) as [eqx | eqx].
    subst. rewrite BIJ.(@backward _ _ _ _).
    destruct (PVar.eq_dec x0 x0) as [eq0 | eq0]. reflexivity. congruence.
    destruct (PVar.eq_dec (v2p x) x0).
    subst x0. rewrite BIJ.(@forward _ _ _ _) in eqx. congruence.
    reflexivity.

  revert pf.
  generalize (CExprPedraZ.AbDom.assign (v2p x) (iexprTr e) (fst ab)).
  intros ab' pfab'.
  eapply CExprPedraZ.AbDom.gamma_ext.
  reflexivity.
  symmetry. auto.
  assumption.
Qed.

Definition forget: var -> A * query_chan -> query_chan -> A+⊥
  := fun x ab _ =>
       propagateBot (CExprPedraZ.AbDom.project (fst ab) (v2p x)).

Lemma forget_correct: forall (x: var) (ρ: var -> ideal_num)
                             (n: ideal_num) (ab: A * query_chan) (c:query_chan),
                        γ ab ρ -> γ c (upd ρ x n) ->
                        γ (forget x ab c) (upd ρ x n).
Proof.
  intros x rho n ab c [h1 _] _.
  unfold forget.
  simpl.
  assert (pf := CExprPedraZ.AbDom.project_correct).
  specialize (pf (fst ab) (v2p x) (liftRho rho 0) (liftN 0 n)).
  apply propagateBot_correct.
  simpl. unfold PolGammaOp.

  assert (pfm : forall x0, Mem.assign (v2p x) (liftN 0 n) (liftRho rho 0) x0 =
                          liftRho (upd rho x n) ZNum.z x0).
  intro x0.
  unfold Mem.assign, upd, liftRho, liftN.
  destruct (eq_dec (p2v x0) x) as [eqx | eqx].
    subst. rewrite BIJ.(@backward _ _ _ _).
    destruct (PVar.eq_dec x0 x0) as [eq0 | eq0]. reflexivity. congruence.
    destruct (PVar.eq_dec (v2p x) x0). subst.
    rewrite BIJ.(@forward _ _ _ _) in eqx. congruence. reflexivity.

  eapply CExprPedraZ.AbDom.gamma_ext.
  reflexivity.
  symmetry. auto.
  apply pf.
  assumption.
Qed.

Global Instance to_string: ToString A
  := fun p => CExprPedraZ.AbDom.pr p.

Definition enrich_qchan (ab:A) (c:query_chan) : query_chan :=
  {| get_var_ty := c.(get_var_ty);
     AbIdealEnv.get_itv expr :=
       match c.(AbIdealEnv.get_itv) expr, get_itv expr ab with
         | NotBot (Just (Az i1)), NotBot (Just (Az i2)) =>
           fmap (@Just _Az) (i1i2)
         | NotBot (Just (Af i1)), NotBot (Just (Af i2)) =>
           fmap (@Just _Af) (i1i2)
         | NotBot All, NotBot ab | NotBot ab, NotBot All => NotBot ab
         | _, _ => Bot
       end;
     get_congr := c.(get_congr);
     get_eq_expr := c.(get_eq_expr);
     linearize_expr := c.(linearize_expr) |}.

Lemma enrich_qchan_correct :
  forall chan ab ρ,
    ρ ∈ γ chan -> ρ ∈ γ ab -> ρ ∈ γ (enrich_qchan ab chan).
Proof.
  intros chan ab ρ H H0. constructor.
  - intros. apply H.
  - intros. simpl.
    destruct H. specialize (get_itv_correct0 _ _ H1). destruct AbIdealEnv.get_itv. contradiction.
    pose proof (get_itv_correct _ _ _ H0 _ H1).
    destruct x as [|[]], (get_itv e ab) as [|[|[]]], a; auto; try contradiction.
    eapply botbind_spec; eauto. intros. apply H2. apply meet_correct; eauto.
    apply botbind_spec with f1; eauto. apply meet_correct; eauto.
  - intros. apply H. auto.
  - intros. apply H. auto.
  - intros. eapply H; eauto.
Qed.

Global Instance PolAbIdealEnv: ab_ideal_env A (A+⊥) :=
  { id_gamma := PolGammaOp;
    id_top c := NotBot (CExprPedraZ.AbDom.top, nil);
    id_join x y c := NotBot (CExprPedraZ.AbDom.join (fst x) (fst y), nil);
    id_init_iter := id;
    id_widen x y c :=
      let w :=
          match x with
          | Bot => fmap fst y
          | NotBot x =>
            match y with
            | Bot => NotBot x
            | NotBot y =>
              NotBot (CExprPedraZ.AbDom.join x
                       (CExprPedraZ.AbDom.widen x
                         (CExprPedraZ.AbDom.join x (fst y))))
            end
          end
      in
      (w, do w <- w; ret (w, nil));
    assign x e ab c := fmap (fun ab => (ab, nil)) (assign x e ab c);
    forget x ab c := fmap (fun ab => (ab, nil)) (forget x ab c);
    process_msg m ab :=
      match m with
        | Fact_msg e b =>
          do res <- assume_unfold
                      (J:=fun x y => NotBot (CExprPedraZ.AbDom.join x y))
                      assume e b ab;
          ret (res, (m::nil)%list)
        | Known_value_msg x (INz v) =>
          do res <-
             propagateBot (TrustedPedraZ.FullDom.assume
                             (ASCond.ZCond .Atom NumC.Eq (ASTerm.ZTerm.Var (v2p x))
                                                 (ASTerm.ZTerm.Cte v))
                             (fst ab));
          ret (res, (m::nil)%list)
        | _ => ret (fst ab, (m::nil)%list)
      end;
    enrich_query_chan ab c := enrich_qchan ab c }.
Proof.
- intros. split. apply CExprPedraZ.AbDom.gamma_top. constructor.
- intros. eapply gamma_monotone. 2:eauto. apply H.
- intros. split. eapply join_sound; eauto. constructor.
- auto.
- intros. destruct ab1. contradiction. destruct ab2.
  + split. auto. split. auto. constructor.
  + split. eapply CExprPedraZ.AbDom.join_sound. auto.
    split. eapply CExprPedraZ.AbDom.join_sound. auto.
    constructor.
- intros. eapply botbind_spec, assign_correct; eauto. intros. split. eauto. constructor.
- intros. eapply botbind_spec, forget_correct; eauto. intros. split. eauto. constructor.
- intros. destruct m; try (split; [apply H|constructor; [auto|constructor]]).
  + eapply botbind_spec. intros. split. eauto. constructor. auto. constructor.
    apply assume_unfold_correct; eauto.
    intros. eapply CExprPedraZ.AbDom.join_sound. auto.
    intros. eapply assume_correct; auto.
  + destruct i; try (split; [apply H|constructor; [auto|constructor]]).
    eapply botbind_spec. intros. split. eauto. constructor. auto. constructor.
    apply propagateBot_correct, TrustedPedraZ.FullDom.assume_correct, H.
    simpl. unfold liftRho, liftN. rewrite BIJ.(@forward _ _ _ _), H0. auto.
- intros. apply enrich_qchan_correct; auto.
Defined.