Section FancyUpdates.
Context {inv_names : invG}.
Definition fupd (E1 E2 : Ensemble iname) P :=
(wsat * ghost_set g_en E1) -* |==> except0 (wsat * ghost_set g_en E2 * P).
Notation "|={ E1 , E2 }=> P" := (fupd E1 E2 P) (at level 62): logic.
Notation "|={ E }=> P" := (fupd E E P) (at level 62): logic.

(* Specifications: *)
Lemma fupd_mono : forall E1 E2 P Q, P |-- Q -> |={E1, E2}=> P |-- |={E1, E2}=> Q.
Lemma bupd_fupd : forall E P, |==> P |-- |={E}=> P.
Lemma fupd_frame_r : forall E1 E2 P Q, (|={E1,E2}=> P) * Q |-- |={E1,E2}=> (P * Q).
Lemma fupd_intro_mask : forall E1 E2 P (Hdec : forall a, In E2 a \/ ~In E2 a),
Included E2 E1 -> P |-- |={E1,E2}=> |={E2,E1}=> P.
Lemma fupd_trans : forall E1 E2 E3 P, (|={E1,E2}=> |={E2,E3}=> P) |-- |={E1,E3}=> P.
Lemma fupd_timeless : forall E P, timeless P -> |> P |-- |={E}=> P.
Lemma fupd_frame_l : forall E1 E2 P Q, P * (|={E1,E2}=> Q) |-- |={E1,E2}=> (P * Q).
(* This is a generally useful pattern. *)
Lemma fupd_mono' : forall E1 E2 P Q (a : rmap) (Himp : (P >=> Q) (level a)),
app_pred (fupd E1 E2 P) a -> app_pred (fupd E1 E2 Q) a.
Lemma fupd_bupd : forall E1 E2 P Q, P |-- |==> (|={E1,E2}=> Q) -> P |-- |={E1,E2}=> Q.
Lemma fupd_bupd_elim : forall E1 E2 P Q, P |-- |={E1,E2}=> Q -> |==> P |-- |={E1,E2}=> Q.
Lemma fupd_intro : forall E P, P |-- |={E}=> P.
Lemma fupd_timeless' : forall E1 E2 P Q, timeless P -> P |-- |={E1,E2}=> Q ->
|> P |-- |={E1,E2}=> Q.
Lemma fupd_except0_elim : forall E1 E2 P Q, P |-- |={E1,E2}=> Q -> except0 P |-- |={E1,E2}=> Q.
Lemma wsat_fupd_elim : forall P, wsat * (|={Empty_set _,Empty_set _}=> P) |-- |==> except0 (wsat * P).
Lemma fupd_prop' : forall E1 E2 E2' P Q, Included E1 E2 -> (forall a, In E1 a \/ ~ In E1 a) ->
Q |-- |={E1,E2'}=> !!P ->
|={E1, E2}=> Q |-- |={E1}=> !!P && (|={E1, E2}=> Q).
Lemma fupd_prop : forall E1 E2 P Q, Included E1 E2 -> (forall a, In E1 a \/ ~ In E1 a) ->
Q |-- !!P ->
|={E1, E2}=> Q |-- |={E1}=> !!P && (|={E1, E2}=> Q).
Lemma inv_alloc : forall E P, |> P |-- |={E}=> EX i : _, invariant i P.
Lemma make_inv : forall E P Q, P |-- Q -> P |-- |={E}=> EX i : _, invariant i Q.
Lemma inv_close_aux : forall E (i : iname) P,
ghost_list(P := token_PCM) g_dis (list_singleton i (Some tt)) * invariant i P * |> P *
(wsat * ghost_set g_en (Subtract E i))
|-- |==> except0 (wsat * (ghost_set g_en (Singleton i) * ghost_set g_en (Subtract E i))).
Lemma inv_open : forall E i P, In E i ->
invariant i P |-- |={E, Subtract E i}=> (|> P) * (|>P -* |={Subtract E i, E}=> emp).
(* these last two are probably redundant *)
Lemma inv_close : forall E i P, In E i ->
invariant i P * |> P * ghost_list(P := exclusive_PCM _) g_dis (list_singleton i (Some tt)) |--
|={Subtract E i, E}=> TT.
Lemma inv_access : forall E i P, In E i ->
invariant i P |-- |={E, Subtract E i}=> |> P * (|> P -* |={Subtract E i, E}=> TT).