Require Import Vbase Relations ClassicalDescription ClassicalChoice.
Require Import List Permutation Sorting extralib.
Require Import c11 exps.
Require Import GpsSepAlg GpsModel GpsModelLemmas.
Require Import GpsGlobal GpsVisible GpsGlobalHelper.

Local Open Scope string_scope.

Set Implicit Arguments.

C.3.3. Ghost moves


Lemma incoming_upd_ext_esc :
   acts (ND: NoDup acts) a (IN: In a acts) L b rr,
    incoming acts (upd L (Tesc a b) (rr +!+ L (Tesc a b))) b =
    rr +!+ incoming acts L b.
Proof.
  ins; rewrite !(res_plusC rr); unfold incoming, in_sb, in_rf.
  rewrite !map_upd_irr; try (by rewrite in_map_iff; intro; desf).
  rewrite !res_plusA; do 2 f_equal.
  unfold in_esc.
  eapply In_NoDup_Permutation in IN; desf.
  rewrite !(Permutation_rsum (Permutation_map _ (Permutation_map _ IN)));
    simpl; rewrite upds.
  rewrite map_upd_irr, !res_plusA; f_equal; eauto using res_plusC.
  rewrite in_map_iff; intro; desf.
Qed.

Lemma label_restr_fin acts amap sb rf mo sc L E :
  Consistent acts amap sb rf mo sc
  label_restr acts amap sb rf L E
   tel, te (NIN: ¬ In te tel), L te = res_emp.
Proof.
  ins.
  
    (flatten (map (fun amap (Tsb a) acts) acts) ++
     flatten (map (fun amap (Trf a) acts) acts) ++
     flatten (map (fun amap (Tesc a) acts) acts) ++
     map TsbS acts ++ map TrfS acts ++ flatten (map (fun smap (TescS s) acts) E)).
  ins.
  rewrite !in_app_iff, !in_flatten_iff, !in_map_iff in ×.
  repeat match goal with
           H : ¬ (_ _) |- _apply not_or_and in H; desc
         end.
  destruct te; ins; apply H0; try apply not_and_or; intro; desc; eauto 6 using in_map;
  exploit Consistent_hb_in; eauto; try intro; desf; eauto 8 using in_map.
Qed.

Lemma res_gget_max_list l :
   n, n' (LT: n < n') r , In r l res_gget r n' = None.
Proof.
  induction l; ins; desf; [by 0|].
  destruct a as [|p [f [n' C]] e].
    by n; ins; desf; eauto.
   (n + n'); ins; desf; ins; eauto with arith.
Qed.

Lemma outgoing_upd_sbS b acts L E r a :
  outgoing acts (upd L (TsbS b) (L (TsbS b) +!+ r)) E a =
  if a == b then r +!+ outgoing acts L E a else outgoing acts L E a.
Proof.
  unfold outgoing, out_sb, out_rf, out_esc; ins.
  rewrite !map_upd_irr; try (by rewrite in_map_iff; intro; desf).
  by unfold upd; desf; ins; desf; rewrite !res_plusA, res_plusAC.
Qed.

Lemma RP_extC (P : RProp) r (H : P r) r' (D: r' +!+ r Rundef) : P (r' +!+ r).
Proof.
  rewrite res_plusC in *; eapply RP_ext; eauto.
Qed.

Lemma hb_irr :
   acts amap sb rf mo sc
    (CONS: Consistent acts amap sb rf mo sc) a
    (HB: happens_before amap sb rf a a),
    False.
Proof.
  unfold Consistent; ins; desf.
  eapply (ACYC a); revert HB; generalize a at 1 3; induction 1; vauto.
  unfold imm_happens_before, synchronizes_with in *; desf; eauto using clos_trans.
Qed.

Lemma compat_inc_sink :
   acts amap sb rf mo sc
    (CONS: Consistent acts amap sb rf mo sc)
    (ND : NoDup acts) L
    (CC : compat amap sb rf L) E
    (LR : label_restr acts amap sb rf L E) a b,
  a = b
  happens_before amap sb rf a b
  happens_before amap sb rf b a
  L (TsbS b) +!+ incoming acts L a Rundef.
Proof.
  ins.
  apply NNPP; intro X.
  apply not_or_and in X; desf.
  apply not_or_and in X0; desf.
  apply not_or_and in X1; desf.
  apply NNPP in X2.
  apply (CC (TsbS b :: map (Tsb^~ a) (filter (mydecf (happens_before amap sb rf^~ a)) acts)
                     ++ map (Trf^~ a) (filter (mydecf (happens_before amap sb rf^~ a)) acts)
                     ++ map (Tesc^~ a) (filter (mydecf (happens_before amap sb rf^~ a)) acts))).
    constructor; [by rewrite !in_app_iff, !in_map_iff; intro; desf|].
    rewrite !nodup_app; repeat apply conj;
    try eapply nodup_map; try eapply nodup_filter; ins; try congruence;
    by unfold disjoint; intro; rewrite ?in_app_iff, !in_map_iff; ins; desf.

    by ins; rewrite !in_app_iff, !in_map_iff in *; desf; rewrite in_filter_iff in *; ins; desf;
       rewrite mhbE in *; desf; unfold mydecf in *; desf; eapply hb_irr; eauto using hb_trans.

  ins; rewrite !map_app, !rsum_app, !rsum_map_map_filter; ins; apply LR; eauto.
Qed.

Lemma replace_edge_ext :
   A (a : A) f pi l
    (ND: NoDup l)
    (IN : In a l),
  rsum (map (upd f a (f a +!+ pi)) l) = pi +!+ rsum (map f l).
Proof.
  ins; induction ND; ins.
  desf; rewrite ?upds, ?updo; try congruence.
    by rewrite res_plusA, res_plusAC, map_upd_irr.
  by rewrite IHND, res_plusAC.
Qed.

Lemma sat_exch_ext :
   IE sigma r (M : sat_exch IE sigma r)
         r' (D : r +!+ r' Rundef),
  sat_exch IE sigma (r +!+ r').
Proof.
  red; ins; edestruct M; eauto using RP_ext.
Qed.

Lemma exch_conform_ext1 IE acts amap sb rf L te r L' EE sigma
  (ECO : exch_conform IE acts amap sb rf (upd L te r) L' EE sigma)
  (NEQ: a, te TescS sigma a) r'
  (IMP : res_escr (r +!+ r') sigma res_escr r sigma) :
  exch_conform IE acts amap sb rf (upd L te (r +!+ r')) L' EE sigma.
Proof.
  red; ins; unfold upd in *; desf.
    edestruct (ECO te) as (a & M); ins; eauto.
      by desf; auto.
     a; split; ins; desc; des_if; ins.
    by eapply sat_exch_ext; eauto; intro X; rewrite X in ESC.
  edestruct (ECO edge) as (a & M); ins; eauto.
    by desf; auto.
   a; desf; eauto; congruence.
Qed.

Lemma in_esc_upd_in :
   acts L a b r1 r,
    In a acts
    NoDup acts
    L (Tesc a b) = r1
    in_esc acts (upd L (Tesc a b) (r +!+ r1)) b =
    in_esc acts L b +!+ r.
Proof.
  ins; unfold in_esc; eapply in_split in H; desf;
  rewrite !map_app, !rsum_app; ins.
  rewrite nodup_app, nodup_cons in *; desf.
  unfold disjoint in *; ins.
  rupd; rewrite !map_upd_irr, !res_plusA; rewrite ?in_map_iff;
    try intro; desf; eauto.
  by rewrite (res_plusC _ r), !(res_plusAC r).
Qed.

Lemma hb_mhb amap sb rf a b :
  happens_before amap sb rf a b
  may_happens_before amap sb rf a b.
Proof.
  rewrite mhbE; auto.
Qed.

Lemma ghost_allocE r mm :
  ghost_alloc r mm r = Rundef res_gget r mm None.
Proof.
  destruct r; ins; desf; split; ins; try tauto; desf.
Qed.

Lemma ghost_alloc_conform_helper2 :
   acts L EE (ND: NoDup EE) r r' a
         (GAC: ghost_alloc_conform acts (upd L (TsbS a) (L (TsbS a) +!+ r)) EE)
         (IMP: gl (GA: ghost_alloc r' gl)
                 a' (NEQ: a a') (GA': ghost_alloc (outgoing acts L EE a') gl),
                 False)
         (DEF: outgoing acts (upd L (TsbS a) (L (TsbS a) +!+ r +!+ r')) EE a Rundef),
    ghost_alloc_conform acts (upd L (TsbS a) (L (TsbS a) +!+ r +!+ r')) EE.
Proof.
  red; ins; destruct (eqP a0 a'); ins.
  eapply GAC with (gl:=gl); ins;
    rewrite ?incoming_upd_irr in *; ins.

  destruct (eqP a a0); desf.
    rewrite outgoing_upd_in in DEF, OUT; ins; rewrite outgoing_upd_in; ins;
    rewrite outgoing_upd_irr in OUT'; ins; eauto.
    rewrite <- res_plusA in ×.
    unfold ghost_alloc; desf; ins; desf; ins; intro; eauto.
    eapply IMP; eauto;
    unfold gres_plus in *; des_eqrefl; desf; ins; clear DEF; inv_lplus gl;
    destruct (gres gl); ins; desf; congruence.
  by rewrite outgoing_upd_irr in OUT; try rewrite outgoing_upd_irr; ins.

  destruct (eqP a a'); desf.
    rewrite outgoing_upd_in in DEF, OUT'; ins; rewrite outgoing_upd_in; ins;
    rewrite outgoing_upd_irr in OUT; ins; eauto.
    rewrite <- res_plusA in ×.
    unfold ghost_alloc; desf; ins; desf; ins; intro; eauto.
    clear DEF.
    eapply IMP with (a'0 := a0); eauto.
    unfold gres_plus in *; des_eqrefl; desf; ins; inv_lplus gl.
    destruct (gres gl); ins; desf; congruence.
  by rewrite outgoing_upd_irr in OUT'; try rewrite outgoing_upd_irr; ins.
Qed.

Lemma outgoing_ee :
   acts amap sb rf L EE
    (LR : label_restr acts amap sb rf L EE) sigma a,
    outgoing acts L
         (if excluded_middle_informative (In sigma EE)
          then EE
          else sigma :: EE) a =
    outgoing acts L EE a.
Proof.
  unfold outgoing, out_esc; ins; desf; ins; do 3 f_equal.
  red in LR; desc; rewrite LRescS; auto using res_plus_emp_l.
Qed.

Lemma valid_ghost_gget :
   r r' (VG : valid_ghost r r') r0
         (BAR: m gr, res_gget r0 m = Some gr
                            res_gget r m = None
                            res_gget r' m = None) r''
         (IDEF : r +!+ r0 +!+ r'' Rundef)
         (ODEF : r' +!+ r0 Rundef)
         (OUD : r' +!+ r0 +!+ r'' = Rundef),
    gl : nat,
     res_gget r'' gl None
     res_gget (r +!+ r0) gl = None
     res_gget (r' +!+ r0) gl None.
Proof.
  ins; rewrite <- res_plusA in *; red in VG; desf; ins; desf; ins; desf.
  clear ODEF IDEF; rewrite gres_plusC in *; unfold gres_plus in *; repeat des_eqrefl; desf; ins.
  clear p p1 pmap pmap0 p0 Heq Heq2 escr1 escr escr0 escr'.
  symmetry in EQ; apply lift_plus_noneD in EQ; destruct EQ as [l M].
  inv_lplus l; l; specialize (VGG l); specialize (BAR l).
  remember (o l) as oo; clear Heqoo.
  remember (o1 l) as oo1; clear Heqoo1.
  remember (o0 l) as oo0; clear Heqoo0.
  destruct (gres l), (gres0 l); ins; desf; try specialize (VGG _ eq_refl); desf.
  × exfalso; destruct s; ins; desf; rewrite <- eq_rect_eq in *; ins.
    destruct s0; ins; desf; rewrite <- eq_rect_eq in *; ins.
    by rewrite salg_plusC in *;
       assert (K := salg_plusA _ _ _ Heq5 _ Heq4); desc;
       eapply salg_plusA2 in Heq; eauto; desf;
      eapply VGG0 in Heq; desf.
  × exfalso; clear VGG; exploit BAR; desf.
  × exfalso; destruct s; ins; desf; rewrite <- eq_rect_eq in *; ins; desf.
    rewrite salg_plusC in *; apply VGG0 in Heq0; desf.
Qed.

Lemma exch_conform_upd1_acc IE acts amap sb rf L L' EE sigma te2 r
  (ECO : exch_conform IE acts amap sb rf (upd L te2 r) L' EE sigma) te1 r1
  (N1: a, te1 = TescS sigma a sat_exch IE sigma r1) r2
  (N2: a, te2 = TescS sigma a sat_exch IE sigma r2)
  (SRC: te_src te1 = te_src te2)
  (T1: te_tgt te1 = None)
  (T2: te_tgt te2 = None)
  (NEQ: te1 te2)
  (DEF: r1 +!+ r2 Rundef)
  (EQ: r1 +!+ r2 = L te1 +!+ r) :
  exch_conform IE acts amap sb rf (upd (upd L te1 r1) te2 r2) L' EE sigma.
Proof.
  red; ins; unfold upd in *; desf.
    exploit (proj2 (res_escr_plus _ _ DEF sigma)); vauto.
    rewrite EQ in *; rewrite res_escr_plus; intro K; desf.
      edestruct (ECO te1) as (a & M); ins; try (by desf).
      des_if; ins; try congruence; a; des_if;
      desc; ins; clarify; split; eauto; try congruence.
    edestruct (ECO te2) as (a & M); ins; try (by desf).
    des_if; ins; try congruence; a; des_if;
    desc; ins; clarify; split; eauto; try congruence.

    exploit (proj2 (res_escr_plus _ _ DEF sigma)); vauto.
    rewrite EQ in *; rewrite res_escr_plus; intro K; desf.
      edestruct (ECO te1) as (a & M); ins; try (by desf).
      des_if; ins; try congruence; a; des_if;
      desc; ins; clarify; split; eauto; try congruence.
    edestruct (ECO te2) as (a & M); ins; try (by desf).
    des_if; ins; try congruence; a; des_if;
    desc; ins; clarify; split; eauto; try congruence.

  edestruct (ECO edge) as (a & M); ins; try (by desf).
  des_if; ins; try congruence; a; des_if;
  desc; ins; clarify; split; eauto; try congruence.
Qed.

Visibility of ghost locations

Lemma visible_ghost_one :
   acts amap sb rf mo sc
    (CONS: Consistent acts amap sb rf mo sc) L E
    (LR: label_restr acts amap sb rf L E)
    (CC: compat amap sb rf L) N
    (PC: prefix_closed sb rf N) te
    (IN : In (te_src te) N) gl
    (G : res_gget (L te) gl None)
    (ND: NoDup acts) (NDE: NoDup E),
   a,
    << HB : may_happens_before amap sb rf a (te_src te) >>
    << INC : res_gget (incoming acts L a) gl = None >>
    << OUT : res_gget (outgoing acts L E a) gl None >>
    << INA : In a acts >>.
Proof.
  ins.
  revert G; pattern te.
  eapply edge_depth_ind with (lab:=amap) (V:=N); eauto.
    by red in CONS; desc; intros ? ?; edestruct ACYC; eauto.
  clear te IN; ins; desf; unfold NW.
  assert ( sigma a, edge = TescS sigma a In sigma E).
    by ins; apply NNPP; intro; desf; red in LR; ins; desf; rewrite LRescS in G; ins; vauto.
  assert ( a, te_tgt edge = Some a In a acts).
    by ins; eapply lab_tgt_in_acts; eauto; intro X; rewrite X in *; ins.

  destruct (classic (res_gget (incoming acts L (te_src edge)) gl = None)).
    eexists; repeat split; vauto.
    2: by eapply lab_src_in_acts; eauto; intro X; rewrite X in *; ins.
    rewrite <- (updI L edge), outgoing_upd_in_alt; ins; desf; eauto.
    rewrite res_gget_plus; intro; desf.
    rewrite <- outgoing_upd_in_alt, updI in H2; ins; desf; eauto.
    eapply helper_out_def; eauto.

  unfold incoming, in_sb, in_rf, in_esc in H1.
  rewrite !res_gget_plus, !res_gget_rsum in ×.
  repeat match goal with
             H : ¬ (_ _) |- _apply not_or_and in H; desc
           | H : ¬ (_ _) |- _apply not_and_or in H; des
           | H : ¬ _ |- _apply not_all_ex_not in H; desc
         end;
  repeat (rewrite in_map_iff in *; desf);
  clear G;
  (assert (HB: happens_before amap sb rf x0 (te_src edge));
  [match goal with H : res_gget (L ?tee) _ None |- _
     let X := fresh in eapply hb_one with (te := tee); eauto; intro X; rewrite X in *; ins
   end | edestruct IH as [a' ?]; eauto; ins; desc; a'; split; eauto using mhb_trans, hb_mhb]).
Qed.

Lemma visible_ghost2 :
   acts amap sb rf mo sc
    (CONS: Consistent acts amap sb rf mo sc) L E
    (GAC: ghost_alloc_conform acts L E)
    (CC: compat amap sb rf L) te a gl
    (G : res_gget (L te) gl None)
    (INC : res_gget (incoming acts L a) gl = None)
    (OUT : res_gget (outgoing acts L E a) gl None)
    (LR: label_restr acts amap sb rf L E)
    (ND: NoDup acts) (NDE: NoDup E) (INA: In a acts),
  may_happens_before amap sb rf a (te_src te).
Proof.
  ins; eapply visible_ghost_one with (N:=acts) in G; eauto using Consistent_prefix_closed; desf.
  2: by ins; eapply lab_src_in_acts; eauto; intro X; rewrite X in *; ins.
  assert (a = a0); desf.
  eapply GAC with (gl := gl); eauto; red; ins; desf;
  rewrite ghost_allocE in *; desf; eapply compat_inc in H; eauto.
Qed.

Lemma sat_exch_emp IE sigma : ¬ sat_exch IE sigma res_emp.
Proof.
  unfold sat_exch; red; ins.
  destruct IE as [p e A B]; ins.
  specialize (A sigma res_emp); specialize (B sigma res_emp).
  destruct (e sigma); specialize (H _ _ eq_refl).
  desf; [apply A|apply B]; repeat eexists; eauto using res_plus_emp_l; ins.
Qed.

Lemma ghost_elim_sat_exch IE P1 P2 Q r r' sigma :
   interp_exch IE sigma = (P1, P2)
   ghost_elim P1 P2 Q r r' sat_exch IE sigma r'.
Proof.
  destruct 2; [left|right]; congruence.
Qed.

Lemma three_sat_exch IE r1 r2 r3 sigma :
  sat_exch IE sigma r1
  sat_exch IE sigma r2
  sat_exch IE sigma r3
  r1 +!+ r2 +!+ r3 = Rundef.
Proof.
  unfold sat_exch; destruct IE as [p e A B]; ins.
  specialize (A sigma); specialize (B sigma).
  destruct (e sigma) as [P Q]; ins.
  apply NNPP; intro X.
  specialize (H _ _ eq_refl);
  specialize (H0 _ _ eq_refl); desf.
  1: by rewrite <- res_plusA in X; destruct (A (r1 +!+ r2));
        repeat eexists; ins; kundef.
  3: by rewrite <- res_plusA in X; destruct (B (r1 +!+ r2));
        repeat eexists; ins; kundef.
 specialize (H1 _ _ eq_refl); desf.
   by destruct (A (r2 +!+ r3)); repeat eexists; ins; kundef.
   by rewrite res_plusAC in X; destruct (B (r1 +!+ r3));
      repeat eexists; ins; kundef.
 specialize (H1 _ _ eq_refl); desf.
   by rewrite res_plusAC in X; destruct (A (r1 +!+ r3));
      repeat eexists; ins; kundef.
   by destruct (B (r2 +!+ r3)); repeat eexists; ins; kundef.
Qed.

Lemma ghost_step :
   b acts (NIN: ¬ In b acts) amap sb rf mo sc r P
    (CONS: Consistent (b::acts) amap sb rf mo sc)
    (ND: NoDup (b :: acts))
    (PC : prefix_closed sb rf acts)
    (PI: pres_in sb rf b acts) IE
    (GM: ghost_move IE r P) L EE
    (V : a (IN: In a acts), valid_node IE (b::acts) (b::acts) amap rf L EE a)
    (CC: compat amap sb rf (upd L (TsbS b) (L (TsbS b) +!+ r)))
    (CO: conform (b::acts) amap mo L acts)
    (ECO: sigma,
           exch_conform IE (b::acts) amap sb rf
                         (upd L (TsbS b) (L (TsbS b) +!+ r))
                         (upd L (TsbS b) (L (TsbS b) +!+ r)) EE sigma)
    (GAC: ghost_alloc_conform (b::acts)
                (upd L (TsbS b) (L (TsbS b) +!+ r)) EE)
    (VG: valid_ghost (incoming (b::acts) L b)
                     (r +!+ out_esc (b::acts) L EE b))
    (RS: res_lt (res_strip (incoming (b::acts) L b)) r)
    (EO: c, L (Tesc b c) = res_emp)
    (LR : label_restr (b::acts) amap sb rf L EE)
    (Osb : out_sb (b :: acts) L b = res_emp)
    (Orf : out_rf (b :: acts) L b = res_emp)
    (ND' : NoDup EE),
   L' EE' r,
    << IN': P r >>
    << V : a (IN: In a acts), valid_node IE (b::acts) (b::acts) amap rf L' EE' a >>
    << CC: compat amap sb rf (upd L' (TsbS b) (L' (TsbS b) +!+ r)) >>
    << CO: conform (b::acts) amap mo L' acts >>
    << ECO: sigma,
              exch_conform IE (b::acts) amap sb rf
                           (upd L' (TsbS b) (L' (TsbS b) +!+ r))
                           (upd L' (TsbS b) (L' (TsbS b) +!+ r)) EE' sigma >>
    << GAC: ghost_alloc_conform (b::acts)
                (upd L' (TsbS b) (L' (TsbS b) +!+ r)) EE' >>
    << VG: valid_ghost (incoming (b::acts) L' b)
                       (r +!+ out_esc (b::acts) L' EE' b) >>
    << RS: res_lt (res_strip (incoming (b::acts) L' b)) r >>
    << EO: c, L' (Tesc b c) = res_emp >>
    << Esb: a b, L' (Tsb a b) = L (Tsb a b) >>
    << Erf: a b, L' (Trf a b) = L (Trf a b) >>
    << EsbS: a, L' (TsbS a) = L (TsbS a) >>
    << ErfS: a, L' (TrfS a) = L (TrfS a) >>
    << NDE : NoDup EE' >>
    << EEE : sigma, In sigma EE In sigma EE' >>
    << LR : label_restr (b::acts) amap sb rf L' EE' >>.
Proof.
  induction 6; ins; unfold NW; desc.
    by eexists L, EE, r; repeat (split; ins).

Case "transitivity".
  exploit IHGM; eauto.
  clear r V CC CO ECO GAC VG EO RS IHGM GM GM' LR.
  intro; desf; exploit H; eauto.
    by rewrite <- Osb; unfold out_sb; f_equal; try done;
       clear - Esb; induction (b :: acts); ins; f_equal.
    by rewrite <- Orf; unfold out_rf; f_equal; try done;
       clear - Erf; induction (b :: acts); ins; f_equal.
  by intro; desf; repeat (eexists; try edone); eauto using eq_trans.

Case "Ghost allocation".
  assert (MM: mm,
                res_gget r mm = None
                 te, res_gget (L te) mm = None).
    clear - CONS LR.
    destruct (label_restr_fin CONS LR) as [myL EMP].
    destruct (res_gget_max_list (r :: map L myL)) as [mm X].
     (S mm); split; ins. eapply X; ins; vauto.
    destruct (classic (In te myL)); eauto using in_map.
    by rewrite EMP; ins.

  desf; assert (DEF: r Rundef) by (intro; subst; red in VG; desf).

  assert (CC' : compat amap sb rf (upd L (TsbS b)
           (L (TsbS b) +!+ r +!+
            Rdef (fun _p_bot) (gres_one mm gone) (fun _false)))).
    red; red; ins; eapply CC; eauto.
    revert H.
    destruct (classic (In (TsbS b) E)) as [C|C];
      [eapply In_NoDup_Permutation in C; desf;
       rewrite !(Permutation_rsum (Permutation_map _ C)); simpl; rewrite !upds|];
    rewrite !map_upd_irr; try done.
    rewrite !res_plusA, !(res_plusAC (Rdef _ _ _)), res_plusC; intro.
    apply NNPP; intro.
     revert H; apply res_gget_def; ins.
    unfold out_esc; repeat (rewrite res_gget_plus; right; split; ins).
    by rewrite res_gget_rsum; right; ins; rewrite in_map_iff in *; desf.

  eexists L, EE,
    (res_plus r (Rdef (fun _p_bot) (gres_one mm gone) (fun _false)));
    split; try edone; repeat (apply conj; try done).
    by eapply PEQ; eauto using gres_plus_emp_r, res_gget_def.

    ins; rewrite <- res_plusA; eapply exch_conform_ext1; try done.
    2: by intro ESC; apply res_escr_plusE in ESC; desf.

    red; ins; eapply ECO in ESC; ins; destruct ESC as (a' & M & M').
     a'; split; desf; eauto.
    rewrite incoming_upd_irr in *; ins.
    right; ins; edestruct M' as [gl Z]; desc; eauto.
     gl; repeat split; ins.
    destruct (eqP b a'); desf; [|by rewrite outgoing_upd_irr in *].
    revert Z1; rewrite res_plusA, !outgoing_upd_in, <- res_plusA; ins.
    rewrite res_gget_plus; intro; desf.
    apply res_gget_def in H; ins.
    repeat first [ apply res_gget_rsum; right; ins;
                   repeat (rewrite in_map_iff in *; desf)
                 | apply res_gget_plus; right; split; ins].
    by intro X; rewrite X in ×.

    eapply ghost_alloc_conform_helper2; eauto using helper_out_def, in_eq.
    ins; desf; desf; apply ghost_allocE in GA'; desf.
      by eapply helper_out_def in GA'; eauto using compat_mon_upd.
    clear - GA' MM0; unfold outgoing, out_sb, out_rf, out_esc in GA'.
    by repeat first
       [ rewrite res_gget_rsum in GA'; apply not_or_and in GA';
         destruct GA' as [_ GA']; apply not_all_ex_not in GA'; desc;
         apply imply_to_and in GA'; rewrite in_map_iff in *; desf
       | rewrite res_gget_plus in GA'; apply not_or_and in GA';
         destruct GA' as [_ GA']; apply not_and_or in GA'; desf].

    red in VG; ins; desf.
    rewrite !res_plusA, res_plusAC, res_plusC.
    eapply res_gget_def2 with (mm := mm) (gone := gone) in VG0; eauto; desf.
    do 7 (eexists; eauto); unnw.
    assert (KK: res_gget (incoming (b :: acts) L b) mm = None).
      unfold incoming, in_sb, in_rf, in_esc;
      repeat (rewrite res_gget_plus; right; split; ins);
      by rewrite res_gget_rsum; right; ins; rewrite in_map_iff in *; desf.
    rewrite VG in KK; simpls.
    clear - KK VG0 VGG; ins; specialize (VGG _ _ RG); desc; ins.
    destruct gm as [A gm]; ins.
    unfold gres_plus, gres_one in VG0; des_eqrefl; desf; ins.
    by inv_lplus gl; desf; desf; rewrite VGG in *; ins; desf; ins; eauto.

    by unfold out_esc; repeat (rewrite res_gget_plus; right; split; ins);
       rewrite res_gget_rsum; right; ins; rewrite in_map_iff in *; desf.

  by eapply res_lt_trans, res_lt_plus_r, res_lt_refl.

Case "Ghost update".
  assert (GG: g'', gres_plus (gres_strip g) g' = Some g''). {
    generalize (GDEF (gres_strip g)); rewrite gres_plus_strip_idemp, gres_plusC.
    destruct (gres_plus (gres_strip g) g'); vauto.
    by intro X; specialize (X eq_refl).
  }
  desc.
  assert (GDEF' : gF,
         gres_plus g'' gF = None gres_plus g gF = None).
    clear - GG GDEF; ins.
    case_eq (gres_plus g gF) as EQ; ins; exfalso.
    rewrite gres_plusC in GG.
    eapply (gres_plusA2 GG) in H; desf.
      by apply (gres_plusA (gres_plus_strip_idemp g)) in EQ; desf.
    apply (gres_plusA (gres_plus_strip_idemp g)) in EQ; desf.
    by rewrite GDEF in ×.

  assert (CC': compat amap sb rf (upd L (TsbS b) (L (TsbS b) +!+ Rdef p g'' e))).
    repeat red; intros; eapply CC; eauto; revert H.
    destruct (classic (In (TsbS b) E)) as [C|C];
      [eapply In_NoDup_Permutation in C; desf;
       rewrite !(Permutation_rsum (Permutation_map _ C)); simpl; rewrite !upds|];
    rewrite !map_upd_irr; try done.
    rewrite !res_plusA, 2!(res_plusAC (Rdef _ _ _)); simpl; desf.
    apply GDEF' in Heq1; congruence.

  eexists L, EE, (Rdef p g'' e); repeat (apply conj; try done).
    assert (XX: Rdef p g'' e =
          Rdef p g' e +!+ Rdef (fun _p_bot) (gres_strip g) (fun _false)).
      by rewrite res_plusC; ins; rewrite lift_plus_emp_l, GG.
    by rewrite XX; eapply RP_ext; congruence.

  {
    red; intros.
    exploit (ECO sigma edge); eauto.
      apply res_plus_eq_empD, proj1 in Osb; rewrite Osb, res_plus_emp_l in ×.
      by revert ESC; unfold upd; desf.
    intros (a' & M & M'); a'; revert M M'.
    rewrite !updo, !incoming_upd_irr; ins; split; ins.
    clear VG; desf; eauto; right; ins.
    edestruct M' as [gl Z]; desc; eauto;
     gl; repeat split; ins.
    destruct (eqP b a'); desf; [|by rewrite outgoing_upd_irr in *].
    revert Z1; rewrite !outgoing_upd_in; ins.
    rewrite res_plusC in Z1; rewrite res_plusC; ins; desf; ins.
    2: apply GDEF' in Heq1; congruence.
    clear - Z1 Heq2 Heq1 GG.
    unfold gres_plus, gres_strip in *; repeat des_eqrefl; ins; desf; ins.
    inv_lplus gl; destruct (g gl), (o1 gl); ins; desf; congruence.
  }

  {
    eapply ghost_alloc_conform_helper1; eauto using helper_out_def, in_eq; subst.
    rewrite (proj1 (res_plus_eq_empD _ _ Osb)), !res_plus_emp_l.
    clear - GDOM GG; ins; intro X; specialize (GDOM _ X).
    unfold gres_plus, gres_strip in *; des_eqrefl; desf; ins.
    inv_lplus gl; rewrite X in *; ins; desf; congruence.
  }

  desf; clear - RS GG VG GDEF GDEF' GDOM; unfold valid_ghost in *; ins; desf.
  2: by apply GDEF' in Heq1; congruence.
  rewrite VG; do 7 eexists; eauto.
  unnw.
  assert (GDOM' : gl, g gl = None g'' gl = None).
  { clear - GG GDOM.
    unfold gres_plus, gres_strip in GG; repeat des_eqrefl; desf; split; ins; inv_lplus gl.
    rewrite H, (GDOM _ H) in *; ins; desf.
    by rewrite H in *; destruct (g gl), (g' gl); ins; desf.
  }

  rewrite VG in *; simpls.

  clear - GG Heq1 Heq2 VGG RS GDEF GDEF' GDOM'; ins; specialize (VGG _ _ RG); desc.
  destruct gm as [A gm]; ins.
  rewrite gres_plusC in Heq1, Heq2.
  unfold gres_plus, gres_strip in Heq1, Heq2; repeat des_eqrefl; desf; ins.
  inv_lplus gl; specialize (GDOM' gl); rewrite VGG in ×.
  destruct (gres gl) as [[B gg]|]; ins; desf;
  try rewrite <- eq_rect_eq in *; desf;
  try (by exploit GDOM');
  try (by exploit GDOM'0); eauto.

   repeat eexists; eauto; ins.
   clear GDOM' GDOM'0.
   unfold gres_plus in GG; des_eqrefl; desf; ins.
   eapply VGG0; clear VGG0.

   rewrite salg_plusC in Heq1, Heq3.
   eapply salg_plusA2 in SPN; eauto; desf; eauto using salg_plusA3.

   clear GDEF; specialize (GDEF' (gres_one gl (Some (existT _ A yz)))).

   unfold gres_plus in GDEF'; repeat des_eqrefl; ins; desf; try (by exploit GDEF');
   clear GDEF'; inv_lplus gl; desf; desf;
   try rewrite Heq in *; try rewrite Heq0 in *; ins; desf; try rewrite <- eq_rect_eq in *; desf; desf;
   ins; desf; try rewrite <- eq_rect_eq in *; desf; eauto using salg_plusA4;
   match goal with
       H : None = _ |- _
       symmetry in H; apply lift_plus_noneD in H; desf;
       unfold olift_plus in *; ins; desf; ins; desf; ins; desf;
       try rewrite <- eq_rect_eq in *; clarify; eauto using salg_plusA3
   end; eauto using salg_plusA4.

   rewrite <- H0; clear H0.
   unfold gres_plus in GG; des_eqrefl; desf; ins.
   assert ( t, o1 gl = Some (existT _ A t)).
     by clear GDEF'; inv_lplus gl; rewrite H1 in *; ins; desf; eauto.
   desc; repeat eexists; eauto; ins.
   specialize (GDEF' (gres_one gl (Some (existT _ A fr)))).
   unfold gres_plus in GDEF'; repeat des_eqrefl; ins; desf; try (by exploit GDEF');
   clear GDEF'; inv_lplus gl; desf; desf;
   try rewrite H in *; ins; desf; desf; try rewrite <- eq_rect_eq in *; clarify.
   by symmetry in EQ0; apply lift_plus_noneD in EQ0; desf;
      symmetry in EQ1; apply lift_plus_noneD in EQ1; desf; clarify;
      unfold olift_plus in *; ins; desf; ins; desf; ins; desf;
      try rewrite <- eq_rect_eq in *; clarify; eauto.

  rewrite res_lt_strip_l in ×.
  eapply res_lt_trans; eauto.
   (Rdef (fun _p_bot) (gres_strip g') (fun _false)).
  desf; clear - GG; ins.
  apply gres_strip_plus in GG; rewrite gres_strip_idemp in GG; rewrite GG.
  rewrite lift_plusC, lift_plus_emp_l; ins; auto using prot_plusC; f_equal; ins.
  by extensionality l; rewrite orbF.

Case "Escrow introduction".
  assert ((r1 +!+ Rdef (fun _ : natp_bot) gres_emp (eq_op^~ sigma)) +!+
          res_strip r2 Rundef).
    by desf; rewrite res_plusC, res_plusAC, <- res_plusA; auto with rpd.

  assert (ESE : a, ¬ In sigma EE L (TescS sigma a) = res_emp).
    by intros; apply LR; auto.

  assert (CC': compat amap sb rf (upd L (TsbS b)
                 (L (TsbS b) +!+ r1 +!+
                  Rdef (fun _ : natp_bot) gres_emp (eq_op^~ sigma) +!+ r2))).
  { rewrite (res_plusC _ r2).
    clarify; clear - NIN CC; repeat red; ins; eapply CC; eauto.
    revert H.
    destruct (classic (In (TsbS b) E)) as [C|C];
      [eapply In_NoDup_Permutation in C; desf;
       rewrite !(Permutation_rsum (Permutation_map _ C)); simpl; rewrite !upds|];
    rewrite !map_upd_irr; eauto.
    by rewrite !res_plusA, !(res_plusAC (Rdef _ _ _)); simpl; desf;
       rewrite ?gres_plusI, ?lift_plus_emp_l in ×.
  }

  eexists (upd L (TescS sigma b) (L (TescS sigma b) +!+ r2)),
          (if excluded_middle_informative (In sigma EE) then EE else sigma :: EE),
          ((r1 +!+ Rdef (fun _ : natp_bot) gres_emp (eq_op^~ sigma)) +!+ res_strip r2);
    split; try edone.
    by eapply RP_ext; eauto.
  repeat (match goal with |- _ _apply conj end;
          auto using in_eq, in_cons; try done); try (by intros; apply updo).
  clear - ESE NIN V; ins; specialize (V _ IN); unfold valid_node in *; desc.
  eexists r; ins.
  unfold incoming, out_esc, out_sb, out_rf, in_sb, in_rf, in_esc in *; ins.
  rewrite !map_upd_irr; try (by rewrite in_map_iff; intro; desf).
  unfold NW.

  repeat split;
    try by unfold upd; ins; desf; ins; try rewrite ESE, res_plus_emp_l; eauto.

  rupd; rewrite updC; try done; eapply compat_upd2_acc; try done.
  by rewrite !res_plusA, (res_plusC (res_strip r2)), res_plus_strip_idemp.

  clear - NIN CO; red; ins.
  unfold outgoing, out_sb, out_esc, out_rf; ins.
  rewrite !map_upd_irr; try (by rewrite in_map_iff; intro; desf).
  unfold upd; desf; eapply CO; ins.

  assert (DEF': L (TescS sigma b) +!+ r2 Rundef).
    subst; clear - ND' ESE VG; red in VG; unfold out_esc in *; desf; ins.
    revert VG0.
    destruct (classic (In sigma EE)) as [C|];
      [eapply In_NoDup_Permutation in C; desf;
       rewrite (Permutation_rsum (Permutation_map _ (Permutation_map _ C)))|
      rewrite ESE, res_plus_emp_l]; ins;
    try rewrite res_plusC; rewrite !res_plusA, <- (res_plusA r2), res_plusAC in *;
    intro X; rewrite X in *; ins.

  {
  clear CC'; ins.

  red; ins.

  destruct (eqP (te_src edge) b) as [|NEQ].
    destruct (classic (sigma = sigma0)) as [|X].
       by desc; b; clarify; rewrite mhbE; rupd; split; eauto;
          red; ins; rewrite EI in *; desf; eauto using RP_extC.

    assert (M: a,
              sat_exch IE sigma0 (L (TescS sigma0 a))
              (may_happens_before amap sb rf a b
               r : resource,
                 sat_exch IE sigma0 r
                 incoming (b :: acts) L a +!+ r Rundef
                  gl : nat,
                   res_gget r gl None
                   res_gget (incoming (b :: acts) L a) gl = None
                   res_gget (outgoing (b :: acts) (upd L (TsbS b) (L(TsbS b) +!+ r1 +!+ r2)) EE a)
                gl None)).
    { clear RINS DEF'; unfold upd in ESC; revert ESC; desf.
      intro.
        apply res_plus_eq_empD, proj1 in Osb; rewrite Osb, res_plus_emp_l in ×.
        rewrite res_plusA, res_plusAC in ESC.
        destruct edge; unfold te_src in *; try done.
        apply res_escr_plusE in ESC; ins; desf; desf.

      ins; exploit (ECO sigma0 (TsbS a)); rupd; eauto.
        eapply res_escr_plusI; ins; apply res_escr_plusE in ESC; ins; desf; eauto.
        by destruct r2; ins; eauto.
      by intro M; desc; revert M M0; rewrite !incoming_upd_irr; rupd; ins; eauto.

      intro.
        apply res_plus_eq_empD, proj1 in Osb; rewrite Osb, res_plus_emp_l in ×.
        destruct edge; unfold te_src in *; try done.
        apply res_escr_plusE in ESC; ins; desf; desf.

      by ins; destruct (ECO sigma0 (TescS sigma a)) as [? M]; desc;
         try revert M M0; rewrite ?incoming_upd_irr; rupd; ins; eauto.

      ins; destruct (ECO sigma0 (TsbS a)) as [? M];
      try revert M; rupd; eauto.
      by eapply res_escr_plusI; ins; desf; eauto.

      by rewrite ?incoming_upd_irr; eauto.

      ins; exploit (ECO sigma0 edge); eauto.
        by revert ESC; rupd; intro; desf.
      intros (a & M & M'); a; revert M M';
        rewrite ?incoming_upd_irr; rupd; ins.
    }

    desc; clarify; a; split; rupd; try congruence.
    clear RINS; des; eauto; right; rewrite !incoming_upd_irr; ins.
    edestruct M0 as [gl K]; eauto; desc; gl.
    repeat split; ins; rupd.
    rewrite outgoing_upd2_acc, !res_plusA, res_plus_strip_l, (res_plusC (Rdef _ _ _));
      ins; try (by desf; vauto).
    rewrite outgoing_upd_sbS, ?res_plusA, (outgoing_ee LR), !(res_plusAC (Rdef _ _ _)) in ×.
    desf; desf.
    by rewrite res_gget_plus; intro; desf;
       rewrite res_plusC in H0; apply res_plus_escr_def in H0; ins;
       intro XX; rewrite XX in *; ins.

  exploit (ECO sigma0 edge); eauto.
    by revert ESC; rupd; intro; desf.
  intros (a & M & M'); a; revert M M'; rewrite !incoming_upd_irr; ins.
  rewrite outgoing_upd2_acc; ins; try (by clear RINS; desf; vauto).
  split.
    by clear M'; revert M; unfold upd; des_if; eauto using sat_exch_ext.
  rupd; rewrite !res_plusA, res_plus_strip_l, (res_plusC (Rdef _ _ _)).
  rewrite outgoing_upd_sbS, (outgoing_ee LR) in ×.
  clear RINS; desf; desf; eauto.
  right; ins; exploit M'; eauto; intros [gl Z]; desc; gl; repeat split; ins.
  rewrite !res_plusA, !(res_plusAC (Rdef _ _ _)) in ×.
  by rewrite res_gget_plus; intro; desf;
     rewrite res_plusC in H0; apply res_plus_escr_def in H0; ins;
     intro XX; rewrite XX in *; ins.
  }

  rupd; clear RINS.
  eapply ghostalloc_upd2_acc; intros; clarify;
    try (by desf; eauto using in_eq, in_cons, NoDup).
  rewrite !res_plusA, res_plus_strip_l; subst.
  eapply ghost_alloc_conform_helper1.
    by desf; vauto.
    by instantiate (1 := L (TsbS b) +!+ r1 +!+ r2);
       desf; clear -LR GAC n; red in LR; desc;
       red; intros; eapply GAC; eauto;
       revert OUT OUT'; unfold outgoing, out_esc; simpl; rupd;
       rewrite !LRescS, !res_plus_emp_l; ins; vauto.
    intro; rewrite !ghost_allocE; intro X; desf.
    destruct (CC' (TsbS b :: nil));
      (try (by clear; ins; desf; rupd; rewrite ?res_plus_emp_r; vauto)).
    by ins; rupd; rewrite ?res_plus_emp_r; vauto.
    by right; rewrite (res_plusC _ r2), <- (res_plusA r1), <- res_plusA in X;
       rewrite res_gget_plus in X; apply not_or_and in X;
       destruct X as [_ X]; apply not_and_or in X; desf.
  by eapply helper_out_def; desf; eauto using NoDup, in_eq, lr_ext_esc.

  clear RINS.
  remember (b :: acts) as acts'; clear Heqacts'.
  unfold incoming, in_esc, in_sb, in_rf in *; ins.
  rewrite !map_upd_irr; try (by rewrite in_map_iff; intro; desf).
  unfold out_esc in *; ins; rupd.
  rewrite map_upd_irr with (l := map (Tesc b) acts');
    try (by rewrite in_map_iff; intro; desf).
  clarify.

  clear CC'.
  replace (rsum
       (map (upd L (TescS sigma b) (L (TescS sigma b) +!+ r2))
            (map (TescS^~ b)
                 (if excluded_middle_informative (In sigma EE)
                  then EE
                  else sigma :: EE))))
    with (r2 +!+ rsum (map L (map (TescS^~ b) EE))).
  2: desf; ins; rupd.
  2: rewrite replace_edge_ext; try apply nodup_map; try apply in_map_iff;
     eauto; congruence.
  2: rewrite map_upd_irr; try rewrite in_map_iff; try intro; desf.
  2: by red in LR; desc; rewrite LRescS, res_plus_emp_l; auto.
  rewrite !res_plusA in ×.
  rewrite (res_plusAC _ r1), (res_plusAC r2).
  rewrite <- (res_plusA r2), res_plus_strip_idemp.
  red in VG; desf; rewrite VG, VG0; ins; rewrite lift_plus_emp_l, gres_plusI; ins.
  do 7 eexists; ins; desf; eauto; try apply/orP; try rewrite VG1 in *; desf;
    eauto using eqxx.

  clarify; clear - H RS RDEF.
  rewrite incoming_upd_irr; ins.
  rewrite res_lt_strip_l, !res_strip_plus, !res_strip_idemp in *; ins.
    by rewrite res_plusA, res_plusAC; auto using res_lt_plus_l.
  by intro X; rewrite X in ×.

  by ins; rupd.

  by desf; vauto.

  by desf; vauto.

  by desf; auto using in_eq, lr_ext_esc.

Case "Escrow elimination 1".

  subst.

  edestruct (ECO sigma (TsbS b)) as (a & M & M'); rupd; eauto.
    by apply res_plus_eq_empD, proj1 in Osb; rewrite Osb, res_plus_emp_l in ×.
  rewrite updo in M; ins.
  rewrite incoming_upd_irr in M'; ins.

  assert (INS: In sigma EE).
    clear - M LR ESCR; apply NNPP; intro X.
    red in LR; desc; rewrite LRescS in M; auto.
    by apply sat_exch_emp in M.

  assert (INA: In a (b :: acts)).
    clear - M LR ESCR; apply NNPP; intro X.
    red in LR; desc; rewrite LRescS in M; auto.
    by apply sat_exch_emp in M.

  destruct (eqP a b) as [|NEQ]; subst.
  { clear M'.
    assert (DEF1: rE +!+ L (TsbS b) +!+ r0 +!+ L (TescS sigma b) Rundef).
      intro; destruct (CC (TsbS b :: TescS sigma b :: nil)); ins.
        by repeat constructor; ins; intro; desf.
        by desf.
      rupd; try congruence.
      revert H.
      rewrite res_plus_emp_r, (proj1 (res_plus_eq_empD _ _ Osb)), !res_plus_emp_l.
      by rewrite res_plusA.

    assert (DEF': (r0 +!+ res_strip rE) +!+ L (TescS sigma b) Rundef).
      intro X; apply DEF1; clear -X Osb.
      rewrite (proj1 (res_plus_eq_empD _ _ Osb)), res_plus_emp_l.
      rewrite res_plusA in X.
      by rewrite <- (res_plus_strip_idemp rE), !res_plusA, (res_plusAC r0),
                 X, res_plus_undef.

    eexists (upd L (TescS sigma b) rE),
            EE, ((r0 +!+ res_strip rE) +!+ L (TescS sigma b)).
    split; rupd.
      clear - DEF' DEF1 M GEL ESCR.
      rewrite <- !res_plusA, res_plusC, <- !res_plusA in DEF1.
      specialize (M _ _ ESCR); destruct GEL; desf.
      by destruct (@interp_exchOK1 IE sigma (L (TescS sigma b) +!+ rE));
         rewrite ESCR; ins; repeat eexists; ins; kundef.
      by eapply IN'; split; ins; do 3 eexists; eauto; split; eauto; kundef.
      by eapply IN'; split; ins; do 3 eexists; eauto; split; eauto; kundef.
      by destruct (@interp_exchOK2 IE sigma (L (TescS sigma b) +!+ rE));
         rewrite ESCR; ins; repeat eexists; ins; kundef.
    split; ins.
      by repeat apply valid_node_upd_irr; eauto; simpl; try intro; desf.
    split.
      rewrite updC, <- res_plusA; rupd; try (by intro; desf).
      by eapply compat_upd2_swap; ins; rewrite !res_plusA, res_plus_strip_l, (res_plusC r0).
    split.
      by red; unfold out_rf; ins; rewrite !map_upd_irr, !updo in *; ins;
         try (by rewrite in_map_iff; intro; desf); eapply CO.
    split.
      ins; rewrite updC, <- !res_plusA; rupd; ins.
      eapply exch_conform_upd2_swap; rupd; ins; desf.
      rewrite !res_plusA, res_plus_strip_l.
      rewrite updC; ins.
      rewrite (res_plusC r0 rE).
      eapply exch_conform_upd1_acc; eauto; ins; desf.
          by eauto using ghost_elim_sat_exch.
        by rewrite !(res_plusAC (res_strip rE)), <- res_plusA, res_plus_strip_l.
      clear; rewrite !(res_plusAC (res_strip rE)), <- res_plusA, res_plus_strip_l.
      by rewrite res_plusAC, <- !res_plusA, res_plusC, !res_plusA.
    split.
      rewrite updC, <- !res_plusA; rupd; ins.
      eapply ghostalloc_upd2_swap; rupd; ins; desf; try congruence.
      by rewrite !res_plusA, res_plus_strip_l, (res_plusC r0).
    inv ND.
    rewrite incoming_upd_irr; try done.
    rewrite out_esc_upd_in2; rupd; ins; try congruence.
    repeat (match goal with |- _ _split end; eauto 6 using in_eq, in_cons, pres_in_hb);
      ins; try by intros; rewrite ?updo; try intro; desf; eauto using in_eq.

    rewrite (res_plusC _ rE); rewrite !res_plusA in ×.
    rewrite !(res_plusAC rE), !(res_plusAC (L (TescS sigma b))).
    rewrite (res_plusAC (res_strip rE)), <- (res_plusA rE), res_plus_strip_idemp.
    by rewrite res_plusC, !res_plusA, <- out_esc_upd_in2, updI; ins.

    apply res_lt_plus_r.
    by rewrite res_lt_strip_l, res_strip_plus, res_strip_idemp in *; ins;
       try kundef; rewrite res_plusC.
  }


  assert (HB: happens_before amap sb rf a b).
  {
    rewrite outgoing_upd_irr in M'; ins; try congruence.
    rewrite mhbE in *; desf.
    inv ND;
    edestruct (compat_inc_sink)
    with (a := a) (b:= b)
         (L := upd L (TsbS b) (L (TsbS b) +!+ rE +!+ r0))
      as [|[|[|ZZZ]]];
    eauto using in_eq; desf.
    by exfalso; eauto using prefix_closed_hb.

    rewrite incoming_upd_irr, upds, !res_plusA, (res_plusAC r0) in ZZZ; ins.


    exploit (M' rE); clear M'; eauto using ghost_elim_sat_exch.
      by rewrite res_plusC; kundef.
    intro K; desc.
    exploit (visible_ghost2 CONS GAC CC (TsbS b) a gl); rupd; eauto using in_eq, in_cons;
      rewrite ?incoming_upd_irr, ?outgoing_upd_irr; ins; try congruence.
      rewrite (proj1 (res_plus_eq_empD _ _ Osb)), res_plus_emp_l in ×.
      by rewrite res_gget_plus; intro; desf.
    rewrite mhbE in *; desf.
  }
  clear M'.

  assert (DEF: L (TescS sigma a) +!+ (rE +!+ r0) +!+
                          out_esc (b :: acts) L EE b Rundef).
  {
    unfold out_esc.
    rewrite rsum_map_map_eq_empI with (l := b :: acts), res_plus_emp_r; ins.
    rewrite !res_plusA; intro Z.
    eapply CC with (E := (TescS sigma a :: TsbS b :: map (TescS^~ b) EE)).
      by repeat constructor; ins; try apply nodup_map; ins;
         try rewrite in_map_iff; try intro; desf.
      by ins; desf; ins; rewrite in_map_iff in *; desf; eauto.
    ins; rewrite upds, !updo; ins; try congruence.
    rewrite map_upd_irr; try (by rewrite in_map_iff; intro; desf).
    subst; eapply res_plus_eq_empD, proj1 in Osb.
    by rewrite Osb, res_plus_emp_l, !res_plusA.
  }

  ins; desf.

  assert (DEFi: L (TescS sigma a) +!+ incoming (b :: acts) L b Rundef).
     by desf; rewrite res_plusC; eapply helper_plus_inc_escS_def;
        eauto using compat_mon_upd.

  assert (MYDEF: (r0 +!+ res_strip rE) +!+ L (TescS sigma a) Rundef).
    rewrite res_plusC, <- res_plusA; apply res_plus_strip_def; rewrite res_plusA.
    by intro X; apply DEF; clear - X; rewrite <- res_plusA, (res_plusC rE);
       rewrite X.

  assert (VIS: gl,
            res_gget (incoming (b :: acts) L b) gl = None
            res_gget ((rE +!+ r0) +!+ out_esc (b :: acts) L EE b) gl None
            res_gget (L (TescS sigma a)) gl = None).
    ins; apply NNPP; intro K.
    exploit (visible_ghost2 CONS GAC CC (TescS sigma a) b gl); rupd; eauto using in_eq, in_cons;
      rewrite ?incoming_upd_irr, ?outgoing_upd_in; ins; try congruence.
      by unfold outgoing; rewrite Osb, Orf, !res_plus_emp_l, res_plusC.
    by eauto 3 using hb_irr, mhb_hb_trans.

  eexists (upd (upd (upd L (TescS sigma a) res_emp)
                    (Tesc a b) (L (TescS sigma a) +!+ L (Tesc a b)))
               (TescS sigma b) (L (TescS sigma b) +!+ rE)),
          EE, ((r0 +!+ res_strip rE) +!+ L (TescS sigma a)).
  split; desf.
      clear - MYDEF DEF M GEL ESCR.
      rewrite <- !res_plusA in DEF.
      specialize (M _ _ ESCR); destruct GEL; desf.
      by destruct (@interp_exchOK1 IE sigma (L (TescS sigma a) +!+ rE));
         rewrite ESCR; ins; repeat eexists; ins; kundef.
      by eapply IN'; split; ins; do 3 eexists; eauto; split; eauto; kundef.
      by eapply IN'; split; ins; do 3 eexists; eauto; split; eauto; kundef.
      by destruct (@interp_exchOK2 IE sigma (L (TescS sigma a) +!+ rE));
         rewrite ESCR; ins; repeat eexists; ins; kundef.
  split; ins.
  destruct (eqP a0 a); clarify.
  2: by repeat apply valid_node_upd_irr; eauto; simpl; try intro; desf.
  apply valid_node_upd_irr; ins.
  by apply valid_node_upd_esc; eauto using in_eq.

  split.
    rupd; rewrite updC; try (by intro; desf); eapply compat_upd2_acc; ins;
    rupd; try (by intro; desf).
    eapply compat_upd3; eauto; try done; rewrite ?M, ?res_plus_emp_l;
      auto using res_lt_plus_l, res_lt_refl, res_lt_emp_l;
      try congruence.
    by rewrite !res_plusA, !(res_plusAC (L (TescS sigma a))), (res_plusC _ rE),
               res_plus_strip_idemp, (res_plusC rE); apply res_lt_refl.

  split.
    by red; unfold out_rf; ins; rewrite !map_upd_irr, !updo in *; ins;
       try (by rewrite in_map_iff; intro; desf); eapply CO.

  split.
    ins; rupd.
    eapply exch_conform_upd2_acc; rupd; ins; try congruence.
    rewrite !res_plusA, <- (res_plusAC (res_strip rE)), res_plus_strip_l,
            (res_plusC (L (TescS sigma a)) rE), (res_plusAC rE).

    assert (DEF' : outgoing (b :: acts) L EE b +!+ rE +!+ r0 +!+ L (TescS sigma a) Rundef).
      rewrite <- !res_plusA, (res_plusA _ rE).
      unfold outgoing; rewrite Osb, Orf, !res_plus_emp_l.
      by rewrite (res_plusC _ (rE +!+ r0)), res_plusC.

    destruct (classic (sigma0 = sigma)).
    { red; ins; subst.
      clear ESC; b; split; rupd.

      rewrite res_plusC; eapply sat_exch_ext; ins; eauto using ghost_elim_sat_exch.
      intro X; apply DEF.
      rewrite res_plusA, (res_plusAC r0).
      unfold out_esc.
      eapply In_NoDup_Permutation in INS; desc; ins.
      rewrite !(Permutation_rsum (Permutation_map _ (Permutation_map _ INS)));
      ins.
      by rewrite res_plusA, <- (res_plusA rE), X; ins; rewrite ?res_plus_undef.

      rewrite incoming_upd_irr, updC, incoming_upd_irr, res_plusC, incoming_upd_in,
              <- res_plusA, <- incoming_upd_in, updI; ins; auto.
      rewrite outgoing_upd_in, 2!outgoing_upd_irr; rupd; ins; desf; try congruence.
      right; ins.
      rewrite res_plusA in IDEF.
      rewrite <- !res_plusA, (res_plusA _ rE).
      unfold outgoing; rewrite Osb, Orf, !res_plus_emp_l, (res_plusC _ (rE +!+ r0)).
      eapply valid_ghost_gget; ins.
        apply NNPP; intro K.
        exploit (visible_ghost2 CONS GAC CC (TescS sigma a) b m); rupd; eauto using in_eq, in_cons;
          rewrite ?incoming_upd_irr, ?outgoing_upd_in; ins; try congruence.
          by unfold outgoing; rewrite Osb, Orf, !res_plus_emp_l, res_plusC.
        by eauto 3 using hb_irr, mhb_hb_trans.
      by rewrite res_plusC.

      rewrite res_plusC, <- !res_plusA.
      assert (X := three_sat_exch M SE (ghost_elim_sat_exch _ _ ESCR GEL)).
      by rewrite <- res_plusA in X; rewrite X.
    }
 
    assert (DEF'' : L (TescS sigma b) +!+ rE +!+ L (TsbS b) +!+ r0 +!+
                      res_strip rE +!+ L (TescS sigma a) Rundef).
    { clear - DEF INS ND' Osb.
      rewrite (proj1 (res_plus_eq_empD _ _ Osb)), res_plus_emp_l.
      rewrite (res_plusAC (res_strip rE)), <- (res_plusA rE), res_plus_strip_idemp.
      rewrite <- (res_plusA rE), res_plusAC, <- res_plusA, res_plusC, <- !res_plusA.
      intro X; apply DEF.
      eapply In_NoDup_Permutation in INS; desc; ins; unfold out_esc.
      rewrite !(Permutation_rsum (Permutation_map _ (Permutation_map _ INS))).
      by ins; rewrite <- !res_plusA, X; ins.
    }
    eapply exch_conform_upd1_acc; rupd; ins; try rewrite res_plusA; ins;
    try congruence.
    rewrite updC; ins; eapply exch_conform_irr1; ins.
    rewrite res_plusAC, (res_plusAC (res_strip rE)),
            <- (res_plusA rE), res_plus_strip_idemp.
    eapply exch_conform_upd3 with
      (r4 := L (TescS sigma a))
      (rr := L (TsbS b) +!+ rE +!+ r0);
      try rewrite res_plus_emp_l; ins; desf; eauto using res_plusC.
    2: by rewrite !res_plusA.
    2: by rewrite outgoing_upd_in, !res_plusA; ins.
    2: by rewrite outgoing_upd_in, res_plusC in M2; ins;
          unfold outgoing in M2; rewrite Osb, Orf, !res_plus_emp_l in M2; eauto.
    {
      rewrite <- (res_plusA rE), <- res_plusA.
      red; ins; rupd; unfold upd in ESC; desf; [eapply res_escr_plus in ESC; desf|].
      3: by rewrite (proj1 (res_plus_eq_empD _ _ Osb)), res_plus_emp_l, res_plusA; kundef.
      × edestruct (ECO sigma0 (TsbS b)) as [a' Z]; rupd; ins.
         a'; revert Z; rupd; congruence.
      × edestruct (ECO sigma0 (TescS sigma a)) as [a' Z]; rupd; ins.
         a'; revert Z; rupd; try congruence; ins; des; split;
        eauto using mhb_trans, hb_mhb.
      × edestruct (ECO sigma0 edge) as [a' Z]; rupd; ins.
         a'; revert Z; rupd; congruence.
    }

  split.
  { eapply ghostalloc_upd2_acc; rupd; ins; try congruence.
    eapply ghostalloc_upd3; eauto; rewrite ?res_plus_emp_l; ins; desf; eauto using res_plusC.
      by rewrite res_plusC, !res_plusA, res_plusAC,
            (res_plusAC (res_strip rE)), <- (res_plusA rE), res_plus_strip_idemp.
    rewrite outgoing_upd_in; unfold outgoing; ins; rewrite Osb, Orf, !res_plus_emp_l.
    by rewrite res_plusC, res_plusA, res_plusAC, <- res_plusA in DEF.
  }
  inv ND.
  revert VG DEF.
  rewrite incoming_upd_irr, updC, incoming_upd_irr; try done.
  rewrite incoming_upd_ext_esc; ins; eauto using pres_in_hb.
  rewrite out_esc_upd_in, !out_esc_upd_irr; rupd; ins; try congruence.
  repeat (match goal with |- _ _split end; eauto 6 using in_eq, in_cons, pres_in_hb);
    ins; try by intros; rewrite !updo; try intro; desf; eauto.
  {
    rewrite (res_plusC _ rE); rewrite !res_plusA in ×.
    rewrite !(res_plusAC rE), !(res_plusAC (L (TescS sigma a))).
    rewrite (res_plusAC (res_strip rE)), <- (res_plusA rE), res_plus_strip_idemp.
    red in VG; desc; rewrite VG in ×.
    destruct (L (TescS sigma a)); ins; desf.
    do 7 eexists; ins; unnw.
    clear - VIS Heq Heq0 VGG.
    ins; unfold gres_plus in *; repeat des_eqrefl; desf; ins.
    inv_lplus gl; specialize (VIS gl); specialize (VGG gl); rewrite RG in ×.
    destruct (gres gl) as [[A gg]|]; ins; desf; eauto;
    try specialize (VGG _ eq_refl); desf; ins;
    try (by exploit VIS);
    try rewrite <- H1; try rewrite <- H0; eauto.
    eexists; split; ins.
    by case_eq (salg_plus A s0 fr) as N;
       rewrite salg_plusC in Heq1, Heq3; eapply salg_plusA in N; eauto;
       desf; rewrite VGG0 in N; ins; eapply salg_plusA2 in SPN; eauto; desf.
  }
  rewrite res_plusC.
  rewrite res_lt_strip_l in *; apply res_lt_strip_frame.
  2: by rewrite res_plusC.
  rewrite res_plusC; revert RS; rewrite !res_strip_plus, res_strip_idemp; ins.
  by rewrite res_plusC; intro X; rewrite X in *; desf.
Qed.


This page has been generated by coqdoc