Lvc.Constr.MapAgreeSet

Require Export Setoid Coq.Classes.Morphisms.
Require Import EqDec Computable Util AutoIndTac.
Require Export CSet Containers.SetDecide.
Require Export MapBasics MapLookup MapAgreement.

Set Implicit Arguments.

Section MapAgreeSet.
  Variable X : Type.
  Context `{OrderedType X}.
  Variable Y : Type.
  Context `{OrderedType Y}.

  Definition agree_set (lv:set X) (m :XY) : set X
    := filter (fun xif [m x === x] then true else false) lv.

  Lemma agree_set_spec (lv:set X) (m : XY) x
        `{Proper _ (respectful _eq _eq) m} `{Proper _ (respectful _eq _eq) }
  : x agree_set lv m x lv m x === x.
  Proof.
    intros.
    assert (Proper (_eq ==> eq) (fun x : Xif [m x === x] then true else false)). {
      hnf; intros. cbv beta. repeat destruct if; eauto.
       - exfalso. eapply n. rewrite <- H2; eauto. rewrite H1; eauto.
       - exfalso; eapply n. rewrite H2; eauto. rewrite H1; eauto. }
    split; intros.
    + pose proof (filter_1 H4). pose proof (filter_2 H4).
      cbv beta in ×. destruct if in H6; eauto. congruence.
    + eapply filter_3.
      - eassumption.
      - eapply H4.
      - destruct if; eauto.
  Qed.

  Lemma agree_on_agree_set_eq
        (lv:set X) (D :XY)
        `{Proper _ (respectful _eq _eq) D} `{Proper _ (respectful _eq _eq) }
  : agree_on _eq lv D agree_set lv D [=] lv.
  Proof.
    intros. hnf; intros. split; intros.
    + eapply agree_set_spec in H4; decompose records; eauto.
    + eapply agree_set_spec; eauto. split; eauto. eapply H3; eauto.
  Qed.

  Lemma agree_set_agree_on Z `{OrderedType Z}
        (lv:set X) (D :XY) (E : XZ)
        `{Proper _ (respectful _eq _eq) D} `{Proper _ (respectful _eq _eq) }
  : agree_on _eq lv D agree_on _eq (agree_set lv D ) E
    → agree_on _eq lv E .
  Proof.
    intros. hnf; intros.
    eapply H5. eapply agree_set_spec; eauto. split; eauto.
    eapply H4; eauto.
  Qed.

  Lemma agree_on_agree_set (lv:set X) (D D´´: XY)
        `{Proper _ (respectful _eq _eq) D}
        `{Proper _ (respectful _eq _eq) }
        `{Proper _ (respectful _eq _eq) D´´}
  : agree_on _eq lv D agree_set lv D D´´ agree_set lv D´´.
  Proof.
    intros. hnf; intros. rewrite agree_set_spec in *; eauto.
    intuition. transitivity (D a); eauto. symmetry. eapply H4; eauto.
  Qed.

  Lemma agree_set_incl (lv:set X) (D : XY)
        `{Proper _ (respectful _eq _eq) D}
        `{Proper _ (respectful _eq _eq) }
  : (agree_set lv D ) lv.
  Proof.
    intros. hnf; intros. eapply agree_set_spec in H3; firstorder.
  Qed.

  Lemma agree_set_incl_both (lv´ lv:set X) (D :XY)
        `{Proper _ (respectful _eq _eq) D}
        `{Proper _ (respectful _eq _eq) }
  : lv´ lvagree_set lv´ D agree_set lv D .
  Proof.
    intros. hnf; intros. rewrite agree_set_spec in *; firstorder.
  Qed.

End MapAgreeSet.

Arguments agree_set {X} {H} {Y} {H0} lv m .
Arguments agree_set_spec {X} {H} {Y} {H0} lv m x {H1} {H2}.

Global Instance eq_cset_agree_set_morphism X `{OrderedType X} Y `{OrderedType Y}
  : Proper (SetInterface.Equal ==> (@fpeq X Y _eq H H0) ==> (@fpeq X Y _eq _ _) ==> SetInterface.Equal) (@agree_set X _ Y _ ).
Proof.
  unfold respectful; unfold fpeq.
  hnf;intros; decompose records. hnf.
  intros. split; intros.
  + eapply agree_set_spec in H2; eauto. decompose records.
    eapply agree_set_spec; eauto. split.
    - rewrite <- H1; eauto.
    - rewrite <- (H4 _). rewrite <- (H3 _); eauto.
  + eapply agree_set_spec in H2; eauto. decompose records.
    eapply agree_set_spec; eauto. split.
    - rewrite H1; eauto.
    - rewrite (H4 _). rewrite (H3 _); eauto.
Qed.

Add Parametric Morphism {X} `{OrderedType X} {Y} `{OrderedType Y} : (@lookup_set X _ Y _)
  with signature (@fpeq X Y _eq _ _) ==> SetInterface.Equal ==> SetInterface.Equal
    as eq_cset_lookup_set_morphism.
Proof.
  intros. intro. unfold fpeq in *; decompose records.
  split; intros; eapply lookup_set_spec in H1; decompose records; eauto.
  + eapply lookup_set_spec; eauto.
    eexists x1. split. rewrite <- H2; eauto. rewrite <- (H3 _); eauto.
  + eapply lookup_set_spec; eauto.
    eexists x1. split. rewrite H2; eauto. rewrite (H3 _); eauto.
Qed.

Add Parametric Morphism {X} `{OrderedType X} {Y} `{OrderedType Y}
  : (@lookup_set X _ Y _)
  with signature (@fpeq X Y _eq _ _) ==> Subset ==> Subset
    as incl_lookup_set_morphism.
Proof.
  intros. hnf; intros.
  unfold fpeq in *; decompose records.
  eapply lookup_set_spec in H3; decompose records; eauto; eapply lookup_set_spec; eauto.
  eexists x1. split. rewrite <- H2. eauto. rewrite <- (H4 _); eauto.
Qed.

Lemma agree_set_minus X `{OrderedType X} Y `{OrderedType Y} lv lv´ (D : XY)
      `{Proper _ (_eq ==> _eq) D} `{Proper _ (_eq ==> _eq) }
: agree_set lv D \ lv´ [=] agree_set (lv \ lv´) D .
Proof.
  intro. split; intros.
  + edestruct (@minus_in_in _ _ _ _ _ H3); eauto.
    rewrite agree_set_spec in H4 |- *; eauto.
    split.
  - eapply in_in_minus; eauto; eapply H4.
  - eapply H4.
    + rewrite agree_set_spec in H3; dcr; eauto.
      edestruct (minus_in_in _ _ _ _ H4); eauto.
      eapply in_in_minus; eauto. eapply agree_set_spec; eauto.
Qed.