(****************)
(* main methods *)
(****************)
Definition def h := if h is Def _ _ then true else false.
Definition empty := @Def (finmap.nil _ _) is_true_true.
Definition upd h x d := nosimpl
(if h is Def hs ns then
if decP (@idP (x != null)) is left pf then
Def (@upd_nullP _ _ d pf ns)
else Undef
else Undef).
Definition dom h : pred ptr := nosimpl
(if h is Def f _ then mem (supp f) else pred0).
Definition free x h : heap :=
(if h is Def hs ns then Def (free_nullP x ns) else Undef).
Definition look (x : ptr) h :=
(if h is Def hs _ then
if fnd x hs is Some d then d else dyn tt
else dyn tt).
Definition union2 h1 h2 := nosimpl
(if (h1, h2) is (Def hs1 ns1, Def hs2 ns2) then
if disj hs1 hs2 then
Def (@un_nullP _ _ ns1 ns2)
else Undef
else Undef).
Definition empb h :=
if h is Def hs _ then supp hs == [::] else false.
Definition fresh h :=
(if h is Def hs _ then last null (supp hs) else null) .+ 1.
Definition subdom h1 h2 :=
if (h1, h2) is (Def hs1 _, Def hs2 _) then
all (fun x => x \in supp hs2) (supp hs1)
else false.
Definition subheap h1 h2 :=
subdom h1 h2 /\ forall x, x \in dom h1 -> look x h1 = look x h2.
(* Definition subheap h1 h2 p :=  *)
(*   if (h1, h2) is (Def hs1 _, Def hs2 _) then  *)
(*     all (fun x => p (look x h1) (look x h2)) (supp hs1) *)
(*   else false. *)
Definition subtract h1 h2 :=
if h1 is (Def hs1 _) then
foldl (fun h x => free x h) h2 (supp hs1)
else Undef.
Definition pick h :=
if h is Def hs _ then head null (supp hs) else null.
Definition pts A (x : ptr) (v : A) := upd empty x (dyn v).
Notation "h1 :+ h2" := (union2 h1 h2) (at level 43, left associativity).
Notation "h2 :- h1" := (subtract h1 h2) (at level 43, left associativity).
Notation "x :-> v" := (pts x v) (at level 30).
(***********************)
(* monoidal properties *)
(***********************)

(* Specifications: *)
Lemma unC : forall h1 h2, h1 :+ h2 = h2 :+ h1.
Lemma unA : forall h1 h2 h3, h1 :+ (h2 :+ h3) = h1 :+ h2 :+ h3.
Lemma unCA h1 h2 h3 : h1 :+ (h2 :+ h3) = h2 :+ (h1 :+ h3).
Lemma unhKl h h1 h2 : def (h :+ h1) -> h :+ h1 = h :+ h2 -> h1 = h2.
Lemma domPt A x (v : A) : dom (x :-> v) =i [pred y | (x == y) && (x != null)].
Lemma domF h x :
dom (free x h) =i [pred y | if x == y then false else y \in dom h].
Lemma domUn h1 h2 :
dom (h1 :+ h2) =i
[pred x | def (h1 :+ h2) && (x \in [predU dom h1 & dom h2])].
Lemma dom_null h x : x \in dom h -> x != null.
(*******)
(* def *)
(*******)
Lemma def0 : def empty.
Lemma defPt A x (v : A) : def (x :-> v) = (x != null).
Lemma defUnl h1 h2 : def (h1 :+ h2) -> def h1.
Lemma defUnF h1 h2 x : def (h1 :+ h2) -> def (h1 :+ free x h2).
Lemma heap_eta h x : x \in dom h -> h = upd (free x h) x (look x h).
Lemma updU h x y d1 d2 :
upd (upd h x d1) y d2 =
if x == y then upd h x d2 else upd (upd h y d2) x d1.
Lemma updF h x y d :
upd (free x h) y d =
if x == y then upd h x d else free x (upd h y d).
Lemma updUnl h1 h2 x d :
upd (h1 :+ h2) x d =
if x \in dom h1 then upd h1 x d :+ h2 else h1 :+ upd h2 x d.
Lemma updUnr h1 h2 x d :
upd (h1 :+ h2) x d =
if x \in dom h2 then h1 :+ upd h2 x d else upd h1 x d :+ h2.
Lemma pts_injT A1 A2 x (v1 : A1) (v2 : A2) :
def (x :-> v1) -> x :-> v1 = x :-> v2 -> A1 = A2.