Definition ogetBlock (ov : option val) : block -> bool :=
  match ov with
    | None => fun _:block => false
    | Some v => getBlocks (v::nil)
  end.Inductive match_event : Event.t -> Event.t -> Prop :=
| mk_match_event :
  forall j j' ev1 ev2,
  let args1 := ev1.(args) in
  let args2 := ev2.(args) in
  let rv1 := ev1.(rv) in
  let rv2 := ev2.(rv) in
  let m1 := ev1.(pre_mem) in
  let m1' := ev1.(post_mem) in
  let m2 := ev2.(pre_mem) in
  let m2' := ev2.(post_mem) in
  inject_incr (as_inj j) (as_inj j') ->
  Mem.inject (as_inj j) m1 m2 ->
  Mem.inject (as_inj j') m1' m2' ->
  Forall2 (val_inject (as_inj j)) args1 args2 ->
  oval_inject (as_inj j') rv1 rv2 ->
  match_event ev1 ev2.Inductive match_event : Event.t -> Event.t -> Prop :=
| mk_match_event :
  forall j j' ev1 ev2,
  let args1 := ev1.(args) in
  let args2 := ev2.(args) in
  let rv1 := ev1.(rv) in
  let rv2 := ev2.(rv) in
  let m1 := ev1.(pre_mem) in
  let m1' := ev1.(post_mem) in
  let m2 := ev2.(pre_mem) in
  let m2' := ev2.(post_mem) in
  inject_incr (as_inj j) (as_inj j') ->
  Mem.inject (as_inj j) m1 m2 ->
  Mem.inject (as_inj j') m1' m2' ->
  Forall2 (val_inject (as_inj j)) args1 args2 ->
  oval_inject (as_inj j') rv1 rv2 ->
  match_event ev1 ev2.Inductive match_event : Event.t -> Event.t -> Prop :=
| mk_match_event :
  forall j j' ev1 ev2,
  let args1 := ev1.(args) in
  let args2 := ev2.(args) in
  let rv1 := ev1.(rv) in
  let rv2 := ev2.(rv) in
  let m1 := ev1.(pre_mem) in
  let m1' := ev1.(post_mem) in
  let m2 := ev2.(pre_mem) in
  let m2' := ev2.(post_mem) in
  inject_incr (as_inj j) (as_inj j') ->
  Mem.inject (as_inj j) m1 m2 ->
  Mem.inject (as_inj j') m1' m2' ->
  Forall2 (val_inject (as_inj j)) args1 args2 ->
  oval_inject (as_inj j') rv1 rv2 ->
  match_event ev1 ev2.Inductive match_event : Event.t -> Event.t -> Prop :=
| mk_match_event :
  forall j j' ev1 ev2,
  let args1 := ev1.(args) in
  let args2 := ev2.(args) in
  let rv1 := ev1.(rv) in
  let rv2 := ev2.(rv) in
  let m1 := ev1.(pre_mem) in
  let m1' := ev1.(post_mem) in
  let m2 := ev2.(pre_mem) in
  let m2' := ev2.(post_mem) in
  inject_incr (as_inj j) (as_inj j') ->
  Mem.inject (as_inj j) m1 m2 ->
  Mem.inject (as_inj j') m1' m2' ->
  Forall2 (val_inject (as_inj j)) args1 args2 ->
  oval_inject (as_inj j') rv1 rv2 ->
  match_event ev1 ev2.Inductive match_event : Event.t -> Event.t -> Prop :=
| mk_match_event :
  forall j j' ev1 ev2,
  let args1 := ev1.(args) in
  let args2 := ev2.(args) in
  let rv1 := ev1.(rv) in
  let rv2 := ev2.(rv) in
  let m1 := ev1.(pre_mem) in
  let m1' := ev1.(post_mem) in
  let m2 := ev2.(pre_mem) in
  let m2' := ev2.(post_mem) in
  inject_incr (as_inj j) (as_inj j') ->
  Mem.inject (as_inj j) m1 m2 ->
  Mem.inject (as_inj j') m1' m2' ->
  Forall2 (val_inject (as_inj j)) args1 args2 ->
  oval_inject (as_inj j') rv1 rv2 ->
  match_event ev1 ev2.Inductive match_event : Event.t -> Event.t -> Prop :=
| mk_match_event :
  forall j j' ev1 ev2,
  let args1 := ev1.(args) in
  let args2 := ev2.(args) in
  let rv1 := ev1.(rv) in
  let rv2 := ev2.(rv) in
  let m1 := ev1.(pre_mem) in
  let m1' := ev1.(post_mem) in
  let m2 := ev2.(pre_mem) in
  let m2' := ev2.(post_mem) in
  inject_incr (as_inj j) (as_inj j') ->
  Mem.inject (as_inj j) m1 m2 ->
  Mem.inject (as_inj j') m1' m2' ->
  Forall2 (val_inject (as_inj j)) args1 args2 ->
  oval_inject (as_inj j') rv1 rv2 ->
  match_event ev1 ev2.Inductive match_event : Event.t -> Event.t -> Prop :=
| mk_match_event :
  forall j j' ev1 ev2,
  let args1 := ev1.(args) in
  let args2 := ev2.(args) in
  let rv1 := ev1.(rv) in
  let rv2 := ev2.(rv) in
  let m1 := ev1.(pre_mem) in
  let m1' := ev1.(post_mem) in
  let m2 := ev2.(pre_mem) in
  let m2' := ev2.(post_mem) in
  inject_incr (as_inj j) (as_inj j') ->
  Mem.inject (as_inj j) m1 m2 ->
  Mem.inject (as_inj j') m1' m2' ->
  Forall2 (val_inject (as_inj j)) args1 args2 ->
  oval_inject (as_inj j') rv1 rv2 ->
  match_event ev1 ev2.Inductive match_event : Event.t -> Event.t -> Prop :=
| mk_match_event :
  forall j j' ev1 ev2,
  let args1 := ev1.(args) in
  let args2 := ev2.(args) in
  let rv1 := ev1.(rv) in
  let rv2 := ev2.(rv) in
  let m1 := ev1.(pre_mem) in
  let m1' := ev1.(post_mem) in
  let m2 := ev2.(pre_mem) in
  let m2' := ev2.(post_mem) in
  inject_incr (as_inj j) (as_inj j') ->
  Mem.inject (as_inj j) m1 m2 ->
  Mem.inject (as_inj j') m1' m2' ->
  Forall2 (val_inject (as_inj j)) args1 args2 ->
  oval_inject (as_inj j') rv1 rv2 ->
  match_event ev1 ev2.Inductive match_event : Event.t -> Event.t -> Prop :=
| mk_match_event :
  forall j j' ev1 ev2,
  let args1 := ev1.(args) in
  let args2 := ev2.(args) in
  let rv1 := ev1.(rv) in
  let rv2 := ev2.(rv) in
  let m1 := ev1.(pre_mem) in
  let m1' := ev1.(post_mem) in
  let m2 := ev2.(pre_mem) in
  let m2' := ev2.(post_mem) in
  inject_incr (as_inj j) (as_inj j') ->
  Mem.inject (as_inj j) m1 m2 ->
  Mem.inject (as_inj j') m1' m2' ->
  Forall2 (val_inject (as_inj j)) args1 args2 ->
  oval_inject (as_inj j') rv1 rv2 ->
  match_event ev1 ev2.Inductive match_event : Event.t -> Event.t -> Prop :=
| mk_match_event :
  forall j j' ev1 ev2,
  let args1 := ev1.(args) in
  let args2 := ev2.(args) in
  let rv1 := ev1.(rv) in
  let rv2 := ev2.(rv) in
  let m1 := ev1.(pre_mem) in
  let m1' := ev1.(post_mem) in
  let m2 := ev2.(pre_mem) in
  let m2' := ev2.(post_mem) in
  inject_incr (as_inj j) (as_inj j') ->
  Mem.inject (as_inj j) m1 m2 ->
  Mem.inject (as_inj j') m1' m2' ->
  Forall2 (val_inject (as_inj j)) args1 args2 ->
  oval_inject (as_inj j') rv1 rv2 ->
  match_event ev1 ev2.Inductive match_trace : list Event.t -> list Event.t -> Prop :=
| match_trace_nil : match_trace nil nil
| match_trace_cons :
  forall tr1 tr2 ev1 ev2,
  match_event ev1 ev2 ->
  match_trace tr1 tr2 ->
  match_trace (ev1 :: tr1) (ev2 :: tr2).Inductive match_trace : list Event.t -> list Event.t -> Prop :=
| match_trace_nil : match_trace nil nil
| match_trace_cons :
  forall tr1 tr2 ev1 ev2,
  match_event ev1 ev2 ->
  match_trace tr1 tr2 ->
  match_trace (ev1 :: tr1) (ev2 :: tr2).Inductive match_trace : list Event.t -> list Event.t -> Prop :=
| match_trace_nil : match_trace nil nil
| match_trace_cons :
  forall tr1 tr2 ev1 ev2,
  match_event ev1 ev2 ->
  match_trace tr1 tr2 ->
  match_trace (ev1 :: tr1) (ev2 :: tr2).Notation data := (sim.(SM_simulation.core_data _ _ _ _ _)).Notation ord  := (sim.(SM_simulation.core_ord _ _ _ _ _)).Notation match_state := (sim.(SM_simulation.match_state _ _ _ _ _)).Inductive trace_match_state :
  data -> SM_Injection -> Z*list Event.t*C -> mem ->
                          Z*list Event.t*D -> mem -> Prop :=
| mk_trace_match_state :
  forall j tr z c m ttr d tm cd,
  match_trace tr ttr ->
  match_state cd j c m d tm ->
  trace_match_state cd j (z,tr,c) m (z,ttr,d) tm.Inductive trace_match_state :
  data -> SM_Injection -> Z*list Event.t*C -> mem ->
                          Z*list Event.t*D -> mem -> Prop :=
| mk_trace_match_state :
  forall j tr z c m ttr d tm cd,
  match_trace tr ttr ->
  match_state cd j c m d tm ->
  trace_match_state cd j (z,tr,c) m (z,ttr,d) tm.

Lemma REACH_as_inj_REACH': forall mu (WD: SM_wd mu) m1 m2 vals1 vals2 (MemInjMu : Mem.inject (as_inj mu) m1 m2) (ValInjMu : Forall2 (val_inject (as_inj mu)) vals1 vals2) b1 (R : REACH m1 (getBlocks vals1) b1 = true), exists b2 d, as_inj mu b1 = Some (b2, d) /\ REACH m2 (getBlocks vals2) b2 = true.