Module AbIdealEnvProduct


Require Import AdomLib Util Coqlib.
Require Import AbIdealEnv IdealExpr.

Fixpoint process_msg_list {B iter_B:Type} `{ab_ideal_env B iter_B}
         (mchan:messages_chan) (ab:B * query_chan) (accu_mchan:messages_chan) :=
  match mchan with
    | nil => NotBot (fst ab, accu_mchan)
    | cons m mchanq =>
      do (ab', mchan') <- process_msg m ab;
      process_msg_list mchanq (ab', snd ab) (mchan'++accu_mchan)%list
  end.

Lemma process_msg_list_correct {A iter_A:Type} `{ab_ideal_env A iter_A}:
  forall (mchan:messages_chan) (ab:A * query_chan) (accu_mchan:messages_chan) ρ,
    ρ ∈ γ mchan -> ρ ∈ γ ab -> ρ ∈ γ accu_mchan ->
    ρ ∈ γ (process_msg_list mchan ab accu_mchan).
Proof.
  induction mchan. intros. destruct H1. split; auto. intros. simpl. inv H0.
  eapply botbind_spec with ρ, process_msg_correct; auto. intros [? ?] [? ?].
  apply IHmchan. auto. destruct H1; split; auto.
  simpl in *. clear - H2 H3.
  induction l. auto. inv H3. constructor. auto. apply IHl. auto.
Qed.

Instance ab_ideal_env_product {A iter_A B iter_B:Type}
         `(ab_ideal_env A iter_A)
         `(ab_ideal_env B iter_B) : ab_ideal_env (A*B) (iter_A*iter_B)%type :=
  {| id_init_iter a :=
       (id_init_iter (fmap fst a),
        id_init_iter (fmap snd a))
   ; id_top qchan :=
       do (a, mchana) <- id_top qchan;
       let qchana := enrich_query_chan a qchan in
       do (b, mchanb) <- id_top qchana;
       do (b, mchan) <- process_msg_list mchana (b, qchana) mchanb;
       ret ((a, b), mchan)
   ; id_leb x y :=
       let '((xa, xb), chan) := x in
       let '(ya, yb) := y in
       (id_leb (xa, chan) ya && id_leb (xb, chan) yb)%bool
   ; id_join x y qchan :=
       let '((xa, xb), xqchan) := x in
       let '((ya, yb), yqchan) := y in
       do (a, mchana) <- id_join (xa, xqchan) (ya, yqchan) qchan;
       let qchana := enrich_query_chan a qchan in
       do (b, mchanb) <- id_join (xb, xqchan) (yb, yqchan) qchana;
       do (b, mchan) <- process_msg_list mchana (b, qchana) mchanb;
       ret ((a, b), mchan)
   ; id_widen x y qchan :=
       let '(xa, xb) := x in
       let ayqchan := do (yab, yqchan) <- y; ret (fst yab, yqchan) in
       let '(ita, wa) := id_widen xa ayqchan qchan in
       let qchana :=
         do qchan <- qchan;
         do (a, _) <- wa;
         ret (enrich_query_chan a qchan)
       in
       let byqchan := do (yab, yqchan) <- y; ret (snd yab, yqchan) in
       let '(itb, wb) := id_widen xb byqchan qchana in
       ((ita, itb),
         do (a, mchana) <- wa;
         do (b, mchanb) <- wb;
         do qchana <- qchana;
         do (b, mchan) <- process_msg_list mchana (b, qchana) mchanb;
         ret ((a, b), mchan))
   ; assign v e ab qchan :=
       let '((a, b), abqchan) := ab in
       do (a, mchana) <- assign v e (a, abqchan) qchan;
       let qchana := enrich_query_chan a qchan in
       do (b, mchanb) <- assign v e (b, abqchan) qchana;
       do (b, mchan) <- process_msg_list mchana (b, qchana) mchanb;
       ret ((a, b), mchan)
   ; forget v ab qchan :=
       let '((a, b), abqchan) := ab in
       do (a, mchana) <- forget v (a, abqchan) qchan;
       let qchana := enrich_query_chan a qchan in
       do (b, mchanb) <- forget v (b, abqchan) qchana;
       do (b, mchan) <- process_msg_list mchana (b, qchana) mchanb;
       ret ((a, b), mchan)
   ; enrich_query_chan ab qchan :=
       let '(a, b) := ab in
       let qchan := enrich_query_chan a qchan in
       enrich_query_chan b qchan
   ; process_msg msg ab :=
       let '((a, b), abqchan) := ab in
       do (a, mchana) <- process_msg msg (a, abqchan);
       let qchana := enrich_query_chan a abqchan in
       do (b, mchan) <- process_msg_list mchana (b, qchana) nil;
       ret ((a, b), mchan)
  |}.
Proof.
  - intros.
    eapply botbind_spec with ρ, @id_top_correct; auto. intros [? ?] [? ?].
    eapply botbind_spec with ρ, @id_top_correct, @enrich_query_chan_correct; auto. intros [? ?] [? ?].
    eapply botbind_spec with ρ, process_msg_list_correct; auto. intros [? ?] [? ?].
    split. split. auto. auto. auto.
    split. auto. apply enrich_query_chan_correct; auto.
  - intros. destruct ab1 as [[] ?], ab2.
    rewrite Bool.andb_true_iff in H1. destruct H1.
    destruct H2. destruct H2.
    split. eapply id_leb_correct in H1. eauto. split. auto. auto.
    eapply id_leb_correct in H3. eauto. split. auto. auto.
  - intros. destruct ab1 as [[] ?], ab2 as [[] ?].
    eapply botbind_spec with ρ, @id_join_correct; auto. intros [? ?] [? ?].
    eapply botbind_spec with ρ, @id_join_correct; auto. intros [? ?] [? ?].
    eapply botbind_spec with ρ, process_msg_list_correct; auto. intros [? ?] [? ?].
    split. split. auto. auto. auto.
    split. auto. apply enrich_query_chan_correct; auto.
    destruct H1 as [[[] ?]|[[] ?]]; [left|right]; split; auto.
    apply enrich_query_chan_correct; auto.
    destruct H1 as [[[] ?]|[[] ?]]; [left|right]; split; auto.
  - split; apply id_init_iter_sound; eapply botbind_spec with a; eauto; intros; apply H2.
  - intros. destruct ab1. cbv zeta. destruct H1. unfold fst, snd in H1, H3.
    repeat match goal with
    | H:γ ?x ρ |- context [id_widen ?x ?y ?chan] =>
      let WINCR := fresh "WINCR" in
      assert (WINCR:=id_widen_incr x y chan ρ H);
      destruct (id_widen x y chan);
      assert (Hc:ρ ∈ γ chan); [|specialize (WINCR Hc); clear Hc]
    end.
    eapply H2. eapply botbind_spec, H2. intros.
    eapply botbind_spec with ρ. 2:apply WINCR. intros [? ?] [? ?].
    eapply enrich_query_chan_correct; auto.
    split. split. apply WINCR. apply WINCR0.
    eapply botbind_spec with ρ. 2:eapply WINCR. intros [? ?] [? ?].
    eapply botbind_spec with ρ. 2:eapply WINCR0. intros [? ?] [? ?].
    eapply botbind_spec with ρ.
    intros. eapply botbind_spec with ρ, process_msg_list_correct. intros [? ?] [? ?].
    split. split. apply H4. apply H9. apply H10. apply H5. split.
    apply H6. apply H8. apply H7.
    eapply botbind_spec, H2. intros.
    eapply botbind_spec with ρ. 2:eapply WINCR. intros [? ?] [? ?].
    eapply enrich_query_chan_correct. apply H9. apply H8.
  - intros. destruct ab as [[] ?], H1 as [[] ?].
    eapply botbind_spec with (upd ρ x n), @assign_correct; auto. intros [? ?] [? ?].
    eapply botbind_spec with (upd ρ x n), @assign_correct; auto. intros [? ?] [? ?].
    eapply botbind_spec with (upd ρ x n), @process_msg_list_correct; auto. intros [? ?] [? ?].
    split. split. auto. auto. auto.
    split. auto. apply enrich_query_chan_correct; auto. split; auto.
    apply enrich_query_chan_correct; auto. split; auto.
  - intros. destruct ab as [[] ?], H1 as [[] ?].
    eapply botbind_spec with (upd ρ x n), @forget_correct; auto. intros [? ?] [? ?].
    eapply botbind_spec with (upd ρ x n), @forget_correct; auto. intros [? ?] [? ?].
    eapply botbind_spec with (upd ρ x n), @process_msg_list_correct; auto. intros [? ?] [? ?].
    split. split. auto. auto. auto.
    split. auto. apply enrich_query_chan_correct; auto. split; auto.
    apply enrich_query_chan_correct; auto. split; auto.
  - intros. destruct ab as [[a b] c], H1 as [[Ha Hb] Hc].
    eapply botbind_spec with ρ, @process_msg_correct; auto. intros [? ?] [? ?].
    eapply botbind_spec with ρ, process_msg_list_correct; auto. intros [? ?] [? ?].
    split. split. auto. auto. auto.
    split. auto. apply enrich_query_chan_correct; auto.
    constructor.
    split; auto.
  - intros. destruct ab, H1.
    apply enrich_query_chan_correct; auto.
    apply enrich_query_chan_correct; auto.
Defined.

Section Reduce.

Context (A iter_A:Type) `{ab_ideal_env A iter_A}.

Definition reduced_product := { ab : A * query_chan | γ (fst ab) ⊆ γ (snd ab) }.

Instance reduced_gamma : gamma_op reduced_product (var -> ideal_num) :=
  fun ab => γ (proj1_sig ab).

Fixpoint filter_broadcasted (l:messages_chan) : messages_chan :=
  match l with
    | nil => nil
    | Broadcasted_msg m :: l => m :: filter_broadcasted l
    | _ :: l => filter_broadcasted l
  end.

Instance qchan_top : top_op query_chan :=
  let _ := tt in
  {| get_var_ty := fun v => ⊤;
     get_itv := fun e => ⊤;
     get_congr := fun e => ⊤;
     get_eq_expr := fun _ => None;
     linearize_expr := fun e => None |}.

Instance qchan_top_correct : top_op_correct query_chan (var -> ideal_num).
Proof.
  constructor.
  - constructor.
  - constructor.
  - intros. apply top_correct.
  - discriminate.
  - discriminate.
Qed.

Program Definition reduce (ab:(A*messages_chan)+⊥): reduced_product+⊥ :=
  do ab <- ab;
  let '(ab, mchanab) := ab return _ in
  let c := enrich_query_chan ab top in
  do (ab, _) <- process_msg_list (filter_broadcasted mchanab) (ab, c) nil;
  let qchan := enrich_query_chan ab top in
  ret ((ab, qchan):reduced_product).
Next Obligation.
eapply enrich_query_chan_correct, top_correct. auto. Qed.

Lemma reduce_correct:
  forall (ab:(A*messages_chan)+⊥) (ρ:var->ideal_num), ρ ∈ γ ab -> ρ ∈ γ (reduce ab).
Proof.
  intros.
  apply botbind_spec with ρ; auto. intros. destruct a, H1.
  apply botbind_spec with ρ, process_msg_list_correct; auto. intros. destruct a0, H3.
  split. auto. apply enrich_query_chan_correct, top_correct; auto.
  clear - H2. simpl in *. unfold messages_chan_gamma in *.
  induction m. auto. inv H2. destruct a0; auto. constructor; auto.
  split. auto. apply enrich_query_chan_correct, top_correct; auto.
  constructor.
Qed.

Program Instance ab_ideal_env_reduce: ab_ideal_env_nochan reduced_product iter_A :=
  {| idnc_top := reduce (id_top top)
   ; idnc_leb x y := id_leb x (fst y)
   ; idnc_join x y := reduce (id_join x y top)
   ; idnc_widen := {|
       init_iter x := id_init_iter (fmap (fst ∘ (@proj1_sig _ _)) x);
       widen x y :=
         let y := do y <- y; ret (proj1_sig y) in
         let '(it, w) := id_widen x y top return _ in
         (it, reduce w) |}
   ; idnc_assign v e ab := reduce (assign v e ab top)
   ; idnc_forget v ab := reduce (forget v ab top)
   ; idnc_assume c b ab := reduce (process_msg (Fact_msg c b) ab)
   ; idnc_get_query_chan ab := snd ab
  |}.
Next Obligation.
intro. apply reduce_correct, id_top_correct, top_correct. Qed.
Next Obligation.
  repeat intro. eapply id_leb_correct in H0; eauto.
  split; eauto. eapply (proj2_sig a2), H0.
Qed.
Next Obligation.
  repeat intro. apply reduce_correct, id_join_correct, top_correct.
  destruct H0 as [[]|[]]; [left|right]; split; auto; eapply proj2_sig.
Qed.
Next Obligation.
  split; intros; simpl.
  - eapply id_init_iter_sound. eapply botbind_spec with a, H0. intros. apply H1.
  - match goal with
    | |- context [id_widen ?A ?B ?C] => pose proof id_widen_incr A B C
    end.
    destruct id_widen. split. apply H1. auto. apply top_correct.
    apply reduce_correct. apply H1. auto. apply top_correct.
Qed.
Next Obligation.
  apply reduce_correct, assign_correct; auto. apply top_correct.
Qed.
Next Obligation.
  apply reduce_correct, forget_correct; auto. apply top_correct.
Qed.
Next Obligation.
apply reduce_correct, process_msg_correct; auto. Qed.
Next Obligation.
apply (proj2_sig ab), H0. Qed.

Program Instance reduced_ToString {T:ToString.ToString A} : ToString.ToString reduced_product :=
  fun x => T (fst x).

End Reduce.

Existing Instances reduced_ToString ab_ideal_env_reduce ab_ideal_env_product.