Record Tuple : Set := mkTuple {k : K; v : V}.Record Tuple : Set := mkTuple {k : K; v : V}.Record Tuple : Set := mkTuple {k : K; v : V}.Record Tuple : Set := mkTuple {k : K; v : V}.(**************************************************)
(* Definitions                                    *)
(**************************************************)



Definition assoc := list Tuple.(* <Warning> : Syntax is discontinued *) 


Definition assoc_empty := nil (A:=Tuple).(* search function : locate a value by its key *)
Fixpoint assoc_find (l : assoc) : K -> option V :=
  fun k0 : K =>
  match l with
  | nil => none V
  | mkTuple k v :: l' =>
      match Keq_dec k k0 with
      | left _ => some V v
      | right _ => assoc_find l' k0
      end
  end.(* function to add an entry in an array:  may replace an existing entry
  if the key is already present in the array *)
Fixpoint assoc_add (l : assoc) : K -> V -> assoc :=
  fun (k0 : K) (v0 : V) =>
  match l with
  | nil => mkTuple k0 v0 :: nil
  | mkTuple k v :: l' =>
      match Keq_dec k k0 with
      | left _ => mkTuple k0 v0 :: l'
      | _ => mkTuple k v :: assoc_add l' k0 v0
      end
  end.(* remove an entry from an array or do nothing if the key isn't
    present in the array *) 
Fixpoint assoc_delete (l : assoc) : K -> assoc :=
  fun k0 : K =>
  match l with
  | nil => nil (A:=Tuple)
  | mkTuple k v :: l' =>
      match Keq_dec k k0 with
      | left _ => assoc_delete l' k0
      | _ => mkTuple k v :: assoc_delete l' k0
      end
  end.(* tests the existence of a key in an array *)
Definition assoc_mem (l : assoc) (k : K) : Prop :=
  match assoc_find l k with
  | some _ => True
  | _ => False
  end.(* tests the existence of the specified tuple in an array *)
Definition assoc_hasmem (l : assoc) (k : K) (v : V) : Prop :=
  match assoc_find l k with
  | some v' => v = v'
  | _ => False
  end.(* definition of equal functions from keys to values option *)
Definition assoc_eqm (f1 f2 : K -> option V) := forall k : K, f1 k = f2 k.(* definition of almost-everywhere-equal functions from keys 
  to values option *)
Definition assoc_almost_eqm (k0 : K) (f1 f2 : K -> option V) :=
  forall k : K, k <> k0 -> f1 k = f2 k.

(* Specifications: *)
Lemma assoc_almost_eqm_trans : forall (k : K) (f1 f2 f3 : K -> option V), assoc_almost_eqm k f1 f2 -> assoc_almost_eqm k f2 f3 -> assoc_almost_eqm k f1 f3.
Lemma assoc_almost_eqm_sym : forall (k : K) (f1 f2 : K -> option V), assoc_almost_eqm k f1 f2 -> assoc_almost_eqm k f2 f1.
Lemma assoc_eqm_trans : forall f1 f2 f3 : K -> option V, assoc_eqm f1 f2 -> assoc_eqm f2 f3 -> assoc_eqm f1 f3.
Lemma assoc_semfind_nil : assoc_eqm (assoc_find assoc_empty) (fun k : K => none V).
Lemma assoc_semfind_cons_1 : forall (k : K) (v : V) (l : assoc), assoc_almost_eqm k (assoc_find (mkTuple k v :: l)) (assoc_find l).
Lemma assoc_semfind_cons_2 : forall (k : K) (v : V) (l : assoc), assoc_find (mkTuple k v :: l) k = some V v.
Lemma assoc_semfind_change_valeur : forall (k : K) (v v' : V) (l : assoc), assoc_almost_eqm k (assoc_find (mkTuple k v :: l)) (assoc_find (mkTuple k v' :: l)).
Lemma assoc_semfind_increase_1 : forall (a : Tuple) (l l' : assoc), assoc_eqm (assoc_find l) (assoc_find l') -> assoc_eqm (assoc_find (a :: l)) (assoc_find (a :: l')).
Lemma assoc_semfind_increase_2 : forall (k : K) (a : Tuple) (l l' : assoc), assoc_almost_eqm k (assoc_find l) (assoc_find l') -> assoc_almost_eqm k (assoc_find (a :: l)) (assoc_find (a :: l')).
Lemma assoc_semfind_commute : forall (k0 k1 : K) (v0 v1 : V) (l : assoc), k0 <> k1 -> assoc_eqm (assoc_find (mkTuple k1 v1 :: mkTuple k0 v0 :: l)) (assoc_find (mkTuple k0 v0 :: mkTuple k1 v1 :: l)).
Lemma assoc_hasmem_find : forall (l : assoc) (k : K) (v : V), assoc_hasmem l k v -> assoc_find l k = some V v.
Lemma assoc_find_hasmem : forall (l : assoc) (k : K) (v : V), assoc_find l k = some V v -> assoc_hasmem l k v.
Lemma assoc_find_none_hasmem : forall (l : assoc) (k : K) (v : V), assoc_find l k = none V -> forall v : V, ~ assoc_hasmem l k v.
Lemma assoc_find_mem : forall (l : assoc) (k : K) (v : V), assoc_find l k = some V v -> assoc_mem l k.
Lemma assoc_hasmem_mem : forall (l : assoc) (k : K) (v : V), assoc_hasmem l k v -> assoc_mem l k.
Lemma assoc_mem_hasmem : forall (l : assoc) (k : K), assoc_mem l k -> exists v : V, assoc_hasmem l k v.
Lemma assoc_add_egale_cons : forall (t : assoc) (k : K) (v : V), assoc_eqm (assoc_find (mkTuple k v :: t)) (assoc_find (assoc_add t k v)).
Lemma assoc_add_correct_1 : forall (k : K) (v : V) (t : assoc), assoc_almost_eqm k (assoc_find (assoc_add t k v)) (assoc_find t).
Lemma assoc_add_correct_2 : forall (k : K) (v : V) (t : assoc), assoc_find (assoc_add t k v) k = some V v.
Lemma assoc_add_correct_3 : forall (k : K) (v : V) (t : assoc), assoc_hasmem (assoc_add t k v) k v.
Lemma assoc_add_correct_4 : forall (k : K) (v : V) (t : assoc), assoc_mem (assoc_add t k v) k.
Lemma assoc_del_correct_1 : forall (l : assoc) (k : K), assoc_find (assoc_delete l k) k = none V.
Lemma assoc_del_correct_2 : forall (l : assoc) (k : K) (v : V), ~ assoc_hasmem (assoc_delete l k) k v.
Lemma assoc_del_correct_3 : forall (l : assoc) (k : K), ~ assoc_mem (assoc_delete l k) k.
Lemma assoc_semfind_del : forall (l : assoc) (k : K), assoc_almost_eqm k (assoc_find l) (assoc_find (assoc_delete l k)).
Lemma assoc_del_decrease_1 : forall (l : assoc) (k k' : K), assoc_find l k = none V -> assoc_find (assoc_delete l k') k = none V.
Lemma assoc_del_decrease_2 : forall (l : assoc) (k k' : K) (v : V), assoc_find (assoc_delete l k') k = some V v -> assoc_find l k = some V v.
Lemma assoc_del_decrease_3 : forall (l : assoc) (k k' : K) (v v' : V), assoc_find l k = some V v -> assoc_find (assoc_delete l k') k = some V v' -> v = v'.
Lemma assoc_del_correct_4 : forall (l : assoc) (k k' : K) (v : V), ~ assoc_hasmem l k v -> ~ assoc_hasmem (assoc_delete l k') k v.
Lemma assoc_del_correct_5 : forall (l : assoc) (k k' : K), ~ assoc_mem l k -> ~ assoc_mem (assoc_delete l k') k.
Lemma assoc_mem_dec : forall (l : assoc) (k : K), {assoc_mem l k} + {~ assoc_mem l k}.
Lemma assoc_hasmem_dec : forall (Veq_dec : forall x y : V, {x = y} + {x <> y}) (l : assoc) (k : K) (v : V), {assoc_hasmem l k v} + {~ assoc_hasmem l k v}.
Lemma assoc_hasmem_ex_dec : forall (Veq_dec : forall x y : V, {x = y} + {x <> y}) (l : assoc) (k : K) (v : V), {(exists v : V, assoc_hasmem l k v)} + {~ (exists v : V, assoc_hasmem l k v)}.
Lemma assoc_add_mem_choice : forall (b0 b : assoc) (k k0 : K) (v0 : V), b = assoc_add b0 k0 v0 -> assoc_mem b k -> assoc_mem b0 k \/ k = k0.
Lemma assoc_add_hasmem_choice : forall (b0 b : assoc) (k k0 : K) (v v0 : V), b = assoc_add b0 k0 v0 -> assoc_hasmem b k v -> assoc_hasmem b0 k v \/ k = k0 /\ v = v0.
Lemma assoc_add_mem_invar : forall (l l' : assoc) (k k' : K) (v : V), l' = assoc_add l k' v -> k' <> k -> assoc_mem l k -> assoc_mem l' k.
Lemma assoc_add_mem_invar_contrap : forall (l l' : assoc) (k k' : K) (v : V), l' = assoc_add l k' v -> k' <> k -> assoc_mem l' k -> assoc_mem l k.
Lemma assoc_add_not_mem_invar : forall (l l' : assoc) (k k' : K) (v' : V), l' = assoc_add l k' v' -> k' <> k -> ~ assoc_mem l k -> ~ assoc_mem l' k.
Lemma assoc_add_not_mem_invar_contrap : forall (l l' : assoc) (k k' : K) (v' : V), l' = assoc_add l k' v' -> k' <> k -> ~ assoc_mem l' k -> ~ assoc_mem l k.
Lemma assoc_add_hasmem_invar : forall (l l' : assoc) (k k' : K) (v v' : V), l' = assoc_add l k' v' -> k' <> k -> assoc_hasmem l k v -> assoc_hasmem l' k v.
Lemma assoc_add_hasmem_invar_contrap : forall (l l' : assoc) (k k' : K) (v v' : V), l' = assoc_add l k' v' -> k' <> k -> assoc_hasmem l' k v -> assoc_hasmem l k v.
Lemma assoc_add_not_hasmem_invar : forall (l l' : assoc) (k k' : K) (v v' : V), l' = assoc_add l k' v' -> k' <> k -> ~ assoc_hasmem l k v -> ~ assoc_hasmem l' k v.
Lemma assoc_add_not_hasmem_invar_contrap : forall (l l' : assoc) (k k' : K) (v v' : V), l' = assoc_add l k' v' -> k' <> k -> ~ assoc_hasmem l' k v -> ~ assoc_hasmem l k v.
Lemma assoc_del_mem_invar : forall (l l' : assoc) (k k' : K), l' = assoc_delete l k' -> k' <> k -> assoc_mem l k -> assoc_mem l' k.
Lemma assoc_del_mem_invar_contrap : forall (l l' : assoc) (k k' : K), l' = assoc_delete l k' -> k' <> k -> assoc_mem l' k -> assoc_mem l k.
Lemma assoc_del_not_mem_invar : forall (l l' : assoc) (k k' : K), l' = assoc_delete l k' -> k' <> k -> ~ assoc_mem l k -> ~ assoc_mem l' k.
Lemma assoc_del_not_mem_invar_contrap : forall (l l' : assoc) (k k' : K), l' = assoc_delete l k' -> k' <> k -> ~ assoc_mem l' k -> ~ assoc_mem l k.
Lemma assoc_del_hasmem_invar : forall (l l' : assoc) (k k' : K) (v : V), l' = assoc_delete l k' -> k' <> k -> assoc_hasmem l k v -> assoc_hasmem l' k v.
Lemma assoc_del_hasmem_invar_contrap : forall (l l' : assoc) (k k' : K) (v : V), l' = assoc_delete l k' -> k' <> k -> assoc_hasmem l' k v -> assoc_hasmem l k v.
Lemma assoc_del_not_hasmem_invar : forall (l l' : assoc) (k k' : K) (v : V), l' = assoc_delete l k' -> k' <> k -> ~ assoc_hasmem l k v -> ~ assoc_hasmem l' k v.
Lemma assoc_del_not_hasmem_invar_contrap : forall (l l' : assoc) (k k' : K) (v : V), l' = assoc_delete l k' -> k' <> k -> ~ assoc_hasmem l' k v -> ~ assoc_hasmem l k v.
Lemma assoc_unique_key : forall (l : assoc) (k : K) (v v' : V), assoc_hasmem l k v -> assoc_hasmem l k v' -> v' = v.
Lemma assoc_add_find_effect : forall (l0 l1 : assoc) (k k' : K) (v v' : V), none V = assoc_find l0 k -> some V v = assoc_find l1 k -> l1 = assoc_add l0 k' v' -> k' = k /\ v' = v.
Lemma assoc_add_mem_effect : forall (l0 l1 : assoc) (k k' : K) (v : V), ~ assoc_mem l0 k -> assoc_mem l1 k -> l1 = assoc_add l0 k' v -> k' = k.
Lemma assoc_add_hasmem_effect : forall (l0 l1 : assoc) (k k' : K) (v v' : V), ~ assoc_hasmem l0 k v -> assoc_hasmem l1 k v -> l1 = assoc_add l0 k' v' -> k' = k /\ v' = v.
Lemma assoc_del_mem_effect : forall (l : assoc) (k k' : K), assoc_mem l k -> ~ assoc_mem (assoc_delete l k') k -> k' = k.
Lemma assoc_del_hasmem_effect : forall (l : assoc) (k k' : K) (v v' : V), assoc_hasmem l k v -> ~ assoc_hasmem (assoc_delete l k') k v -> k' = k.