Lvc.Infra.MoreListSet

Require Import Util CSet LengthEq List Get Computable DecSolve AllInRel Omega.
Require Import Keep OptionR MoreList OUnion Annotation.

Lemma PIR2_ifSndR_keep X `{OrderedType X} n (AP:X)
  : PIR2 (ifSndR Subset) AP (keep n AP).
Proof.
  unfold keep, mapi. generalize 0.
  general induction AP; simpl.
  - econstructor.
  - cases; eauto using PIR2, @ifSndR.
Qed.

Lemma zip_AP_mon X Y `{OrderedType Y}
      (AP:list (set Y)) (DL:list X) (f:X set Y set Y)
      (LEN:length DL = length AP)
  : ( x y, y f x y)
     PIR2 Subset AP (zip f DL AP).
Proof.
  length_equify.
  general induction LEN; simpl; eauto using PIR2.
Qed.

Lemma drop_fold_zip_ounion X `{OrderedType X} A B k
  : ( n a, get A n a length a = length B)
     (drop k (fold_left (zip ounion) A B)) =
      fold_left (zip ounion) (List.map (drop k) A) (drop k B).
Proof with eauto 20 using get with len.
  general induction A; simpl; eauto.
  - rewrite IHA...
    + rewrite drop_zip...
Qed.

Notation "'olist_union' A B" := (fold_left (zip ounion) A B) (at level 50, A at level 0, B at level 0).

Lemma PIR2_olist_union_bound X `{OrderedType X} A b c
  : ( n a, get A n a PIR2 (ifFstR Subset) a c)
     PIR2 (ifFstR Subset) b c
     PIR2 (ifFstR Subset) (olist_union A b) c.
Proof.
  intros. general induction A; simpl; eauto.
  - eapply IHA; eauto using get, ifFstR_zip_ounion.
Qed.

Lemma get_olist_union_b X `{OrderedType X} A b n x
  : get b n (Some x)
     ( n a, get A n a a = b)
     s, get (olist_union A b) n (Some s) x s.
Proof.
  intros GETb LEN. general induction A; simpl in ×.
  - eexists x. eauto with cset.
  - exploit LEN; eauto using get.
    edestruct (get_length_eq _ GETb (eq_sym H0)) as [y GETa]; eauto.
    exploit (zip_get ounion GETb GETa).
    destruct y; simpl in ×.
    + exploit IHA; try eapply GET; eauto.
      rewrite zip_length2; eauto using get with len.
      edestruct H2; dcr; subst. eexists; split; eauto.
      rewrite <- H7; eauto.
    + exploit IHA; try eapply GET; eauto.
      rewrite zip_length2; eauto using get with len.
Qed.

Lemma get_olist_union_A X `{OrderedType X} A a b n k x
  : get A k a
     get a n (Some x)
     ( n a, get A n a a = b)
     s, get (olist_union A b) n (Some s) x s.
Proof.
  intros GETA GETa LEN.
  general induction A; simpl in × |- *; isabsurd.
  inv GETA; eauto.
  - exploit LEN; eauto using get.
    edestruct (get_length_eq _ GETa H0) as [y GETb].
    exploit (zip_get ounion GETb GETa).
    destruct y; simpl in ×.
    exploit (@get_olist_union_b _ _ A); eauto.
    rewrite zip_length2; eauto using get with len.
    destruct H2; dcr; subst. eexists; split; eauto.
    rewrite <- H4; eauto.
    eapply get_olist_union_b; try eapply GETunion; eauto.
    rewrite zip_length2; eauto using get with len.
  - eapply IHA; eauto.
    rewrite zip_length2; eauto using get with len.
Qed.

Lemma get_olist_union_A' X `{OrderedType X} A a b n k x p
  : get A k a
     get a n (Some x)
     ( n a, get A n a a = b)
     get (olist_union A b) n p
     s, p = (Some s) x s.
Proof.
  intros. edestruct get_olist_union_A; eauto; dcr.
  get_functional; eauto.
Qed.

Tactic Notation "Rexploit" uconstr(H) :=
  eapply modus_ponens; [refine H | intros].

Tactic Notation "Rexploit" uconstr(X) "as" ident(H) :=
  eapply modus_ponens; [refine X | intros H].

Lemma get_fold_zip_join X (f: X X X) (A:list (list X)) (b:list X) n
  : n < b
     ( n a, get A n a a = b)
     y, get (fold_left (zip f) A b) n y.
Proof.
  intros LE LEN. general induction A; simpl in ×.
  - edestruct get_in_range; eauto.
  - exploit LEN; eauto using get.
    eapply IHA; eauto using get with len.
Qed.

Definition ominus' {X} `{OrderedType X} (s : set X) (t : option (set X))
  := mdo t' <- t; s \ t' .

Definition minuso {X} `{OrderedType X}
           (s : set X) (t : option (set X)) := s \ oget t .

Lemma zip_ominus_contra {X} `{OrderedType X} DL b b'
  : PIR2 (fstNoneOrR Subset) b b'
     zip ominus' DL b zip ominus' DL b'.
Proof.
  intros.
  general induction H0; destruct DL; simpl; eauto using PIR2.
  - econstructor; eauto.
    + inv pf; simpl; econstructor.
      unfold flip. rewrite H1. eauto.
Qed.

Lemma PIR2_combineParams {X} `{OrderedType X}
      (A:list (ann (list (list X)) × list (option (set X))))
      (B C:list (option (set X)))
  : ( n a, get A n a length (snd a) = length B)
     PIR2 B C
     PIR2 B (olist_union (List.map snd A) C).
Proof.
  general induction B; invt PIR2.
  - clear H0. general induction A; eauto.
  - general induction A.
    + econstructor; eauto.
    + exploit H0; eauto using get.
      destruct a. destruct l; isabsurd. simpl in ×.
      assert (length YL = length l). {
        eapply PIR2_length in H1. simpl in ×. omega.
      }
      eapply IHA; eauto 10 using fstNoneOrR_ounion_left,
                  PIR2_ounion_left, get, @PIR2 with len.
Qed.

Lemma PIR2_combineParams_get {X} `{OrderedType X}
      (A:list (ann (list (list X)) × list (option (set X))))
      (B C:list (option (set X))) n a
  : ( n a, get A n a length (snd a) = length B)
     length B = length C
     get A n a
     PIR2 B (snd a)
     PIR2 B (olist_union (List.map snd A) C).
Proof.
  intros LEN1 LEN2 GET P. length_equify.
  general induction LEN2; simpl.
  - clear LEN1 GET P. general induction A; eauto.
  - clear IHLEN2.
    general induction GET; simpl.
    + exploit (LEN1); eauto using get.
      destruct x. destruct l; isabsurd. simpl in ×.
      eapply PIR2_combineParams; eauto using get.
      inv P.
      econstructor; eauto using fstNoneOrR_ounion_right, PIR2_ounion_right with len.
    + exploit (LEN1); eauto using get.
      destruct x'. destruct l; isabsurd. simpl in ×.
      eapply IHGET; eauto using get with len.
      eapply length_length_eq. rewrite zip_length2; try omega. eauto with len.
      eapply length_eq_length in LEN2. omega.
Qed.

Lemma PIR2_ominus_minuso {X} `{OrderedType X} A B B'
  : PIR2 (fstNoneOrR Subset) B B'
     ominus' A B minuso A B'.
Proof.
  intros EQ.
  general induction EQ; destruct A; simpl; eauto.
  econstructor; eauto.
  inv pf; simpl; econstructor.
  simpl. unfold flip. rewrite H0. reflexivity.
Qed.

Notation "DL \\ ZL" := (zip (fun s Ls \ of_list L) DL ZL) (at level 50).

Lemma ominus'_Some_oto_list {X} `{OrderedType X} A B C1 C2
  : PIR2 C1 C2
     ominus' (A \\ B) C1 Some A \\ app (A:=X) B (oto_list C2).
Proof.
  intros.
  general induction H0; simpl; destruct A, B; try reflexivity.
  - simpl; econstructor; eauto.
    + inv pf; simpl ominus'. econstructor.
      econstructor. unfold flip, oto_list.
      rewrite of_list_app. rewrite of_list_3.
      unfold flip in H0. rewrite <- minus_union.
      rewrite H1. reflexivity.
Qed.