Notation CoreSem Sem :=(semantics.csem(event_semantics.msem (semSem Sem))).
Inductive match_thread_source:
meminj -> @ctl (state_sum (semC Sems) (semC Semt)) -> mem -> @ctl (state_sum (semC Sems) (semC Semt)) -> mem -> Prop  :=
| SThread_Running: forall j code1 m1 code2 m2,
source_match j code1 m1 code2 m2 ->
match_thread_source
j (Krun (SState _ _ code1)) m1
(Krun (SState _ _ code2)) m2
| SThread_Blocked: forall j code1 m1 code2 m2 ls1 ls2 f f',
semantics.at_external (CoreSem Sems) genvS code1 m1 = Some (f,ls1) ->
semantics.at_external (CoreSem Sems) genvS code2 m2 = Some (f',ls2) ->
Val.inject_list j ls1 ls2 ->
source_match j code1 m1 code2 m2 ->
match_thread_source  j (Kblocked (SState _ _ code1)) m1
(Kblocked (SState _ _ code2)) m2
| SThread_Resume: forall j code1 m1 code2 m2 ls1 ls2 f f' v v' code1' code2',
(*Do I need to keep this two? Probanly not*)
semantics.at_external (CoreSem Sems) genvS code1 m1 = Some (f,ls1) ->
semantics.at_external (CoreSem Sems) genvS code2 m2 = Some (f',ls2) ->
Val.inject_list j ls1 ls2 ->
semantics.after_external (CoreSem Sems) genvS None code1 = Some code1' ->
semantics.after_external (CoreSem Sems) genvS None code2 = Some code2' ->
source_match j code1' m2 code2' m2 ->
match_thread_source j (Kresume (SState _ _ code1) v) m1
(Kresume (SState _ _ code2) v') m2
| SThread_Init: forall j m1 m2 v1 v1' v2 v2',
Val.inject j v1 v2 ->
Val.inject j v1' v2' ->
match_thread_source j (Kinit v1 v1') m1
(Kinit v2 v2') m2.
Inductive match_thread_target :
meminj -> @ctl (state_sum (semC Sems) (semC Semt)) -> mem -> @ctl (state_sum (semC Sems) (semC Semt)) -> mem -> Prop  :=
| TThread_Running: forall j code1 m1 code2 m2,
target_match j code1 m1 code2 m2 ->
match_thread_target  j (Krun (TState _ _ code1)) m1
(Krun (TState _ _ code2)) m2
| TThread_Blocked: forall j code1 m1 code2 m2 ls1 ls2 f f',
semantics.at_external (CoreSem Semt) genvT code1 m1 = Some (f,ls1) ->
semantics.at_external (CoreSem Semt) genvT code2 m2 = Some (f',ls2) ->
Val.inject_list j ls1 ls2 ->
target_match j code1 m1 code2 m2 ->
match_thread_target j (Kblocked (TState _ _ code1)) m1
(Kblocked (TState _ _ code2)) m2
| TThread_Resume: forall j code1 m1 code2 m2 ls1 ls2 f f' v v' code1' code2',
(*Do I need to keep this two? Probanly not*)
semantics.at_external (CoreSem Semt) genvT code1 m1 = Some (f,ls1) ->
semantics.at_external (CoreSem Semt) genvT code2 m2 = Some (f',ls2) ->
Val.inject_list j ls1 ls2 ->
semantics.after_external (CoreSem Semt) genvT None code1 = Some code1' ->
semantics.after_external (CoreSem Semt) genvT None code2 = Some code2' ->
target_match j code1' m2 code2' m2 ->
match_thread_target j (Kresume (TState _ _ code1) v) m1
(Kresume (TState _ _ code2) v') m2
| TThread_Init: forall j m1 m2 v1 v1' v2 v2',
Val.inject j v1 v2 ->
Val.inject j v1' v2' ->
match_thread_target j (Kinit v1 v1') m1
(Kinit v2 v2') m2.
(* match_compiled_states *)
Inductive match_thread_compiled:
compiler_index -> meminj ->
@ctl (state_sum (semC Sems) (semC Semt)) -> mem ->
@ctl (state_sum (semC Sems) (semC Semt)) -> mem -> Prop  :=
| CThread_Running: forall cd j code1 m1 code2 m2,
match_compiled_states cd j code1 m1 code2 m2 ->
match_thread_compiled cd j (Krun (SState _ _ code1)) m1
(Krun (TState _ _ code2)) m2
| CThread_Blocked: forall cd j code1 m1 code2 m2 ls1 ls2 f f',
semantics.at_external (CoreSem Sems) genvS code1 m1  = Some (f,ls1) ->
semantics.at_external (CoreSem Semt) genvT code2 m2 = Some (f',ls2) ->
Val.inject_list j ls1 ls2 ->
match_compiled_states cd j code1 m1 code2 m2 ->
match_thread_compiled  cd j (Kblocked (SState _ _ code1)) m1
(Kblocked (TState _ _ code2)) m2
| CThread_Resume: forall cd j code1 m1 code2 m2 ls1 ls2 f f' v v' code1' code2',
(*Do I need to keep this two? Probanly not*)
semantics.at_external (CoreSem Sems) genvS code1 m1 = Some (f,ls1) ->
semantics.at_external (CoreSem Semt) genvT code2 m2 = Some (f',ls2) ->
Val.inject_list j ls1 ls2 ->
semantics.after_external (CoreSem Sems) genvS None code1 = Some code1' ->
semantics.after_external (CoreSem Semt) genvT None code2 = Some code2' ->
match_compiled_states cd j code1' m1 code2' m2 ->
match_thread_compiled cd j (Kresume (SState _ _ code1) v) m1
(Kresume (TState _ _ code2) v') m2
| CThread_Init: forall cd j m1 m2 v1 v1' v2 v2',
Val.inject j v1 v2 ->
Val.inject j v1' v2' ->
match_thread_compiled cd j (Kinit v1 v1') m1
(Kinit v2 v2') m2.
Definition FST {A B} (HH : A /\ B):=
fst (ssrfun.pair_of_and HH).
Definition SND {A B} (HH : A /\ B):=
snd (ssrfun.pair_of_and HH).
(* Definition FST {A B} (HH : A /\ B) : A:= match HH with | conj H _ => H end. *)
Record concur_match (ocd: option compiler_index)
(j:meminj) (cstate1: C1) (m1: mem) (cstate2: C2) (m2: mem):=
{ same_length: num_threads cstate1 = num_threads cstate2
; memcompat1: HybridMachine.mem_compatible _ _ _ cstate1 m1
; memcompat2: HybridMachine.mem_compatible _ _ _ cstate2 m2
; mtch_source:
forall (i:nat),
(i > hb')%nat ->
forall (cnti1: containsThread cstate1 i)
(cnti2: containsThread cstate2 i),
match_thread_source  j
(getThreadC cnti1)
(restrPermMap (FST (memcompat1 i cnti1)))
(getThreadC cnti2)
(restrPermMap (FST (memcompat2 i cnti2)))
; mtch_target:
forall (i:nat),
(i < hb')%nat ->
forall (cnti1: containsThread cstate1 i)
(cnti2: containsThread cstate2 i),
match_thread_target  j
(getThreadC cnti1)
(restrPermMap (FST(memcompat1 i cnti1)))
(getThreadC cnti2)
(restrPermMap (FST(memcompat2 i cnti2)))
; mtch_compiled:
forall (i:nat),
(i = hb')%nat ->
forall (cnti1: containsThread cstate1 i)
(cnti2: containsThread cstate2 i),
exists cd, ocd = Some cd /\
match_thread_compiled cd j
(getThreadC cnti1)
(restrPermMap (FST(memcompat1 i cnti1)))
(getThreadC cnti2)
(restrPermMap (FST(memcompat2 i cnti2))) }.

(* Specifications: *)
Lemma contains12:
forall {data j cstate1 m1 cstate2 m2},
concur_match data j cstate1 m1 cstate2 m2 ->
forall {i:nat} (cnti1: containsThread cstate1 i),
containsThread cstate2 i.
Lemma contains21:
forall {data j cstate1 m1 cstate2 m2},
concur_match data j cstate1 m1 cstate2 m2 ->
forall {i:nat} (cnti1: containsThread cstate2 i),
containsThread cstate1 i.