Section Invariants.
Instance unit_PCM : Ghost := { valid a := True; Join_G a b c := True }.
Inductive list_join {P : Ghost} : Join (list (option G)) :=
| list_join_nil_l m: list_join nil m m
| list_join_nil_r m: list_join m nil m
| list_join_cons a1 a2 m1 m2 a3 m3: join a1 a2 a3 -> list_join m1 m2 m3 ->
list_join (a1 :: m1) (a2 :: m2) (a3 :: m3).
Existing Instance list_join.
Instance list_PCM (P : Ghost) : Ghost := { valid a := True; Join_G := list_join }.
Instance list_order A : @PCM_order (list_PCM (discrete_PCM A)) list_incl.
Instance set_PCM A : Ghost := { valid := fun _ : Ensemble A => True;
Join_G a b c := Disjoint a b /\ c = Union a b }.
Definition iname := nat.
Class invG := { g_inv : gname; g_en : gname; g_dis : gname }.
Context {inv_names : invG}.
Definition master_list {A} g (l : list (option A)) := ghost_master1(ORD := list_order A) l g.
(* up *)
Instance Inhabitant_option {A} : Inhabitant (option A) := None.
(* Our ghost state construction makes it awkward to put agree inside other ghost state constructions. As a workaround, instead of having one ghost location with a map from indices to agrees, we have a map from indices to ghost locations, each with an agree. *)
Instance token_PCM : Ghost := exclusive_PCM unit.
Definition wsat : mpred := EX I : list mpred, EX lg : list gname, EX lb : list (option bool),
!!(length lg = length I /\ length lb = length I) &&
master_list g_inv (map (fun i => match Znth i lb with Some _ => Some (Znth i lg)
| None => None end) (upto (length I))) *
ghost_list g_dis (map (fun o => match o with Some true => Some (Some tt) | _ => None end) lb) *
ghost_set g_en (fun i : iname => nth i lb None = Some false) *
iter_sepcon (fun i => match Znth i lb with
| Some true => agree (Znth i lg) (Znth i I) * |> Znth i I
| Some false => agree (Znth i lg) (Znth i I)
| _ => emp end) (upto (length I)).
(* This is what's called ownI in Iris; we could build another layer with namespaces. *)
Definition invariant (i : iname) P : mpred := EX g : gname,
ghost_snap(ORD := list_order _) (list_singleton i g) g_inv * agree g P.

Lemma list_join_singleton_inv : forall {P : Ghost} n a b l,
list_join (list_singleton n a) (list_singleton n b) l ->
exists c, join a b c /\ l = list_singleton n c.