Commit f4246d3a authored by Ralf Jung's avatar Ralf Jung

Merge branch 'amin/spanning' into 'master'

Add the spanning tree algorithm.

Closes #3

See merge request FP/iris-examples!3
parents c3a8a2a3 9542b86d
Pipeline #5940 passed with stage
in 5 minutes and 30 seconds
...@@ -44,6 +44,8 @@ This repository contains the following case studies: ...@@ -44,6 +44,8 @@ This repository contains the following case studies:
* Binary logical relations for proving contextual refinements * Binary logical relations for proving contextual refinements
- Proof of refinement for a pair of fine-grained/coarse-grained concurrent counter implementations - Proof of refinement for a pair of fine-grained/coarse-grained concurrent counter implementations
- Proof of refinement for a pair of fine-grained/coarse-grained concurrent stack implementations - Proof of refinement for a pair of fine-grained/coarse-grained concurrent stack implementations
* [spanning-tree](theories/spanning_tree): Proof of partial functional
correctness of a concurrent spanning tree algorithm.
## For Developers: How to update the Iris dependency ## For Developers: How to update the Iris dependency
......
...@@ -48,3 +48,8 @@ theories/logrel/F_mu_ref_conc/examples/stack/stack_rules.v ...@@ -48,3 +48,8 @@ theories/logrel/F_mu_ref_conc/examples/stack/stack_rules.v
theories/logrel/F_mu_ref_conc/examples/stack/CG_stack.v theories/logrel/F_mu_ref_conc/examples/stack/CG_stack.v
theories/logrel/F_mu_ref_conc/examples/stack/FG_stack.v theories/logrel/F_mu_ref_conc/examples/stack/FG_stack.v
theories/logrel/F_mu_ref_conc/examples/stack/refinement.v theories/logrel/F_mu_ref_conc/examples/stack/refinement.v
theories/spanning_tree/graph.v
theories/spanning_tree/mon.v
theories/spanning_tree/spanning.v
theories/spanning_tree/proof.v
From iris.algebra Require Import base gmap.
From stdpp Require Import gmap mapset.
Section Graphs.
Context {T : Type} {HD : EqDecision T} {HC : @Countable T HD}.
Definition graph := gmap T (option T * option T).
Identity Coercion graph_to_gmap : graph >-> gmap.
Definition get_left (g : graph) x : option T := g !! x = fst.
Definition get_right (g : graph) x : option T := g !! x = snd.
Definition strict_sub_child (ch ch' : option T) :=
match ch, ch' with
| Some c, Some c' => c = c'
| Some c, None => True
| None, Some _ => False
| None, None => True
end.
Definition strict_sub_children (ch ch' : option T * option T) : Prop :=
strict_sub_child (ch.1) (ch'.1) strict_sub_child (ch.2) (ch'.2).
Definition strict_subgraph (g g' : graph) : Prop :=
x, strict_sub_children (get_left g x, get_right g x)
(get_left g' x, get_right g' x).
(* A path is a list of booleans true for left child and false for the right *)
(* The empty list is the identity trace (from x to x). *)
Definition path := list bool.
Identity Coercion path_to_list : path >-> list.
Inductive valid_path (g : graph) (x y : T) : path Prop :=
| valid_path_E : x dom (gset _) g x = y valid_path g x y []
| valid_path_l (xl : T) p : get_left g x = Some xl valid_path g xl y p
valid_path g x y (true :: p)
| valid_path_r (xr : T) p : get_right g x = Some xr valid_path g xr y p
valid_path g x y (false :: p).
Definition connected (g : graph) (x : T) :=
z, z dom (gset _) g p, valid_path g x z p.
Definition front (g : graph) (t t' : gset T) := t dom (gset _) g
x v, x t (get_left g x = Some v) (get_right g x = Some v)
v t'.
Definition maximal (g : graph) := front g (dom (gset _) g) (dom (gset _) g).
Definition tree (g : graph) (x : T) :=
z, z dom (gset _) g exists !p, valid_path g x z p.
(* graph facts *)
Lemma front_t_t_dom g z t :
z t connected g z front g t t t = dom (gset _) g.
Proof.
intros Hz Hc [Hsb Hdt].
apply collection_equiv_spec_L; split; trivial.
apply elem_of_subseteq => x Hx. destruct (Hc x Hx) as [p pv].
clear Hc Hx; revert z Hz pv.
induction p => z Hz pv.
- by inversion pv; subst.
- inversion pv as [|? ? Hpv1 Hpv2 Hpv3|? ? Hpv1 Hpv2 Hpv3]; subst.
+ eapply IHp; [eapply Hdt|apply Hpv2]; eauto.
+ eapply IHp; [eapply Hdt|apply Hpv2]; eauto.
Qed.
Lemma front_mono g t t' s : front g t t' t' s front g t s.
Proof. intros [Htd Hf] Hts; split; eauto. Qed.
Lemma front_empty g : front g .
Proof. split; auto. intros ? Hcn; inversion Hcn. Qed.
Lemma strict_sub_children_refl v : strict_sub_children v v.
Proof. by destruct v as [[] []]. Qed.
Lemma strict_sub_children_trans v1 v2 v3 : strict_sub_children v1 v2
strict_sub_children v2 v3 strict_sub_children v1 v3.
Proof.
destruct v1 as [[] []]; destruct v2 as [[] []];
destruct v3 as [[] []]; cbv; by intuition subst.
Qed.
Lemma strict_sub_children_None v : strict_sub_children v (None, None).
Proof. by destruct v as[[] []]. Qed.
Lemma strict_subgraph_empty g : strict_subgraph g .
Proof.
intros i.
rewrite /get_left /get_right /strict_sub_child lookup_empty //=.
by destruct (g !! i) as [[[] []]|].
Qed.
Lemma get_left_dom g x y : get_left g x = Some y x dom (gset _) g.
Proof.
rewrite /get_left elem_of_dom. case _ : (g !! x); inversion 1; eauto.
Qed.
Lemma get_right_dom g x y : get_right g x = Some y x dom (gset _) g.
Proof.
rewrite /get_right elem_of_dom. case _ : (g !! x); inversion 1; eauto.
Qed.
Lemma path_start g x y p : valid_path g x y p x dom (gset _) g.
Proof. inversion 1; subst; eauto using get_left_dom, get_right_dom. Qed.
Lemma path_end g x y p : valid_path g x y p y dom (gset _) g.
Proof. induction 1; subst; eauto. Qed.
End Graphs.
Arguments graph _ {_ _}.
\ No newline at end of file
From iris.heap_lang Require Export lifting notation.
From iris.algebra Require Import auth frac gset gmap excl.
From iris.base_logic Require Export invariants.
From iris.proofmode Require Import tactics.
Import uPred.
From iris.base_logic Require Import cancelable_invariants.
From stdpp Require Import gmap mapset.
From iris_examples.spanning_tree Require Import graph.
(* children cofe *)
Canonical Structure chlC := leibnizC (option loc * option loc).
(* The graph monoid. *)
Definition graphN : namespace := nroot .@ "SPT_graph".
Definition graphUR : ucmraT :=
optionUR (prodR fracR (gmapR loc (exclR chlC))).
(* The monoid for talking about which nodes are marked.
These markings are duplicatable. *)
Definition markingUR : ucmraT := gsetUR loc.
(** The CMRA we need. *)
Class graphG Σ := GraphG
{
graph_marking_inG :> inG Σ (authR markingUR);
graph_marking_name : gname;
graph_inG :> inG Σ (authR graphUR);
graph_name : gname
}.
(** The Functor we need. *)
(*Definition graphΣ : gFunctors := #[authΣ graphUR].*)
Section marking_definitions.
Context `{irisG heap_lang Σ, graphG Σ}.
Definition is_marked (l : loc) : iProp Σ :=
own graph_marking_name ( {[ l ]}).
Global Instance marked_persistentP x : Persistent (is_marked x).
Proof. apply _. Qed.
Lemma dup_marked l : is_marked l is_marked l is_marked l.
Proof. by rewrite /is_marked -own_op -auth_frag_op idemp_L. Qed.
Lemma new_marked {E} (m : markingUR) l :
own graph_marking_name ( m) ={E}=
own graph_marking_name ( (m ({[l]} : gset loc))) is_marked l.
Proof.
iIntros "H". rewrite -own_op (comm _ m).
iMod (@own_update with "H") as "Y"; eauto.
apply auth_update_alloc.
setoid_replace ({[l]} : gset loc) with (({[l]} : gset loc) ) at 2
by (by rewrite right_id).
apply op_local_update_discrete; auto.
Qed.
Lemma already_marked {E} (m : gset loc) l : l m
own graph_marking_name ( m) ={E}=
own graph_marking_name ( m) is_marked l.
Proof.
iIntros (Hl) "Hm". iMod (new_marked with "Hm") as "[H1 H2]"; iFrame.
rewrite gset_op_union (comm _ m) (subseteq_union_1_L {[l]} m); trivial.
by apply elem_of_subseteq_singleton.
Qed.
End marking_definitions.
(* The monoid representing graphs *)
Definition Gmon := gmapR loc (exclR chlC).
Definition excl_chlC_chl (ch : exclR chlC) : option (option loc * option loc) :=
match ch with
| Excl w => Some w
| Excl_Bot => None
end.
Definition Gmon_graph (G : Gmon) : graph loc := omap excl_chlC_chl G.
Definition Gmon_graph_dom (G : Gmon) :
G dom (gset loc) (Gmon_graph G) = dom (gset _) G.
Proof.
intros Hvl; apply mapset_eq => i. rewrite ?elem_of_dom lookup_omap.
specialize (Hvl i). split.
- revert Hvl; case _ : (G !! i) => [[]|] //=; eauto.
intros _ [? Hgi]; inversion Hgi.
- intros Hgi; revert Hgi Hvl. intros [[] Hgi]; rewrite Hgi; inversion 1; eauto.
Qed.
Definition child_to_val (c : option loc) : val :=
match c with
| None => NONEV
| Some l => SOMEV #l
end.
(* convert the data of a node to a value in the heap *)
Definition children_to_val (ch : option loc * option loc) : val :=
(child_to_val (ch.1), child_to_val (ch.2)).
Lemma children_to_val_is_val (c c' : option loc) :
to_val (child_to_val c, child_to_val c') =
Some (child_to_val c, child_to_val c')%V.
Proof. by destruct c; destruct c'. Qed.
Definition marked_graph := gmap loc (bool * (option loc * option loc)).
Identity Coercion marked_graph_gmap: marked_graph >-> gmap.
Definition of_graph_elem (G : Gmon) i v
: option (bool * (option loc * option loc)) :=
match Gmon_graph G !! i with
| Some w => Some (true, w)
| None => Some (false,v)
end.
Definition of_graph (g : graph loc) (G : Gmon) : marked_graph :=
map_imap (of_graph_elem G) g.
(* facts *)
Global Instance Gmon_graph_proper : Proper (() ==> (=)) Gmon_graph.
Proof. solve_proper. Qed.
Lemma new_Gmon_dom (G : Gmon) x w :
dom (gset loc) (G {[x := w]}) = dom (gset loc) G {[x]}.
Proof. by rewrite dom_op dom_singleton_L. Qed.
Definition of_graph_empty (g : graph loc) :
of_graph g = fmap (λ x, (false, x)) g.
Proof.
apply: map_eq => i.
rewrite lookup_imap /of_graph_elem lookup_fmap lookup_omap //.
Qed.
Lemma of_graph_dom_eq g G :
G dom (gset loc) g = dom (gset loc) (Gmon_graph G)
of_graph g G = fmap (λ x, (true, x) )(Gmon_graph G).
Proof.
intros HGvl. rewrite Gmon_graph_dom // => Hd. apply map_eq => i.
assert (Hd' : i dom (gset _) g i dom (gset _) G) by (by rewrite Hd).
revert Hd'; clear Hd. specialize (HGvl i); revert HGvl.
rewrite /of_graph /of_graph_elem /Gmon_graph lookup_imap lookup_fmap
lookup_omap ?elem_of_dom.
case _ : (g !! i); case _ : (G !! i) => [[]|] /=; inversion 1; eauto;
intros [? ?];
match goal with
H : _ @is_Some ?A None |- _ =>
assert (Hcn : @is_Some A None) by eauto;
destruct Hcn as [? Hcn]; inversion Hcn
end.
Qed.
Section definitions.
Context `{heapG Σ, graphG Σ}.
Definition own_graph (q : frac) (G : Gmon) : iProp Σ :=
own graph_name ( (Some (q, G) : graphUR)).
Global Instance own_graph_proper q : Proper (() ==> ()) (own_graph q).
Proof. solve_proper. Qed.
Definition heap_owns (M : marked_graph) (markings : gmap loc loc) : iProp Σ :=
([ map] l v M, (m : loc), markings !! l = Some m
l (#m, children_to_val (v.2)) m #(LitBool (v.1)))%I.
Definition graph_inv (g : graph loc) (markings : gmap loc loc) : iProp Σ :=
( (G : Gmon), own graph_name ( Some (1%Qp, G))
own graph_marking_name ( dom (gset _) G)
heap_owns (of_graph g G) markings strict_subgraph g (Gmon_graph G)
)%I.
Global Instance graph_inv_timeless g Mrk : Timeless (graph_inv g Mrk).
Proof. apply _. Qed.
Context `{cinvG Σ}.
Definition graph_ctx κ g Mrk : iProp Σ := cinv graphN κ (graph_inv g Mrk).
Global Instance graph_ctx_persistent κ g Mrk : Persistent (graph_ctx κ g Mrk).
Proof. apply _. Qed.
End definitions.
Notation "l [↦] v" := ({[l := Excl v]}) (at level 70, format "l [↦] v").
Typeclasses Opaque graph_ctx graph_inv own_graph.
Section graph_ctx_alloc.
Context `{heapG Σ, cinvG Σ, inG Σ (authR markingUR), inG Σ (authR graphUR)}.
Lemma graph_ctx_alloc (E : coPset) (g : graph loc) (markings : gmap loc loc)
(HNE : (nclose graphN) E)
: ([ map] l v g, (m : loc), markings !! l = Some m
l (#m, children_to_val v) m #false)
={E}= (Ig : graphG Σ) (κ : gname), cinv_own κ 1 graph_ctx κ g markings
own_graph 1%Qp .
Proof.
iIntros "H1".
iMod (own_alloc ( ( : markingUR))) as (mn) "H2"; first done.
iMod (own_alloc ( (Some (1%Qp, : Gmon) : graphUR)
(Some (1%Qp, : Gmon) : graphUR))) as (gn) "H3".
{ done. }
iDestruct "H3" as "[H31 H32]".
set (Ig := GraphG _ _ mn _ gn).
iExists Ig.
iAssert (graph_inv g markings) with "[H1 H2 H31]" as "H".
{ unfold graph_inv. iExists . rewrite dom_empty_L. iFrame "H2 H31".
iSplitL; [|iPureIntro].
- rewrite /heap_owns of_graph_empty big_sepM_fmap; eauto.
- rewrite /Gmon_graph omap_empty; apply strict_subgraph_empty. }
iMod (cinv_alloc _ graphN with "[H]") as (κ) "[Hinv key]".
{ iNext. iExact "H". }
iExists κ.
rewrite /own_graph /graph_ctx //=; by iFrame.
Qed.
End graph_ctx_alloc.
Lemma marked_was_unmarked (G : Gmon) x v :
({[x := Excl v]} G) G !! x = None.
Proof.
intros H2; specialize (H2 x).
revert H2; rewrite lookup_op lookup_singleton. intros H2.
by rewrite (excl_validN_inv_l O _ _ (proj1 (cmra_valid_validN _) H2 O)).
Qed.
Lemma mark_update_lookup_base (G : Gmon) x v :
({[x := Excl v]} G) ({[x := Excl v]} G) !! x = Some (Excl v).
Proof.
intros H2; rewrite lookup_op lookup_singleton.
erewrite marked_was_unmarked; eauto.
Qed.
Lemma mark_update_lookup_ne_base (G : Gmon) x i v :
i x ({[x := Excl v]} G) !! i = G !! i.
Proof. intros H. by rewrite lookup_op lookup_singleton_ne //= left_id_L. Qed.
Lemma of_graph_dom g G : dom (gset loc) (of_graph g G) = dom (gset _) g.
Proof.
apply mapset_eq=>i.
rewrite ?elem_of_dom lookup_imap /of_graph_elem lookup_omap.
case _ : (g !! i) => [x|]; case _ : (G !! i) => [[]|] //=; split;
intros [? Hcn]; inversion Hcn; eauto.
Qed.
Lemma in_dom_of_graph (g : graph loc) (G : Gmon) x (b : bool) v :
G of_graph g G !! x = Some (b, v) b x dom (gset _) G.
Proof.
rewrite /of_graph /of_graph_elem lookup_imap lookup_omap elem_of_dom.
intros Hvl; specialize (Hvl x); revert Hvl;
case _ : (g !! x) => [?|]; case _ : (G !! x) => [[] ?|] //=;
intros Hvl; inversion Hvl; try (inversion 1; subst); split;
try (inversion 1; fail); try (intros [? Hcn]; inversion Hcn; fail);
subst; eauto.
Qed.
Global Instance of_graph_proper g : Proper (() ==> (=)) (of_graph g).
Proof. solve_proper. Qed.
Lemma mark_update_lookup (g : graph loc) (G : Gmon) x v :
x dom (gset loc) g
((x [] v) G) of_graph g ((x [] v) G) !! x = Some (true, v).
Proof.
rewrite elem_of_dom /is_Some. intros [w H1] H2.
rewrite /of_graph /of_graph_elem lookup_imap H1 lookup_omap; simpl.
rewrite mark_update_lookup_base; trivial.
Qed.
Lemma mark_update_lookup_ne (g : graph loc) (G : Gmon) x i v :
i x of_graph g ((x [] v) G) !! i = (of_graph g G) !! i.
Proof.
intros H. rewrite /of_graph /of_graph_elem ?lookup_imap ?lookup_omap; simpl.
rewrite mark_update_lookup_ne_base //=.
Qed.
Section graph.
Context `{heapG Σ, graphG Σ}.
Lemma own_graph_valid q G : own_graph q G G.
Proof.
iIntros "H". unfold own_graph.
by iDestruct (own_valid with "H") as %[_ ?].
Qed.
Lemma auth_own_graph_valid q G : own graph_name ( Some (q, G)) G.
Proof.
iIntros "H". unfold own_graph.
by iDestruct (own_valid with "H") as %[_ [_ ?]].
Qed.
Lemma whole_frac (G G' : Gmon):
own graph_name ( Some (1%Qp, G)) own_graph 1 G' G = G'.
Proof.
iIntros "[H1 H2]". rewrite /own_graph.
iCombine "H1" "H2" as "H".
iDestruct (own_valid with "H") as %[H1 H2]; cbn in *.
iPureIntro.
specialize (H1 O).
apply cmra_discrete_included_iff in H1.
apply option_included in H1; destruct H1 as [H1|H1]; [inversion H1|].
destruct H1 as (u1 & u2 & Hu1 & Hu2 & H3);
inversion Hu1; inversion Hu2; subst.
destruct H3 as [[_ H31%leibniz_equiv]|H32]; auto.
inversion H32 as [[q x] H4].
inversion H4 as [H41 H42]; simpl in *.
assert ( (1 q)%Qp) by (rewrite -H41; done).
exfalso; eapply exclusive_l; eauto; typeclasses eauto.
Qed.
Lemma graph_divide q G G' :
own_graph q (G G') own_graph (q / 2) G own_graph (q / 2) G'.
Proof.
replace q with ((q / 2) + (q / 2))%Qp at 1 by (by rewrite Qp_div_2).
by rewrite /own_graph -own_op.
Qed.
Lemma mark_graph {E} (G : Gmon) q x w : G !! x = None
own graph_name ( Some (1%Qp, G)) own_graph q
={E}=
own graph_name ( Some (1%Qp, {[x := Excl w]} G)) own_graph q (x [] w).
Proof.
iIntros (Hx) "H". rewrite -?own_op.
iMod (own_update with "H") as "H'"; eauto.
apply auth_update, option_local_update, prod_local_update;
first done; simpl.
rewrite -{2}[(x [] w)]right_id.
apply op_local_update_discrete; auto.
rewrite -insert_singleton_op; trivial. apply insert_valid; done.
Qed.
Lemma update_graph {E} (G : Gmon) q x w m :
G !! x = None
own graph_name ( Some (1%Qp, {[x := Excl m]} G))
own_graph q (x [] m)
|={E}=> own graph_name ( Some (1%Qp, {[x := Excl w]} G))
own_graph q (x [] w).
Proof.
iIntros (Hx) "H". rewrite -?own_op.
iMod (own_update with "H") as "H'"; eauto.
apply auth_update, option_local_update, prod_local_update;
first done; simpl.
rewrite -!insert_singleton_op; trivial.
replace (<[x:=Excl w]> G) with (<[x:=Excl w]> (<[x:=Excl m]> G))
by (by rewrite insert_insert).
eapply singleton_local_update; first (by rewrite lookup_insert);
apply exclusive_local_update; done.
Qed.
Lemma graph_pointsto_marked (G : Gmon) q x w :
own graph_name ( Some (1%Qp, G)) own_graph q (x [] w)
G = {[x := Excl w]} (delete x G).
Proof.
rewrite /own_graph -?own_op. iIntros "H".
iDestruct (@own_valid with "H") as %[H1 H2]; simpl in *.
iPureIntro.
specialize (H1 O).
apply cmra_discrete_included_iff in H1.
apply option_included in H1; destruct H1 as [H1|H1]; [inversion H1|].
destruct H1 as (u1 & u2 & Hu1 & Hu2 & H1);
inversion Hu1; inversion Hu2; subst.
destruct H1 as [[_ H11%leibniz_equiv]|H12]; simpl in *.
+ by rewrite -H11 delete_singleton right_id_L.
+ apply prod_included in H12; destruct H12 as [_ H12]; simpl in *.
rewrite -insert_singleton_op ?insert_delete; last by rewrite lookup_delete.
apply: map_eq => i. apply leibniz_equiv, equiv_dist => n.
destruct (decide (x = i)); subst;
rewrite ?lookup_insert ?lookup_insert_ne //.
apply singleton_included in H12. destruct H12 as [y [H31 H32]].
rewrite H31 (Some_included_exclusive _ _ H32); try done.
destruct H2 as [H21 H22]; simpl in H22.
specialize (H22 i); revert H22; rewrite H31; done.
Qed.
Lemma graph_open (g :graph loc) (markings : gmap loc loc) (G : Gmon) x
: x dom (gset _) g
own graph_name ( Some (1%Qp, G)) heap_owns (of_graph g G) markings
own graph_name ( Some (1%Qp, G))
heap_owns (delete x (of_graph g G)) markings
( u : bool * (option loc * option loc), of_graph g G !! x = Some u
(m : loc), markings !! x = Some m x (#m, children_to_val (u.2))
m #(u.1)).
Proof.
iIntros (Hx) "(Hg & Ha)".
assert (Hid : x dom (gset _) (of_graph g G)) by (by rewrite of_graph_dom).
revert Hid; rewrite elem_of_dom /is_Some. intros [y Hy].
rewrite /heap_owns -{1}(insert_id _ _ _ Hy) -insert_delete.
rewrite big_sepM_insert; [|apply lookup_delete_None; auto].
iDestruct "Ha" as "[H $]". iFrame "Hg". iExists _; eauto.
Qed.
Lemma graph_close g markings G x :
heap_owns (delete x (of_graph g G)) markings
( u : bool * (option loc * option loc), of_graph g G !! x = Some u
(m : loc), markings !! x = Some m x (#m, children_to_val (u.2))
m #(u.1))
heap_owns (of_graph g G) markings.
Proof.
iIntros "[Ha Hl]". iDestruct "Hl" as (u) "[Hu Hl]". iDestruct "Hu" as %Hu.
rewrite /heap_owns -{2}(insert_id _ _ _ Hu) -insert_delete.
rewrite big_sepM_insert; [|apply lookup_delete_None; auto]. by iFrame "Ha".
Qed.
Lemma marked_is_marked_in_auth (mr : gset loc) l :
own graph_marking_name ( mr) is_marked l l mr.
Proof.
iIntros "H". unfold is_marked. rewrite -own_op.
iDestruct (own_valid with "H") as %Hvl.
iPureIntro. destruct Hvl as [Hvl _]. destruct (Hvl O) as [z Hvl'].
rewrite Hvl' /= !gset_op_union !elem_of_union elem_of_singleton; tauto.
Qed.
Lemma marked_is_marked_in_auth_sepS (mr : gset loc) m :
own graph_marking_name ( mr) ([ set] l m, is_marked l) m mr.
Proof.
iIntros "[Hmr Hm]". rewrite big_sepS_forall pure_forall.
iIntros (x). rewrite pure_impl. iIntros (Hx).
iApply marked_is_marked_in_auth.
iFrame. by iApply "Hm".
Qed.
End graph.
(* Graph properties *)
Lemma delete_marked g G x w :