Qcert.Basic.Util.RList


Section RList.



  Section misc.
    Context {A:Type}.

    Definition singleton {A} (x:A) : list A := x::nil.

    Lemma is_nil_dec (l:list A) : {l = nil} + {l ≠ nil}.

    Fixpoint lflatten (l:list (list A)) : list A :=
      match l with
      | nil ⇒ nil
      | l1 :: l' ⇒
        l1 ++ (lflatten l')
      end.

    Lemma flat_map_app {B} (f:A→list B) l1 l2 :
      flat_map f (l1 ++ l2) = flat_map f l1 ++ flat_map f l2.

    Lemma map_nil f l :
      map f l = (@nil A) ↔ l = (@nil A).

    Lemma eq_means_same_length :
      ∀ (l1 l2:list A),
        l1 = l2 → (length l1) = (length l2).

    Lemma app_cons_middle (l1 l2:list A) (a:A) :
      l1 ++ (a::l2) = (l1 ++ (a::nil))++l2.

  End misc.

  Lemma map_app_break {A B:Type} (f:A→B) {a b c} :
    map f a = b ++ c →
    {b':list A & {c' : list A | a = b' ++ c' ∧ b = map f b' ∧ c = map f c'}}.

  Lemma map_inj_strong {A B} (f g:A→B) (l1 l2:list A)
        (inj:∀ (x y:A), In (f x) (map f l1) → In (g y) (map g l2) → f x = g y → x = y) :
    map f l1 = map g l2 →
    l1 = l2.

  Lemma map_inj {A B} (f g:A→B) (l1 l2:list A)
        (inj:∀ (x y:A), f x = g y → x = y) :
    map f l1 = map g l2 →
    l1 = l2.

  Section folds.
    Context {A B C: Type}.

    Lemma fold_left_map
          (f:A → C → A) (g:B→C) (l:list B) (init:A) :
      fold_left f (map g l) init = fold_left (fun a b ⇒ f a (g b)) l init.

    Lemma fold_left_ext
          (f g:A → B → A) (l:list B) (init:A) :
      (∀ x y, f x y = g x y) →
      fold_left f l init = fold_left g l init.

    Lemma fold_right_app_map_singleton l :
    fold_right (fun a b : list A ⇒ a ++ b) nil
              (map (fun x : A ⇒ (x::nil)) l) = l.

  Lemma fold_right_perm (f : A → A → A)
        (assoc:∀ x y z : A, f x (f y z) = f (f x y) z)
        (comm:∀ x y : A, f x y = f y x) (l1 l2:list A) (unit:A)
        (perm:Permutation l1 l2) :
    fold_right f unit l1 = fold_right f unit l2.

  End folds.

  Section filter.
    Context {A:Type}.

    Lemma filter_length :
      ∀ (p:A → bool), ∀ (l:list A),
          length l ≥ length (filter p l).

    Lemma filter_smaller :
      ∀ (p:A → bool), ∀ (l:list A), ∀ (x:A),
            filter p l ≠ x::l.

    Lemma filter_filter :
      ∀ (p:A → bool), ∀ (s:list A),
          filter p (filter p s) = filter p s.

    Lemma filter_not_filter:
      ∀ (p:A → bool), ∀ (s:list A),
            filter p (filter (fun x ⇒ negb (p x)) s) = nil.

    Lemma filter_id_implies_pred :
      ∀ (p:A → bool), ∀ (l:list A),
          filter p l = l → ∀ (y:A), (In y l → (p y = true)).

    Lemma filter_nil_implies_not_pred :
      ∀ (p:A → bool), ∀ (l:list A),
          filter p l = nil → ∀ (y:A), (In y l → (p y = false)).

    Lemma filter_comm:
      ∀ (x:list A) (p1 p2: A → bool),
        (filter p1 (filter p2 x)) = (filter p2 (filter p1 x)).

    Lemma filter_and:
      ∀ (x:list A) (p1 p2: A → bool),
        (filter p1 (filter p2 x)) = (filter (fun a ⇒ andb (p1 a) (p2 a)) x).

    Lemma filter_eq:
      ∀ (p1 p2:A → bool),
        (∀ x:A, p1 x = p2 x) → (∀ l:list A, filter p1 l = filter p2 l).

    Lemma false_filter_nil {f} {l:list A} :
      (∀ x, In x l → f x = false) → filter f l = nil.

    Lemma filter_app (f:A→bool) l1 l2 :
      filter f (l1 ++ l2) = filter f l1 ++ filter f l2.

    Lemma Forall_filter {P} {l:list A} f :
      Forall P l → Forall P (filter f l).

    Lemma find_filter f (l:list A) : find f l = hd_error (filter f l).

    Lemma filter_ext (f g : A → bool) (l : list A) :
      (∀ x, In x l → f x = g x) →
      filter f l = filter g l.

    Lemma true_filter (f : A → bool) (l : list A) :
      (∀ x : A, In x l → f x = true) → filter f l = l.

  End filter.


        Lemma forall_in_dec {A:Type} P (l:list A)
          (dec:∀ x, In x l → {P x} + {¬ P x}):
      {∀ x, In x l → P x} + {¬ ∀ x, In x l → P x}.

    Lemma exists_in_dec {A:Type} P (l:list A)
          (dec:∀ x, In x l → {P x} + {¬ P x}):
      {∃ x, In x l ∧ P x} + {¬ ∃ x, In x l ∧ P x}.

    Lemma exists_nforall_in_dec {A:Type} P (l:list A)
          (dec:∀ x, In x l → {P x} + {¬ P x}):
      {∃ x, In x l ∧ P x} + {∀ x, In x l → ¬P x}.

      Lemma existsb_ex {A : Type} (f : A → bool) (l : list A) :
       existsb f l = true → {x : A | In x l ∧ f x = true}.

  Section perm_equiv.
    Context {A:Type}.
    Context {eqdec:EqDec A eq}.

    Definition ldeqA := (@Permutation A).

    Definition rbag := list A.

    Global Instance perm_equiv : Equivalence (@Permutation A).
  End perm_equiv.

  Section list2.
    Context {A B:Type}.

    Section fb2.
      Context (f:A→B→bool).
      Fixpoint forallb2 (l1:list A) (l2:list B): bool :=
        match l1,l2 with
          | nil, nil ⇒ true
          | a1::l1, a2::l2 ⇒ f a1 a2 && forallb2 l1 l2
          | _, _ ⇒ false
        end.

      Lemma forallb2_forallb : ∀ (l1:list A) (l2:list B),
                                 (length l1 = length l2) →
                                 forallb (fun xy ⇒ f (fst xy) (snd xy)) (combine l1 l2) = forallb2 l1 l2.

      Lemma forallb2_forallb_true : ∀ (l1:list A) (l2:list B),
                                      (length l1 = length l2 ∧ forallb (fun xy ⇒ f (fst xy) (snd xy)) (combine l1 l2) = true)
                                      ↔
                                      forallb2 l1 l2 = true.

      Lemma forallb2_Forallb : ∀ l1 l2, forallb2 l1 l2 = true ↔ Forall2 (fun x y ⇒ f x y = true) l1 l2.

    End fb2.

    Lemma Forall2_incl : ∀ (f1 f2:A→B→Prop) l1 l2,
                           (∀ x y, In x l1 → In y l2 → f1 x y→ f2 x y) →
                           Forall2 f1 l1 l2 → Forall2 f2 l1 l2.

    Lemma forallb2_eq : ∀ (f1 f2:A→B→bool) l1 l2,
                          (∀ x y, In x l1 → In y l2 → f1 x y = f2 x y) →
                          forallb2 f1 l1 l2 = forallb2 f2 l1 l2.

  End list2.

  Section forall2.

    Lemma forallb2_sym {A B} : ∀ (f:A→B→bool) {l1 l2},
      forallb2 f l1 l2 = forallb2 (fun x y ⇒ f y x) l2 l1.

    Lemma Forall2_map {A B C D} (f:C→D→Prop) (g:A→C) (h:B→D) a b:
      Forall2 (fun x y ⇒ f (g x) (h y)) a b ↔ Forall2 f (map g a) (map h b).

    Lemma Forall2_map_f {A B C D} (f:C→D→Prop) (g:A→C) (h:B→D) a b:
      Forall2 (fun x y ⇒ f (g x) (h y)) a b → Forall2 f (map g a) (map h b).

    Lemma Forall2_map_b {A B C D} (f:C→D→Prop) (g:A→C) (h:B→D) a b:
      Forall2 f (map g a) (map h b) → Forall2 (fun x y ⇒ f (g x) (h y)) a b.

    Lemma Forall2_length {A B} (f:A→B→Prop) a b:
      Forall2 f a b → length a = length b.

    Global Instance Forall2_refl {A} R `{Reflexive A R} : Reflexive (Forall2 R).

    Global Instance Forall2_sym {A} R `{Symmetric A R} : Symmetric (Forall2 R).

    Global Instance Forall2_trans {A} R `{Transitive A R} : Transitive (Forall2 R).

  Global Instance Forall2_pre {A} R `{PreOrder A R} : PreOrder (Forall2 R).

  Global Instance Forall2_part_eq {A} R `{PartialOrder A eq R } :
    PartialOrder eq (Forall2 R).

  Lemma Forall2_trans_relations_weak {A B C}
        (R1:A→B→Prop) (R2:B→C→Prop) (R3:A→C→Prop):
    (∀ a b c, R1 a b → R2 b c → R3 a c) →
    ∀ a b c, Forall2 R1 a b → Forall2 R2 b c → Forall2 R3 a c.

    Lemma Forall2_eq {A} (l1 l2:list A): Forall2 eq l1 l2 ↔ l1 = l2.

    Lemma Forall2_flip {A B} {P:A→B→Prop} {l1 l2} :
      Forall2 P l1 l2 → Forall2 (fun x y ⇒ P y x) l2 l1.

    Lemma Forall2_In_l {A B} {P:A→B→Prop} {l1 l2 a} :
      Forall2 P l1 l2 →
      In a l1 →
      ∃ b,
        In b l2 ∧
        P a b.

    Lemma Forall2_In_r {A B} {P:A→B→Prop} {l1 l2 b} :
      Forall2 P l1 l2 →
      In b l2 →
      ∃ a,
        In a l1 ∧
        P a b.

  Lemma Forall2_app_tail_inv {A B} P l1 l2 a1 a2 :
     @Forall2 A B P (l1 ++ (a1::nil)) (l2 ++ (a2::nil)) →
     Forall2 P l1 l2 ∧ P a1 a2.

  Lemma filter_Forall2_same {A B} P f g (l1:list A) (l2:list B) :
    Forall2 P l1 l2 →
    map f l1 = map g l2 →
    Forall2 P (filter f l1) (filter g l2).

  Lemma Forall2_map_Forall {A B:Type} (P:A→B→Prop) (f:A→B) l :
    Forall2 P l (map f l) ↔ Forall (fun x ⇒ P x (f x)) l.

  End forall2.

  Section forallb_ordpairs.

    Fixpoint forallb_ordpairs {A} f (l:list A)
      := match l with
         | nil ⇒ true
         | x::ls ⇒ forallb (f x) ls && forallb_ordpairs f ls
         end.

    Lemma forallb_ordpairs_ForallOrdPairs {A} f (l:list A) :
      forallb_ordpairs f l = true ↔ (ForallOrdPairs (fun x y ⇒ f x y = true) l).

    Lemma forallb_ordpairs_ext {A} f1 f2 (l:list A) :
      (∀ x y, In x l → In y l → f1 x y = f2 x y) →
      forallb_ordpairs f1 l = forallb_ordpairs f2 l.

    Fixpoint forallb_ordpairs_refl {A} (f:A→A→bool) (l:list A)
      := match l with
         | nil ⇒ true
         | x::ls ⇒ forallb (f x) (x::ls) && forallb_ordpairs_refl f ls
         end.

    Lemma forallb_ordpairs_refl_conj A f (l:list A) :
      forallb_ordpairs_refl f l = forallb_ordpairs f l && forallb (fun x ⇒ f x x) l.

        Lemma forallb_ordpairs_app_cons {A} f (l:list A) x :
    forallb_ordpairs f l = true →
    forallb (fun y ⇒ f y x) l = true →
    forallb_ordpairs f (l ++ x::nil) = true.

  Lemma forallb_ordpairs_refl_app_cons {A} f (l:list A) x :
    forallb_ordpairs_refl f l = true →
    f x x = true →
    forallb (fun y ⇒ f y x) l = true →
    forallb_ordpairs_refl f (l ++ x::nil) = true.

  End forallb_ordpairs.

  Lemma app_cons_cons_expand {A} (l:list A) a b :
    l ++ a::b::nil = (l ++ a ::nil)++b::nil.

  Section remove.
    Context {A:Type}.
    Context {eqdec:EqDec A eq}.

    Lemma remove_in_neq
          (l : list A) (x y : A) : x ≠ y →
                                   (In x l ↔ In x (remove eqdec y l)).

    Lemma list_in_remove_impl_diff x y l:
      In x (remove eqdec y l) → x ≠ y.

    Lemma list_remove_append_distrib:
      ∀ (v:A) (l1 l2:list A),
        remove eqdec v l1 ++ remove eqdec v l2 = remove eqdec v (l1 ++ l2).

    Lemma list_remove_idempotent:
      ∀ v l,
        remove eqdec v (remove eqdec v l) = remove eqdec v l.

    Lemma list_remove_commute:
      ∀ v1 v2 l,
        remove eqdec v1 (remove eqdec v2 l) = remove eqdec v2 (remove eqdec v1 l).

    Remark list_remove_in v1 v2 l1 l2:
      (In v1 l1 → In v1 l2) →
      In v1 (remove eqdec v2 l1) → In v1 (remove eqdec v2 l2).

    Lemma remove_inv v n l:
      In v (remove eqdec n l) → In v l ∧ v ≠ n.

    Lemma not_in_remove_impl_not_in:
      ∀ x v l,
        x ≠ v →
        ¬ In x (remove eqdec v l) →
        ¬ In x l.

    Fixpoint remove_all (x : A) (l : list A) : list A :=
      match l with
      | nil ⇒ nil
      | y::tl ⇒ if (x == y) then (remove_all x tl) else y::(remove_all x tl)
      end.

    Global Instance remove_all_proper : Proper (eq ==> ldeqA ==> ldeqA) remove_all.

    Lemma remove_all_filter x l:
      remove_all x l = filter (nequiv_decb x) l.

    Lemma remove_all_app (v:A) l1 l2
      : remove_all v (l1 ++ l2) = remove_all v l1 ++ remove_all v l2.

    Lemma fold_left_remove_all_In {l init a} :
      In a (fold_left (fun (a : list A) (b : A) ⇒
                       filter (nequiv_decb b) a) l init)
      → In a init ∧ ¬ In a l.

  End remove.

  Lemma nin_remove {A} dec (l:list A) a :
    ¬ In a l → remove dec a l = l.

  Section repall.
    Context {A:Type}.
    Context `{eqdec:EqDec A eq}.

    Definition replace_all l v n
      := map (fun x ⇒ if eqdec x v then n else x) l.

    Lemma replace_all_nin l v n :
      ¬ In v l →
      map (fun x ⇒ if eqdec x v then n else x) l = l.

    Lemma replace_all_remove_neq l v0 v n:
      v ≠ v0 → n ≠ v0 →
      remove eqdec v0
             (map (fun x ⇒ if eqdec x v then n else x)
                  l) =
      (map (fun x ⇒ if eqdec x v then n else x)
           (remove eqdec v0 l)).

    Lemma remove_replace_all_nin l v v' :
      ¬ In v' l →
      remove eqdec v' (replace_all l v v') =
      remove eqdec v l.

    Definition flat_replace_all l (v:A) n
      := flat_map (fun x ⇒ if eqdec x v then n else (x::nil)) l.

    Lemma flat_replace_all_nil l (v:A) :
      flat_replace_all l v nil = @remove_all A eqdec v l.

    Lemma flat_replace_all_app l1 l2 (v:A) n
      : flat_replace_all (l1 ++ l2) v n
        = flat_replace_all l1 v n ++ flat_replace_all l2 v n.

    Lemma fold_left_remove_all_nil_in_inv {B} {x ps l}:
      In x (fold_left
              (fun (h : list nat) (xy : nat × B) ⇒
                 remove_all (fst xy) h)
              ps l) →
      In x l.

    Lemma fold_left_remove_all_nil_in_inv' {x ps l}:
      In x (fold_left
              (fun (h : list nat) (xy : nat) ⇒
                 remove_all xy h)
              ps l) →
      In x l.

    Lemma fold_left_remove_all_nil_in_not_inv' {x ps l}:
      In x (fold_left
              (fun (h : list nat) (xy : nat ) ⇒
                 remove_all xy h)
              ps l) →
      ¬ In x ps.

    Lemma replace_all_remove_eq (l : list A) (v n : A) :
      map (fun x : A ⇒ if eqdec x v then n else x) (remove eqdec v l) = (remove eqdec v l).

  End repall.

  Section incl.

    Definition cut_down_to {A B} {dec:EqDec A eq} (l:list (A×B)) (l2:list A) :=
      filter (fun a ⇒ existsb (fun z ⇒ (fst a) ==b z) l2) l.

    Lemma cut_down_to_in
          {A B} {dec:EqDec A eq}
          (l:list (A×B)) l2 a :
      In a (cut_down_to l l2) ↔ In a l ∧ In (fst a) l2 .

    Lemma cut_down_to_app {A B} {dec:EqDec A eq}
          (l l':list (A×B)) l2 :
      cut_down_to (l++l') l2 = cut_down_to l l2 ++ cut_down_to l' l2.

    Lemma incl_dec {A} {dec:EqDec A eq} (l1 l2:list A) :
      {incl l1 l2} + {¬ incl l1 l2}.

    Global Instance incl_pre A : PreOrder (@incl A).

    Lemma set_inter_contained {A} dec (l l':list A):
      (∀ a, In a l → In a l') →
      set_inter dec l l' = l.

    Lemma set_inter_idempotent {A} dec (l:list A):
      set_inter dec l l = l.

    Lemma set_inter_comm_in {A} dec a b :
      (∀ x, In x (@set_inter A dec a b) → In x (set_inter dec b a)) .

   Lemma nincl_exists {A} {dec:EqDec A eq} (l1 l2:list A) :
     ¬ incl l1 l2 → {x | In x l1 ∧ ¬ In x l2}.

  End incl.

  Section equivlist.
    Context {A:Type}.

    Definition equivlist (l l':list A)
      := ∀ x, In x l ↔ In x l'.

    Global Instance equivlist_equiv : Equivalence equivlist.

    Global Instance Permutation_equivlist :
      subrelation (@Permutation A) equivlist.

    Lemma equivlist_in {l1 l2} : equivlist l1 l2 → (∀ x:A, In x l1 → In x l2).

    Lemma equivlist_incls (l1 l2:list A) :
      equivlist l1 l2 ↔ (incl l1 l2 ∧ incl l2 l1).

    Global Instance equivlist_In_proper : Proper (eq ==> equivlist ==> iff) (@In A).

    Lemma equivlist_dec {dec:EqDec A eq} (l1 l2:list A) :
      {equivlist l1 l2} + {¬ equivlist l1 l2}.

    Lemma equivlist_nil {l:list A} : equivlist l nil → l = nil.

    Lemma app_idempotent_equivlist (l:list A) :
      equivlist (l++l) l.

    Lemma app_commutative_equivlist (l1 l2:list A) :
      equivlist (l1++l2) (l2++l1).

    Lemma app_contained_equivlist (a b:list A) :
      incl b a →
      equivlist (a ++ b) a.

    Lemma set_inter_equivlist dec a b :
      equivlist (@set_inter A dec a b) (set_inter dec b a) .

    Global Instance set_inter_equivlist_proper dec : Proper (equivlist ==> equivlist ==> equivlist) (@set_inter A dec).

  Lemma equivlist_cons l1 l2 (s:A) :
    equivlist l1 l2 →
    equivlist (s::l1) (s::l2).

  Global Instance equivlist_filter :
    Proper (eq ==> equivlist ==> equivlist) (@filter A).

  Global Instance equivlist_remove_all {dec:EqDec A eq} :
    Proper (eq ==> equivlist ==> equivlist) (@remove_all A dec).

    Lemma incl_list_dec (dec:∀ x y:A, {x = y} + {x ≠ y}) (l1 l2:list A) : {(∀ x, In x l1 → In x l2)} + {~(∀ x, In x l1 → In x l2)}.

  End equivlist.

      Lemma set_inter_assoc {A} dec a b c:
        @set_inter A dec (set_inter dec a b) c
        = set_inter dec a (set_inter dec b c).

  Section Assym_over.

    Definition asymmetric_over {A} R (l:list A) :=
      ∀ x y, In x l→ In y l → ¬R x y → ¬R y x → x = y.

    Lemma asymmetric_asymmetric_over {A} {R} :
      (∀ x y:A, ¬R x y → ¬R y x → x = y) →
      ∀ l, asymmetric_over R l .

    Lemma asymmetric_over_incl {A} {R} {l2:list A}
      : asymmetric_over R l2 →
        ∀ l1,
          (∀ x, In x l1 → In x l2) →
          asymmetric_over R l1.

    Lemma asymmetric_over_equivlist {A} {R} {l1 l2:list A} :
      equivlist l1 l2 →
      (asymmetric_over R l1 ↔
       asymmetric_over R l2).

    Lemma asymmetric_over_cons_inv {A} {R} {a:A} {l1} :
      asymmetric_over R (a::l1) →
      asymmetric_over R l1.


    Lemma asymmetric_over_swap {A} R {a b:A} {l1} :
      asymmetric_over R (a::b::l1) →
      asymmetric_over R (b::a::l1).

  End Assym_over.


  Global Instance perm_in {A} : Proper (eq ==> (@Permutation A) ==> iff) (@In A).

  Lemma NoDup_perm' {A:Type} {a b:list A} : NoDup a → Permutation a b → NoDup b.

  Global Instance NoDup_perm {A:Type} :
    Proper (@Permutation A ==> iff) (@NoDup A).

  Lemma NoDup_Permutation' {A : Type} (l l' : list A) :
    NoDup l →
    NoDup l' → equivlist l l' → Permutation l l'.

  Lemma NoDup_rev {A:Type} (l:list A) : NoDup (rev l) ↔ NoDup l.

  Lemma NoDup_app_inv {A:Type} {a b:list A} : NoDup (a++b) → NoDup a.


  Lemma NoDup_app_inv2 {A:Type} {a b:list A} : NoDup (a++b) → NoDup b.

  Lemma NoDup_dec {A:Type} {dec:EqDec A eq} (l:list A): {NoDup l} + {¬NoDup l}.

  Section disj.
    Definition disjoint {A:Type} (l1 l2:list A)
      := ∀ x, In x l1 → In x l2 → False.

    Lemma NoDup_app_dis {A:Type} (a b:list A) :
      NoDup (a++b) → disjoint a b.

    Lemma disjoint_cons_inv1 {A:Type} {a:A} {l1 l2} :
      disjoint (a :: l1) l2 → disjoint l1 l2 ∧ ¬ In a l2.

    Lemma disjoint_app_l {A} (l1 l2 l3:list A) :
    disjoint (l1 ++ l2) l3 ↔ (disjoint l1 l3 ∧ disjoint l2 l3).

   Lemma disjoint_app_r {A} (l1 l2 l3:list A) :
    disjoint l1 (l2 ++ l3) ↔ (disjoint l1 l2 ∧ disjoint l1 l3).

    Lemma NoDup_app {A:Type} {a b:list A} :
      disjoint a b → NoDup a → NoDup b → NoDup (a++b).

    Global Instance disjoint_sym {A:Type} : Symmetric (@disjoint A).

  End disj.

  Lemma unmap_NoDup {A B} (f:A→B) l :
    NoDup (map f l) → NoDup l.

  Lemma map_inj_NoDup {A B} (f:A→B)
            (inj:∀ x y, f x = f y → x = y) (l:list A) :
        NoDup l →
        NoDup (map f l).

  Lemma filter_NoDup {A} (f:A→bool) l :
    NoDup l → NoDup (filter f l).

  Fixpoint zip {A B} (l1:list A) (l2: list B) : option (list (A × B)) :=
    match l1 with
    | nil ⇒
      match l2 with
      | nil ⇒ Some nil
      | _ ⇒ None
      end
    | x1 :: l1' ⇒
      match l2 with
      | nil ⇒ None
      | x2 :: l2' ⇒
        match zip l1' l2' with
        | None ⇒ None
        | Some l3 ⇒
          Some ((x1, x2) :: l3)
        end
      end
    end.

End RList.