Definition upd {A} (m : nat -> A) x e :=
fun y => if eq_nat_dec x y then e else m y.
Definition updatemap (m : map) (x e : nat) : option map :=
match m x with Some _ => Some (upd m x (Some e)) | None => None end.
Definition assertmap (m : map) (x : nat) : Prop :=
match m x with Some (S _) => True | _ => False end.
Definition joincell (a b : option nat) : option (option nat) :=
match a, b with
| None, None => Some None
| Some a, None | None, Some a => Some (Some a)
| Some _, Some _ => None
end.
Definition join (m n o : map) : Prop := forall x, joincell (m x) (n x) = Some (o x).
Definition joins (m n : map) : Prop := exists o, join m n o.
Add Parametric Morphism : join with signature eqmap ==> eqmap ==> eqmap ==> iff as join_morphism.

(* Specifications: *)
Lemma join_eqmap_compat_l {m m' n o}  : eqmap m m' -> join m n o -> join m' n o.
Lemma join_eqmap_compat_r {m n n' o}  : eqmap n n' -> join m n o -> join m n' o.
Lemma join_eqmap {m n o o'}  : join m n o -> join m n o' -> eqmap o o'.
Lemma join_eqmap_r {m n n' o}  : join m n o -> join m n' o -> eqmap n n'.
Lemma join_eqmap_l {m m' n o}  : join m n o -> join m' n o -> eqmap m m'.
Definition joincell_split {a b ab c abc} :
joincell a b = Some ab -> joincell ab c = Some abc ->
{ bc | joincell b c = Some bc /\ joincell a bc = Some abc }.
Lemma join_emptymap_l a : join emptymap a a.
Lemma join_emptymap_r a : join a emptymap a.
Lemma joins_emptymap_l a : joins emptymap a.
Lemma joins_emptymap_r a : joins a emptymap.
Lemma join_comm a b c : join a b c -> join b a c.
Lemma joins_sym a b : joins a b -> joins b a.
Hint Resolve
join_emptymap_l
join_emptymap_r
joins_emptymap_l
joins_emptymap_r
join_comm
joins_sym.
Lemma joins_pointwise m n : joins m n <-> (forall x, joincell (m x) (n x) <> None).
Lemma join_joins_distrib a b ab : join a b ab -> forall c, joins ab c -> joins a c /\ joins b c.
Lemma join_joins_distrib' a b ab : join a b ab -> forall c, joins a c -> joins b c -> joins ab c.
Definition empty (m : map) : Prop := forall x, m x = None.
Lemma join_empty m n : empty n -> join m n m.
Definition nonempty (m : map) : Prop := exists x, m x <> None.
Lemma eqmap_joins m1 m2 : joins m1 m2 -> eqmap m1 m2 -> empty m1 /\ empty m2.
Definition pred := map -> Prop.
Lemma join_eqmap_compat_l {m m' n o}  : eqmap m m' -> join m n o -> join m' n o.
Lemma join_eqmap_compat_r {m n n' o}  : eqmap n n' -> join m n o -> join m n' o.
Lemma join_eqmap {m n o o'}  : join m n o -> join m n o' -> eqmap o o'.
Lemma join_eqmap_r {m n n' o}  : join m n o -> join m n' o -> eqmap n n'.
Lemma join_eqmap_l {m m' n o}  : join m n o -> join m' n o -> eqmap m m'.
Definition joincell_split {a b ab c abc} :
joincell a b = Some ab -> joincell ab c = Some abc ->
{ bc | joincell b c = Some bc /\ joincell a bc = Some abc }.
Lemma join_emptymap_l a : join emptymap a a.
Lemma join_emptymap_r a : join a emptymap a.
Lemma joins_emptymap_l a : joins emptymap a.
Lemma joins_emptymap_r a : joins a emptymap.
Lemma join_comm a b c : join a b c -> join b a c.
Lemma joins_sym a b : joins a b -> joins b a.
Hint Resolve
join_emptymap_l
join_emptymap_r
joins_emptymap_l
joins_emptymap_r
join_comm
joins_sym.
Lemma joins_pointwise m n : joins m n <-> (forall x, joincell (m x) (n x) <> None).
Lemma join_joins_distrib a b ab : join a b ab -> forall c, joins ab c -> joins a c /\ joins b c.
Lemma join_joins_distrib' a b ab : join a b ab -> forall c, joins a c -> joins b c -> joins ab c.
Definition empty (m : map) : Prop := forall x, m x = None.
Lemma join_empty m n : empty n -> join m n m.
Definition nonempty (m : map) : Prop := exists x, m x <> None.
Lemma eqmap_joins m1 m2 : joins m1 m2 -> eqmap m1 m2 -> empty m1 /\ empty m2.
Definition pred := map -> Prop.