(* QuickChick false_beq_id. *)

(* Maps as functions are bad, explicit maps instead *)

Definition partial_map := list (id * nat).Definition empty : partial_map := nil.Definition update := @cons (id * nat).Inductive bind : partial_map -> id -> nat -> Prop :=
  | BindNow   : forall x a m, bind (cons (x, a) m) x a
  | BindLater : forall x x' a a' m',
                  ~ (x = x') ->
                  bind m' x a -> 
                  bind (cons (x',a') m') x a.Inductive bind : partial_map -> id -> nat -> Prop :=
  | BindNow   : forall x a m, bind (cons (x, a) m) x a
  | BindLater : forall x x' a a' m',
                  ~ (x = x') ->
                  bind m' x a -> 
                  bind (cons (x',a') m') x a.Inductive bind : partial_map -> id -> nat -> Prop :=
  | BindNow   : forall x a m, bind (cons (x, a) m) x a
  | BindLater : forall x x' a a' m',
                  ~ (x = x') ->
                  bind m' x a -> 
                  bind (cons (x',a') m') x a.(* KNOWN DUG. The derivation of SizedProofEqs for bind fails. *)
(* Derive SizedProofEqs for (fun x => bind m x a). *)
(* Derive GenSizedSuchThatCorrect for (fun x => bind m x a). *)

Instance adm_st m a : SuchThatCorrect (fun x => bind m x a) (genST (fun x => bind m x a)).Instance checkFalse : Checkable False := {| checker := fun _ => checker false |}.Instance bind_dec m x v : Dec (bind m x v) :=
  {| dec := _ |}.(* TODO: Correct equivalence of maps *)
Definition equiv_map m1 m2 :=
  forall x v , bind m1 x v <-> bind m2 x v.Conjecture apply_empty : forall x a, ~ (bind empty x a).(* QuickChick apply_empty. *)
(* Gave Up! - QuickChick apply_empty_unfolded. *)

Conjecture update_eq : forall (m: partial_map) x v,
    bind (update (x,v) m) x v.

(* Specifications: *)
Theorem update_neq : forall v x1 x2 (m : partial_map), x2 <> x1 -> forall v' v'', bind (cons (x2, v) m) x1 v' -> bind m x1 v'' -> v' = v''.
Lemma update_shadow : forall (m: partial_map) v1 v2 x, update (x, v2) (update (x, v1) m) = update (x, v2) m.
Theorem update_same : forall v x (m : partial_map), bind m x v -> update (x, v) m = m.
Theorem update_permute : forall v1 v2 x1 x2 (m : partial_map), x2 <> x1 -> (update (x1,v1) (update (x2,v2) m)) = (update (x2,v2) (update (x1,v1) m)).