Qcert.Basic.Util.RAssoc





Section RAssoc.

  Section assoc.
    Context {A B:Type}.
    Context (dec:∀ a a':A, {a=a'} + {a≠a'}).

    Fixpoint lookup l a : option B
      := match l with
           | nil ⇒ None
           | (f',v')::os ⇒ if dec a f' then Some v' else lookup os a
         end.

    Fixpoint update_first l a n : list (A×B)
      := match l with
           | nil ⇒ nil
           | (f',v')::os ⇒ if dec a f' then (a,n)::os else (f',v')::(update_first os a n)
         end.

    Definition domain (l:list (A×B)) := map (@fst A B) l.

    Lemma domain_eq (l:list (A×B)) : domain l = map fst l.

    Lemma domain_nil (l:list (A×B)) :
      domain l = nil ↔ l = nil.

    Lemma domain_rev (l:list (A×B)) : domain (rev l) = rev (domain l).

    Lemma domain_update_first l a v: domain (update_first l a v) = domain l.

    Lemma map_eta_fst_domain l :
      (map (fun x : A × B ⇒ fst x) l) = domain l.

    Lemma in_dom : ∀ {l} {a b}, In (a,b) l → In a (domain l).

    Lemma in_domain_in : ∀ {l} {a}, In a (domain l) → ∃ b, In (a,b) l.

    Lemma lookup_none_nin : ∀ {l} {a:A}, lookup l a = None → ¬ In a (domain l).

   Lemma lookup_nin_none {l x} : ¬ In x (domain l) → lookup l x = None.

    Lemma NoDup_domain_NoDup {l} : NoDup (domain l) → NoDup l.

    Lemma lookup_in : ∀ l {a:A} {b:B}, lookup l a = Some b → In (a,b) l.

    Lemma lookup_in_domain : ∀ l {a:A} {b:B}, lookup l a = Some b → In a (domain l).

    Lemma lookup_to_front {l a x} : lookup l a = Some x → ∃ l', Permutation l ((a,x)::l').

    Global Instance dom_perm : Proper (@Permutation (A×B) ==> @Permutation A) domain.

    Global Instance perm_nodup :Proper (@Permutation (A) ==> iff) (@NoDup A).

    Lemma nodup_in_eq : ∀ {l} {a b c}, NoDup (domain l) → In (a,b) l → In (a,c) l → b = c.


    Lemma in_dom_lookup_strong : ∀ {l} {a:A}, In a (domain l) → {v | lookup l a = Some v}.

    Lemma in_dom_lookup : ∀ {l} {a:A}, In a (domain l) → ∃ v, lookup l a = Some v.

    Lemma in_lookup_strong : ∀ {l} {a:A} {b0:B}, In (a,b0) l → {v | lookup l a = Some v}.

    Lemma in_lookup : ∀ {l} {a:A} {b0:B}, In (a,b0) l → ∃ v, lookup l a = Some v.

    Lemma in_lookup_nodup : ∀ {l} {a:A} {b:B}, NoDup (domain l) → In (a,b) l → lookup l a = Some b.

    Lemma nin_update {l a} : lookup l a = None → ∀ v, update_first l a v = l.

    Lemma in_update_break {l a v} :
      lookup l a = Some v → ∀ vv,
                             ∃ l1 l2, l = l1++(a,v)::l2 ∧
                                           update_first l a vv = l1++(a,vv)::l2.

    Lemma lookup_some_nodup_perm {l l'} a v:
      NoDup (domain l) →
      Permutation l l' →
      lookup l a = Some v →
      lookup l' a = Some v.

    Lemma lookup_none_perm {l l'} a :
      Permutation l l' →
      lookup l a = None →
      lookup l' a = None.

    Lemma update_first_NoDup_perm_proper {l l'} a v :
      NoDup (domain l) →
      Permutation l l' →
      Permutation (update_first l a v) (update_first l' a v).

    Lemma lookup_app {l1 l2} x:
      lookup (l1++l2) x =
      match lookup l1 x with
        | Some y ⇒ Some y
        | None ⇒ lookup l2 x
      end.

    Lemma lookup_app_in {l1 l2} a b :
      lookup (l1++l2) a = Some b → In (a,b) l1 ∨ In (a,b) l2.

    Lemma domain_cons a (l:list (A×B)) :
      domain (a::l) = (fst a)::domain l.

  End assoc.

  Lemma cut_down_to_incl_to
        {A B} {dec:EqDec A eq}
        (l:list (A×B)) l2 :
    incl (domain (cut_down_to l l2)) l2.

  Lemma incl_domain_cut_down_incl
        {A B} {dec:EqDec A eq}
        (l:list (A×B)) l2 :
    incl l2 (domain l) →
    incl l2 (domain (cut_down_to l l2)).

  Global Instance domain_incl_proper A B : Proper (@incl (A×B) ==> @incl A) (@domain A B).

  Fixpoint assoc_lookupr {A B:Type} {P Q:A→A→Prop} (eqd:∀ a a':A, {P a a'} + {Q a a'}) (l:list (A×B)) (a:A) : option B
    := match l with
       | nil ⇒ None
       | cons (a',d) r2 ⇒
         match assoc_lookupr eqd r2 a with
         | Some d' ⇒ Some d'
         | None ⇒
           if eqd a a'
           then Some d
           else None
         end
       end.

  Fixpoint projectr {A B:Type} {P Q:A→A→Prop} (eqd:∀ a a':A, {P a a'} + {Q a a'}) (l:list (A×B)) (ats:list A) : list (option (A×B)) :=
    match ats with
    | nil ⇒ nil
    | cons a ats' ⇒
      match assoc_lookupr eqd l a with
      | Some d ⇒ (Some (a,d)) :: (projectr eqd l ats')
      | None ⇒ None :: (projectr eqd l ats')
      end
    end.


  Lemma assoc_lookupr_app {A B:Type} (l1 l2:list (A×B)) x (dec:∀ x y, {x=y} + {x ≠ y}) :
    assoc_lookupr dec (l1++l2) x =
    match assoc_lookupr dec l2 x with
    | Some y ⇒ Some y
    | None ⇒ assoc_lookupr dec l1 x
    end.

  Lemma assoc_lookupr_lookup
        {A B} dec x (ls:list (A×B)):
    assoc_lookupr dec ls x = lookup dec (rev ls) x.

  Lemma lookup_assoc_lookupr
        {A B} dec x (ls:list (A×B)):
    lookup dec ls x = assoc_lookupr dec (rev ls) x.

  Lemma in_dom_lookupr_strong {A B:Type} (l:list (A×B)) a (dec:∀ x y, {x=y} + {x ≠ y}) :
    In a (domain l) → {v|assoc_lookupr dec l a = Some v}.

  Lemma in_dom_lookupr {A B:Type} (l:list (A×B)) a (dec:∀ x y, {x=y} + {x ≠ y}) :
    In a (domain l) → ∃ v, assoc_lookupr dec l a = Some v.

  Lemma assoc_lookupr_in {A B:Type} (l :list (A×B)) a b (dec:∀ x y, {x=y} + {x ≠ y}) :
    assoc_lookupr dec l a = Some b → In (a,b) l.

  Lemma assoc_lookupr_none_nin {A B}
         (dec : ∀ x0 y : A, {x0 = y} + {x0 ≠ y}) {l x} :
    assoc_lookupr dec l x = (@None B) → ¬ In x (domain l).

  Lemma assoc_lookupr_nodup_perm {A B:Type} (l l':list (A×B)) x (dec:∀ x y, {x=y} + {x ≠ y}) :
    NoDup (domain l) → Permutation l l' → assoc_lookupr dec l x = assoc_lookupr dec l' x.

  Lemma in_split_strong {A:Type} `{EqDec A eq} {x} {l:list A} : In x l → {l1:list A & {l2:list A | l = l1 ++ x::l2}}.

  Lemma assoc_lookupr_nin_none {A B:Type} (l:list (A×B)) x (dec:∀ x y, {x=y} + {x ≠ y}) : ¬ In x (domain l) → assoc_lookupr dec l x = None.

  Lemma in_assoc_lookupr_nodup {A B:Type} (l:list (A×B)) a b (dec:∀ x y, {x=y} + {x ≠ y}):
    NoDup (domain l) → In (a,b) l → assoc_lookupr dec l a = Some b.

  Definition permutation_dec {A:Type} `{EqDec A eq} (l l':list A)
    : {Permutation l l'} + {¬Permutation l l'}.

  Lemma permutation_prover {A:Set} {dec:EqDec A eq}
           (l1 l2:list A)
           (pf:holds (permutation_dec l1 l2)) :
              Permutation l1 l2.

  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 domain_length {A B:Type} (l:list (A×B)) :
    length (domain l) = length l.

  Lemma domain_app {A B:Type} (l₁ l₂:list (A×B)) :
    domain (l₁ ++ l₂) = domain l₁ ++ domain l₂.

  Section distinctdom.
    Fixpoint bdistinct_domain {A B} {R} `{dec:EqDec A R} (l:list (A×B)) :=
      match l with
      | nil ⇒ nil
      | x :: l' ⇒
        let dl' := bdistinct_domain l' in
        if (existsb (fun z ⇒ (fst x) ==b (fst z)) dl') then
          dl' else x::dl'
      end.

    Lemma bdistinct_domain_NoDup {A B} {dec:EqDec A eq} (l:list (A×B)) :
      NoDup (domain (bdistinct_domain l)).

    Lemma bdistinct_domain_domain_equiv {A B} {dec:EqDec A eq} (l:list (A×B)) :
      equivlist (domain (bdistinct_domain l)) (domain l).

    Lemma bdistinct_rev_domain_equivlist {A B} {dec:EqDec A eq} (l:list (A×B)) :
      equivlist ((domain l)) (domain (bdistinct_domain (rev l))).

    Lemma bdistinct_domain_assoc_lookupr {A B} {dec:EqDec A eq} (l:list (A×B)) :
      ∀ x,
        assoc_lookupr dec (bdistinct_domain l) x
        = assoc_lookupr dec l x.

  End distinctdom.

  Section lookup_eq.
    Context {A B:Type}.
    Context {dec:EqDec A eq}.

    Definition lookup_incl (l1 l2:list (A×B)) : Prop
      := ∀ (x:A) (y:B), lookup dec l1 x = Some y →
                             lookup dec l2 x = Some y.

    Global Instance lookup_incl_pre : PreOrder lookup_incl.

    Definition lookup_equiv (l1 l2:list (A×B)) : Prop
      := ∀ (x:A), lookup dec l1 x = lookup dec l2 x.

    Global Instance lookup_equiv_equiv : Equivalence lookup_equiv.

    Global Instance lookup_incl_equiv : subrelation lookup_equiv lookup_incl.

    Global Instance lookup_incl_part : PartialOrder lookup_equiv lookup_incl.

    Lemma lookup_incl_dec_nodup {decb:EqDec B eq} :
      ∀ x y, NoDup (domain x) → {lookup_incl x y} + {¬ lookup_incl x y}.

    Lemma lookup_incl_dec {decb:EqDec B eq} :
      ∀ x y, {lookup_incl x y} + {¬ lookup_incl x y}.

    Instance lookup_equiv_eqdec {decb:EqDec B eq} :
      EqDec (list (A×B)) lookup_equiv.

    Lemma lookup_incl_cons_l_nin (l1 l2:list (A×B)) x y :
      lookup_incl l1 l2 →
      ¬ In x (domain l1) →
      lookup_incl l1 ((x,y)::l2).

    Lemma lookup_remove_duplicate l v x l' x' l'' :
      lookup_equiv
        (l ++ (v,x)::l' ++ (v,x')::l'')
        (l ++ (v,x)::l' ++ l'').

    Lemma lookup_remove_nin l v0 (x:B) l' v :
      v ≠ v0 →
      lookup dec (l ++ (v0,x) :: l') v = lookup dec (l ++ l') v.

    Lemma lookup_swap_neq l1 v1 x1 v2 x2 l2 :
      v1 ≠ v2 →
      lookup_equiv
        (l1++(v1,x1)::(v2,x2)::l2)
        (l1++(v2,x2)::(v1,x1)::l2).

    Lemma lookup_equiv_perm_nodup {l1 l2} :
      NoDup (domain l1) →
      Permutation l1 l2 →
      lookup_equiv l1 l2.

  End lookup_eq.

  Lemma assoc_lookupr_lookup_nodup {A B} dec x (ls:list (A×B)):
    NoDup (domain ls) →
      assoc_lookupr dec ls x = lookup dec ls x.

    Lemma remove_domain_filter {A B} `{dec:EqDec A eq} s l:
    remove equiv_dec s (domain l) =
    domain (filter (fun x : A × B ⇒ s ≠b fst x) l).

   Lemma fold_left_remove_all_nil_in_not_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 (domain ps).

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

     Definition swap {A B} (xy:A×B) := (snd xy, fst xy).

  Section swap.
    Lemma swap_idempotent {A B} (a:A×B) : swap (swap a) = a.

    Lemma in_swap {A B} x (l:list (A×B)):
      In x (map swap l) ↔ In (swap x) l.

    Lemma in_swap_in {A B} x (l:list (A×B)):
      In (swap x) (map swap l) ↔ In x l.

  End swap.

  Section ldiff.

    Fixpoint lookup_diff {A B C:Type} (dec:∀ a a':A, {a=a'} + {a≠a'}) (l₁:list (A×B)) (l₂:list (A×C)) :=
      match l₁ with
        | nil ⇒ nil
        | x::xs ⇒ match lookup dec l₂ (fst x) with
                     | None ⇒ x::lookup_diff dec xs l₂
                     | Some _ ⇒ lookup_diff dec xs l₂
                   end
      end.

    Lemma lookup_diff_none1 {A B C:Type} (dec:∀ a a':A, {a=a'} + {a≠a'}) {l₁:list(A×B)} (l₂:list (A×C)) {x} :
      lookup dec l₁ x = None →
      lookup dec (lookup_diff dec l₁ l₂) x = None.

    Lemma lookup_diff_none2 {A B C:Type} (dec:∀ a a':A, {a=a'} + {a≠a'}) (l₁:list (A×B)) {l₂:list (A×C)} {x} :
      lookup dec l₂ x = None →
      lookup dec (lookup_diff dec l₁ l₂) x = lookup dec l₁ x.

    Lemma lookup_diff_some2 {A B C:Type} (dec:∀ a a':A, {a=a'} + {a≠a'}) (l₁:list(A×B)) {l₂:list (A×C)} {x t} :
      lookup dec l₂ x = Some t →
      lookup dec (lookup_diff dec l₁ l₂) x = None.

    Lemma lookup_diff_inv {A B C} (dec:∀ a a':A, {a=a'} + {a≠a'})
          x (l1:list (A×B)) (l2:list (A×C)):
      In x (lookup_diff dec l1 l2) →
      In x l1 ∧ ¬ In (fst x) (domain l2).

    Lemma lookup_diff_nilr {A B C:Type}
          (dec:∀ a a':A, {a=a'} + {a≠a'})
          (l₁:list (A×B)) :
      (lookup_diff dec l₁ (@nil (A×C))) = l₁.

    Lemma NoDup_lookup_diff {A B:Type} (dec:∀ a a':A, {a=a'} + {a≠a'})
          {r₁ r₂:list (A×B)} :
      NoDup (domain r₁) → NoDup (domain (lookup_diff dec r₁ r₂)).

    Lemma lookup_diff_domain_bounded {A B C} dec l₁ l₂ :
      incl (domain l₁) (domain l₂) →
      @lookup_diff A B C dec l₁ l₂ = nil.

    Lemma lookup_diff_bounded {A B} dec l₁ l₂ :
      incl l₁ l₂ →
      @lookup_diff A B B dec l₁ l₂ = nil.

    Lemma lookup_diff_same_domain2 {A B C D} dec (l1:list (A×B)) (l2:list (A×C)) (l3:list (A×D)) :
      equivlist (domain l2) (domain l3) →
      lookup_diff dec l1 l2 = lookup_diff dec l1 l3.

    Lemma map_lookup_diff {A B C} dec (f:A×B→A×C) (l1:list (A×B)) (l2:list (A×C)):
      (∀ a, fst a = fst (f a)) →
      map f (lookup_diff dec l1 l2) = lookup_diff dec (map f l1) l2.

    Lemma lookup_diff_disjoint
          {A B:Type}
          (dec:∀ a a':A, {a=a'} + {a≠a'})
          (l₁ l₂:list (A×B)) :
      disjoint (domain (lookup_diff dec l₁ l₂)) (domain l₂).

  End ldiff.

  Section substlist.

    Definition substlist_subst {A} {dec:EqDec A eq}
               (substlist:list (A×A)) (inp:A)
      := match lookup equiv_dec substlist inp with
         | Some x ⇒ x
         | None ⇒ inp
         end.

  End substlist.

  Section conv.

    Definition ascii_mk_lower_substtable
      := [("A", "a");("B", "b");("C", "c");("D", "d");("E", "e")
          ;("F", "f");("G", "g");("H", "h");("I", "i");("J", "j")
          ;("K", "k");("L", "l");("M", "m");("N", "n");("O", "o")
          ;("P", "p");("Q", "q");("R", "r");("S", "s");("T", "t")
          ;("U", "u");("V", "v");("W", "w");("X", "x");("Y", "y")
          ;("Z", "z")]%char.

    Definition ascii_mk_lower (c:ascii) : ascii
      := substlist_subst ascii_mk_lower_substtable c.

    Definition mk_lower (s:string) : string
      := map_string ascii_mk_lower s.

  End conv.

End RAssoc.