Theory J1

Up to index of Isabelle/HOL/JinjaThreads

theory J1
imports J0

(*  Title:      JinjaThreads/Compiler/J1.thy
    Author:     Andreas Lochbihler
*)

header {* \isaheader{An intermediate language} *}

theory J1 imports "J0" begin

types
  expr1 = "(nat,nat) exp"
  J1_prog = "expr1 prog"

  locals1 = "val list"

translations
  "expr1" <= (type) "(nat, nat) exp"
  "J1_prog" <= (type) "expr1 prog"

types
  J1state = "(expr1 × locals1) list"

types
  J1_thread_action = "(addr,thread_id,(expr1 × locals1) × (expr1 × locals1) list,heap,addr,obs_event option) thread_action"

translations
  "J1_thread_action" <= (type) "(nat,nat,(expr1 × val list) × (expr1 × val list) list,heap,nat,obs_event option) thread_action"


primrec max_vars:: "('a,'b) exp => nat"
  and max_varss:: "('a,'b) exp list => nat"
where
  "max_vars (new C) = 0"
| "max_vars (newA T⌊e⌉) = max_vars e"
| "max_vars (Cast C e) = max_vars e"
| "max_vars (Val v) = 0"
| "max_vars (e «bop» e') = max (max_vars e) (max_vars e')"
| "max_vars (Var V) = 0"
| "max_vars (V:=e) = max_vars e"
| "max_vars (a⌊i⌉) = max (max_vars a) (max_vars i)"
| "max_vars (AAss a i e) = max (max (max_vars a) (max_vars i)) (max_vars e)"
| "max_vars (a•length) = max_vars a"
| "max_vars (e•F{D}) = max_vars e"
| "max_vars (FAss e1 F D e2) = max (max_vars e1) (max_vars e2)"
| "max_vars (e•M(es)) = max (max_vars e) (max_varss es)"
| "max_vars ({V:T=vo; e}) = max_vars e + 1"
(* sync and insync will need an extra local variable when compiling to bytecode to store the object that is being synchronized on until its release *)
| "max_vars (syncV (e') e) = max (max_vars e') (max_vars e + 1)"
| "max_vars (insyncV (a) e) = max_vars e + 1"
| "max_vars (e1;;e2) = max (max_vars e1) (max_vars e2)"
| "max_vars (if (e) e1 else e2) =
   max (max_vars e) (max (max_vars e1) (max_vars e2))"
| "max_vars (while (b) e) = max (max_vars b) (max_vars e)"
| "max_vars (throw e) = max_vars e"
| "max_vars (try e1 catch(C V) e2) = max (max_vars e1) (max_vars e2 + 1)"

| "max_varss [] = 0"
| "max_varss (e#es) = max (max_vars e) (max_varss es)"

lemma max_varss_append [simp]:
  "max_varss (es @ es') = max (max_varss es) (max_varss es')"
by(induct es, auto)

lemma max_varss_map_Val [simp]: "max_varss (map Val vs) = 0"
by(induct vs) auto

lemma max_vars_inline_call: "max_vars (inline_call e' e) ≤ max_vars e + max_vars e'"
  and max_varss_inline_calls: "max_varss (inline_calls e' es) ≤ max_varss es + max_vars e'"
by(induct e and es) auto

definition extNTA2J1 :: "J1_prog => (cname × mname × addr) => ((expr1 × locals1) × (expr1 × locals1) list)"
where
  "extNTA2J1 P = (λ(C, M, a). let (D, _, _, body) = method P C M
                              in (({0:Class D=None; body}, Addr a # replicate (max_vars body) undefined), [(addr a•M([]), [])]))"

lemma extNTA2J1_iff [simp]:
  "extNTA2J1 P (C, M, a) = (({0:Class (fst (method P C M))=None; snd (snd (snd (method P C M)))}, Addr a # replicate (max_vars (snd (snd (snd (method P C M))))) undefined), [(addr a•M([]), [])])"
by(simp add: extNTA2J1_def split_beta)

abbreviation extTA2J1 :: "J1_prog => external_thread_action => J1_thread_action"
where "extTA2J1 P ≡ convert_extTA (extNTA2J1 P)"

abbreviation (input) extRet2J1 :: "val + addr => expr1"
where "extRet2J1 ≡ extRet2J"

lemma max_vars_extRet2J1 [simp]: 
  "max_vars (extRet2J1 va) = 0"
by(cases va) simp_all

inductive red1 :: "J1_prog => expr1 => heap × locals1 => external_thread_action => expr1 => heap × locals1 => bool"
                 ("_ \<turnstile>1 ((1⟨_,/_⟩) -_->/ (1⟨_,/_⟩))" [51,0,0,0,0,0] 81)
  and reds1 :: "J1_prog => expr1 list => heap × locals1 => external_thread_action => expr1 list => heap × locals1 => bool"
                 ("_ \<turnstile>1 ((1⟨_,/_⟩) [-_->]/ (1⟨_,/_⟩))" [51,0,0,0,0,0] 81)
for P :: J1_prog
where
  Red1New:
  "[| new_Addr h = Some a; P \<turnstile> C has_fields FDTs; h' = h(a\<mapsto>(Obj C (init_fields FDTs))) |]
  ==> P \<turnstile>1 ⟨new C, (h, l)⟩ -ε-> ⟨addr a, (h', l)⟩"

| Red1NewFail:
  "new_Addr (hp s) = None
  ==> P \<turnstile>1 ⟨new C, s⟩ -ε-> ⟨THROW OutOfMemory, s⟩"

| New1ArrayRed:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩
  ==> P \<turnstile>1 ⟨newA T⌊e⌉, s⟩ -ta-> ⟨newA T⌊e'⌉, s'⟩"

| Red1NewArray:
  "[| new_Addr h = Some a; i ≥ 0; h' = h(a \<mapsto> (Arr T (replicate (nat i) (default_val T)))) |]
  ==> P \<turnstile>1 ⟨newA T⌊Val (Intg i)⌉, (h, l)⟩ -ε-> ⟨addr a, (h', l)⟩"

| Red1NewArrayNegative:
  "i < 0 ==> P \<turnstile>1 ⟨newA T⌊Val (Intg i)⌉, s⟩ -ε-> ⟨THROW NegativeArraySize, s⟩"

| Red1NewArrayFail:
  "[| new_Addr h = None; i ≥ 0 |]
  ==> P \<turnstile>1 ⟨newA T⌊Val (Intg i)⌉, (h, l)⟩ -ε-> ⟨THROW OutOfMemory, (h, l)⟩"

| Cast1Red:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩
  ==> P \<turnstile>1 ⟨Cast C e, s⟩ -ta-> ⟨Cast C e', s'⟩"

| Red1Cast:
 "[| typeofhp s v = ⌊U⌋; P \<turnstile> U ≤ T |]
  ==> P \<turnstile>1 ⟨Cast T (Val v), s⟩ -ε-> ⟨Val v, s⟩"

| Red1CastFail:
  "[| typeofhp s v = ⌊U⌋; ¬ P \<turnstile> U ≤ T |]
  ==> P \<turnstile>1 ⟨Cast T (Val v), s⟩ -ε-> ⟨THROW ClassCast, s⟩"

| Bin1OpRed1:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> P \<turnstile>1 ⟨e «bop» e2, s⟩ -ta-> ⟨e' «bop» e2, s'⟩"

| Bin1OpRed2:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> P \<turnstile>1 ⟨(Val v) «bop» e, s⟩ -ta-> ⟨(Val v) «bop» e', s'⟩"

| Red1BinOp:
  "binop bop v1 v2 = Some v ==>
  P \<turnstile>1 ⟨(Val v1) «bop» (Val v2), s⟩ -ε-> ⟨Val v, s⟩"

| Red1Var:
  "[| (lcl s)!V = v; V < size (lcl s) |]
  ==> P \<turnstile>1 ⟨Var V, s⟩ -ε-> ⟨Val v, s⟩"

| LAss1Red:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩
  ==> P \<turnstile>1 ⟨V:=e, s⟩ -ta-> ⟨V:=e', s'⟩"

| Red1LAss:
  "V < size l
  ==> P \<turnstile>1 ⟨V:=(Val v), (h, l)⟩ -ε-> ⟨unit, (h, l[V := v])⟩"

| AAcc1Red1:
  "P \<turnstile>1 ⟨a, s⟩ -ta-> ⟨a', s'⟩ ==> P \<turnstile>1 ⟨a⌊i⌉, s⟩ -ta-> ⟨a'⌊i⌉, s'⟩"

| AAcc1Red2:
  "P \<turnstile>1 ⟨i, s⟩ -ta-> ⟨i', s'⟩ ==> P \<turnstile>1 ⟨(Val a)⌊i⌉, s⟩ -ta-> ⟨(Val a)⌊i'⌉, s'⟩"

| Red1AAccNull:
  "P \<turnstile>1 ⟨null⌊Val i⌉, s⟩ -ε-> ⟨THROW NullPointer, s⟩"

| Red1AAccBounds:
  "[| hp s a = Some(Arr T el); i < 0 ∨ i ≥ int (length el) |]
  ==> P \<turnstile>1 ⟨(addr a)⌊Val (Intg i)⌉, s⟩ -ε-> ⟨THROW ArrayIndexOutOfBounds, s⟩"

| Red1AAcc:
  "[| hp s a = Some(Arr T el); i ≥ 0; i < int (length el) |]
  ==> P \<turnstile>1 ⟨(addr a)⌊Val (Intg i)⌉, s⟩ -ε-> ⟨Val (el ! nat i), s⟩"

| AAss1Red1:
  "P \<turnstile>1 ⟨a, s⟩ -ta-> ⟨a', s'⟩ ==> P \<turnstile>1 ⟨a⌊i⌉ := e, s⟩ -ta-> ⟨a'⌊i⌉ := e, s'⟩"

| AAss1Red2:
  "P \<turnstile>1 ⟨i, s⟩ -ta-> ⟨i', s'⟩ ==> P \<turnstile>1 ⟨(Val a)⌊i⌉ := e, s⟩ -ta-> ⟨(Val a)⌊i'⌉ := e, s'⟩"

| AAss1Red3:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> P \<turnstile>1 ⟨AAss (Val a) (Val i) e, s⟩ -ta-> ⟨(Val a)⌊Val i⌉ := e', s'⟩"

| Red1AAssNull:
  "P \<turnstile>1 ⟨AAss null (Val i) (Val e), s⟩ -ε-> ⟨THROW NullPointer, s⟩"

| Red1AAssBounds:
  "[| hp s a = Some(Arr T el); i < 0 ∨ i ≥ int (length el) |]
  ==> P \<turnstile>1 ⟨AAss (addr a) (Val (Intg i)) (Val e), s⟩ -ε-> ⟨THROW ArrayIndexOutOfBounds, s⟩"

| Red1AAssStore:
  "[| hp s a = Some(Arr T el); i ≥ 0; i < int (length el); typeofhp s w = ⌊U⌋; ¬ (P \<turnstile> U ≤ T) |]
  ==> P \<turnstile>1 ⟨AAss (addr a) (Val (Intg i)) (Val w), s⟩ -ε-> ⟨THROW ArrayStore, s⟩"

| Red1AAss:
  "[| h a = Some(Arr T el); i ≥ 0; i < int (length el); typeofh w = Some U; P \<turnstile> U ≤ T;
    h' = h(a \<mapsto> (Arr T (el[nat i := w]))) |]
  ==> P \<turnstile>1 ⟨AAss (addr a) (Val (Intg i)) (Val w), (h, l)⟩ -ε-> ⟨unit, (h', l)⟩"

| ALength1Red:
  "P \<turnstile>1 ⟨a, s⟩ -ta-> ⟨a', s'⟩ ==> P \<turnstile>1 ⟨a•length, s⟩ -ta-> ⟨a'•length, s'⟩"

| Red1ALength:
  "hp s a = ⌊Arr T elem⌋ ==> P \<turnstile>1 ⟨addr a•length, s⟩ -ε-> ⟨Val (Intg (int (length elem))), s⟩"

| Red1ALengthNull:
  "P \<turnstile>1 ⟨null•length, s⟩ -ε-> ⟨THROW NullPointer, s⟩"

| FAcc1Red:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> P \<turnstile>1 ⟨e•F{D}, s⟩ -ta-> ⟨e'•F{D}, s'⟩"

| Red1FAcc:
  "[| hp s a = Some(Obj C fs); fs(F,D) = Some v |]
  ==> P \<turnstile>1 ⟨(addr a)•F{D}, s⟩ -ε-> ⟨Val v, s⟩"

| Red1FAccNull:
  "P \<turnstile>1 ⟨null•F{D}, s⟩ -ε-> ⟨THROW NullPointer, s⟩"

| FAss1Red1:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> P \<turnstile>1 ⟨e•F{D}:=e2, s⟩ -ta-> ⟨e'•F{D}:=e2, s'⟩"

| FAss1Red2:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> P \<turnstile>1 ⟨FAss (Val v) F D e, s⟩ -ta-> ⟨Val v•F{D}:=e', s'⟩"

| Red1FAss:
  "h a = Some(Obj C fs) ==>
  P \<turnstile>1 ⟨FAss (addr a) F D (Val v), (h, l)⟩ -ε-> ⟨unit, (h(a \<mapsto> (Obj C (fs((F,D) \<mapsto> v)))), l)⟩"

| Red1FAssNull:
  "P \<turnstile>1 ⟨FAss null F D (Val v), s⟩ -ε-> ⟨THROW NullPointer, s⟩"

| Call1Obj:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> P \<turnstile>1 ⟨e•M(es), s⟩ -ta-> ⟨e'•M(es), s'⟩"

| Call1Params:
  "P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es',s'⟩ ==>
  P \<turnstile>1 ⟨(Val v)•M(es),s⟩ -ta-> ⟨(Val v)•M(es'),s'⟩"

| Red1CallExternal:
  "[| typeofhp s (Addr a) = ⌊T⌋; is_external_call P T M; P \<turnstile> ⟨a•M(vs), hp s⟩ -ta->ext ⟨va, h'⟩;
     e' = extRet2J1 va; s' = (h', lcl s) |]
  ==> P \<turnstile>1 ⟨(addr a)•M(map Val vs), s⟩ -ta-> ⟨e', s'⟩"

| Red1CallNull:
  "P \<turnstile>1 ⟨null•M(map Val vs), s⟩ -ε-> ⟨THROW NullPointer, s⟩"

| Block1Some:
  "V < length x ==> P \<turnstile>1 ⟨{V:T=⌊v⌋; e}, (h, x)⟩ -ε-> ⟨{V:T=None; e}, (h, x[V := v])⟩"

| Block1Red:
  "P \<turnstile>1 ⟨e, (h, x)⟩ -ta-> ⟨e', (h', x')⟩
  ==> P \<turnstile>1 ⟨{V:T=None; e}, (h, x)⟩ -ta-> ⟨{V:T=None; e'}, (h', x')⟩"

| Red1Block:
  "P \<turnstile>1 ⟨{V:T=None; Val u}, s⟩ -ε-> ⟨Val u, s⟩"

| Synchronized1Red1:
  "P \<turnstile>1 ⟨o', s⟩ -ta-> ⟨o'', s'⟩ ==> P \<turnstile>1 ⟨syncV (o') e, s⟩ -ta-> ⟨syncV (o'') e, s'⟩"

| Synchronized1Null:
  "V < length xs ==> P \<turnstile>1 ⟨syncV (null) e, (h, xs)⟩ -ε-> ⟨THROW NullPointer, (h, xs[V := Null])⟩"

| Lock1Synchronized:
  "[| h a = ⌊arrobj⌋; V < length xs |] ==> P \<turnstile>1 ⟨syncV (addr a) e, (h, xs)⟩ -ε\<lbrace>l Lock->a \<rbrace>\<lbrace>o Synchronization a\<rbrace>-> ⟨insyncV (a) e, (h, xs[V := Addr a])⟩"

| Synchronized1Red2:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> P \<turnstile>1 ⟨insyncV (a) e, s⟩ -ta-> ⟨insyncV (a) e', s'⟩"

| Unlock1Synchronized:
  "[| xs ! V = Addr a'; V < length xs |] ==> P \<turnstile>1 ⟨insyncV (a) (Val v), (h, xs)⟩ -ε\<lbrace>l Unlock->a' \<rbrace>\<lbrace>o Synchronization a'\<rbrace>-> ⟨Val v, (h, xs)⟩"

| Unlock1SynchronizedNull:
  "[| xs ! V = Null; V < length xs |] ==> P \<turnstile>1 ⟨insyncV (a) (Val v), (h, xs)⟩ -ε-> ⟨THROW NullPointer, (h, xs)⟩"

| Unlock1SynchronizedFail:
  "[| xs ! V = Addr a'; V < length xs |]
  ==> P \<turnstile>1 ⟨insyncV (a) (Val v), (h, xs)⟩ -ε\<lbrace>l UnlockFail->a' \<rbrace>-> ⟨THROW IllegalMonitorState, (h, xs)⟩"

| Seq1Red:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> P \<turnstile>1 ⟨e;;e2, s⟩ -ta-> ⟨e';;e2, s'⟩"

| Red1Seq:
  "P \<turnstile>1 ⟨Seq (Val v) e, s⟩ -ε-> ⟨e, s⟩"

| Cond1Red:
  "P \<turnstile>1 ⟨b, s⟩ -ta-> ⟨b', s'⟩ ==> P \<turnstile>1 ⟨if (b) e1 else e2, s⟩ -ta-> ⟨if (b') e1 else e2, s'⟩"

| Red1CondT:
  "P \<turnstile>1 ⟨if (true) e1 else e2, s⟩ -ε-> ⟨e1, s⟩"

| Red1CondF:
  "P \<turnstile>1 ⟨if (false) e1 else e2, s⟩ -ε-> ⟨e2, s⟩"

| Red1While:
  "P \<turnstile>1 ⟨while(b) c, s⟩ -ε-> ⟨if (b) (c;;while(b) c) else unit, s⟩"

| Throw1Red:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> P \<turnstile>1 ⟨throw e, s⟩ -ta-> ⟨throw e', s'⟩"

| Red1ThrowNull:
  "P \<turnstile>1 ⟨throw null, s⟩ -ε-> ⟨THROW NullPointer, s⟩"

| Try1Red:
  "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> P \<turnstile>1 ⟨try e catch(C V) e2, s⟩ -ta-> ⟨try e' catch(C V) e2, s'⟩"

| Red1Try:
  "P \<turnstile>1 ⟨try (Val v) catch(C V) e2, s⟩ -ε-> ⟨Val v, s⟩"

| Red1TryCatch:
  "[| h a = Some(Obj D fs); P \<turnstile> D \<preceq>* C; V < length x |]
  ==> P \<turnstile>1 ⟨try (Throw a) catch(C V) e2, (h, x)⟩ -ε-> ⟨{V:Class C=None; e2}, (h, x[V := Addr a])⟩"

| Red1TryFail:
  "[| hp s a = ⌊Obj D fs⌋; ¬ P \<turnstile> D \<preceq>* C |]
  ==> P \<turnstile>1 ⟨try (Throw a) catch(C V) e2, s⟩ -ε-> ⟨Throw a, s⟩"

| List1Red1:
  "P \<turnstile>1 ⟨e,s⟩ -ta-> ⟨e',s'⟩ ==>
  P \<turnstile>1 ⟨e#es,s⟩ [-ta->] ⟨e'#es,s'⟩"

| List1Red2:
  "P \<turnstile>1 ⟨es,s⟩ [-ta->] ⟨es',s'⟩ ==>
  P \<turnstile>1 ⟨Val v # es,s⟩ [-ta->] ⟨Val v # es',s'⟩"

| New1ArrayThrow: "P \<turnstile>1 ⟨newA T⌊Throw a⌉, s⟩ -ε-> ⟨Throw a, s⟩"
| Cast1Throw: "P \<turnstile>1 ⟨Cast C (Throw a), s⟩ -ε-> ⟨Throw a, s⟩"
| Bin1OpThrow1: "P \<turnstile>1 ⟨(Throw a) «bop» e2, s⟩ -ε-> ⟨Throw a, s⟩"
| Bin1OpThrow2: "P \<turnstile>1 ⟨(Val v1) «bop» (Throw a), s⟩ -ε-> ⟨Throw a, s⟩"
| LAss1Throw: "P \<turnstile>1 ⟨V:=(Throw a), s⟩ -ε-> ⟨Throw a, s⟩"
| AAcc1Throw1: "P \<turnstile>1 ⟨(Throw a)⌊i⌉, s⟩ -ε-> ⟨Throw a, s⟩"
| AAcc1Throw2: "P \<turnstile>1 ⟨(Val v)⌊Throw a⌉, s⟩ -ε-> ⟨Throw a, s⟩"
| AAss1Throw1: "P \<turnstile>1 ⟨(Throw a)⌊i⌉ := e, s⟩ -ε-> ⟨Throw a, s⟩"
| AAss1Throw2: "P \<turnstile>1 ⟨(Val v)⌊Throw a⌉ := e, s⟩ -ε-> ⟨Throw a, s⟩"
| AAss1Throw3: "P \<turnstile>1 ⟨AAss (Val v) (Val i) (Throw a), s⟩ -ε-> ⟨Throw a, s⟩"
| ALength1Throw: "P \<turnstile>1 ⟨(Throw a)•length, s⟩ -ε-> ⟨Throw a, s⟩"
| FAcc1Throw: "P \<turnstile>1 ⟨(Throw a)•F{D}, s⟩ -ε-> ⟨Throw a, s⟩"
| FAss1Throw1: "P \<turnstile>1 ⟨(Throw a)•F{D}:=e2, s⟩ -ε-> ⟨Throw a, s⟩"
| FAss1Throw2: "P \<turnstile>1 ⟨FAss (Val v) F D (Throw a), s⟩ -ε-> ⟨Throw a, s⟩"
| Call1ThrowObj: "P \<turnstile>1 ⟨(Throw a)•M(es), s⟩ -ε-> ⟨Throw a, s⟩"
| Call1ThrowParams: "[| es = map Val vs @ Throw a # es' |] ==> P \<turnstile>1 ⟨(Val v)•M(es), s⟩ -ε-> ⟨Throw a, s⟩"
| Block1Throw: "P \<turnstile>1 ⟨{V:T=None; Throw a}, s⟩ -ε-> ⟨Throw a, s⟩"
| Synchronized1Throw1: "P \<turnstile>1 ⟨syncV (Throw a) e, s⟩ -ε-> ⟨Throw a, s⟩"
| Synchronized1Throw2:
  "[| xs ! V = Addr a'; V < length xs |]
  ==> P \<turnstile>1 ⟨insyncV (a) Throw ad, (h, xs)⟩ -ε\<lbrace>l Unlock->a' \<rbrace>\<lbrace>o Synchronization a'\<rbrace>-> ⟨Throw ad, (h, xs)⟩"
| Synchronized1Throw2Fail:
  "[| xs ! V = Addr a'; V < length xs |]
  ==> P \<turnstile>1 ⟨insyncV (a) Throw ad, (h, xs)⟩ -ε\<lbrace>l UnlockFail->a' \<rbrace>-> ⟨THROW IllegalMonitorState, (h, xs)⟩"
| Synchronized1Throw2Null:
  "[| xs ! V = Null; V < length xs |]
  ==> P \<turnstile>1 ⟨insyncV (a) Throw ad, (h, xs)⟩ -ε-> ⟨THROW NullPointer, (h, xs)⟩"
| Seq1Throw: "P \<turnstile>1 ⟨(Throw a);;e2, s⟩ -ε-> ⟨Throw a, s⟩"
| Cond1Throw: "P \<turnstile>1 ⟨if (Throw a) e1 else e2, s⟩ -ε-> ⟨Throw a, s⟩"
| Throw1Throw: "P \<turnstile>1 ⟨throw(Throw a), s⟩ -ε-> ⟨Throw a, s⟩"

inductive_cases red1_cases:
  "P \<turnstile>1 ⟨new C, s⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨new T⌊e⌉, s⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨e «bop» e', s⟩ -ta-> ⟨e'', s'⟩"
  "P \<turnstile>1 ⟨Var V, s⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨V:=e, s⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨a⌊i⌉, s⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨a⌊i⌉ := e, s⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨a•length, s⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨e•F{D}, s⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨e•F{D} := e2, s⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨e•M(es), s⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨{V:T=vo; e}, s⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨syncV (o') e, s⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨insyncV (a) e, s⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨e;;e', s⟩ -ta-> ⟨e'', s'⟩"
  "P \<turnstile>1 ⟨throw e, s ⟩ -ta-> ⟨e', s'⟩"
  "P \<turnstile>1 ⟨try e catch(C V) e'', s ⟩ -ta-> ⟨e', s'⟩"

lemma red1_preserves_len: "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> length (lcl s') = length (lcl s)"
  and reds1_preserves_len: "P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es', s'⟩ ==> length (lcl s') = length (lcl s)"
by(induct rule: red1_reds1.inducts)(auto)

lemma reds1_preserves_elen: "P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es', s'⟩ ==> length es' = length es"
by(induct es arbitrary: es')(auto elim: reds1.cases)

lemma red1_no_val [dest]:
  "P \<turnstile>1 ⟨Val v, s⟩ -ta-> ⟨e', s'⟩ ==> False"
by(auto elim: red1.cases)

lemma reds1_no_val [dest]:
  "P \<turnstile>1 ⟨map Val vs, s⟩ [-ta->] ⟨es', s'⟩ ==> False"
apply(induct vs arbitrary: es')
apply(erule reds1.cases, auto)+
done

lemma no_reds1_map_Val_Throw [dest]:
  "P \<turnstile>1 ⟨map Val vs @ Throw a # es,s⟩ [-ta->] ⟨es',s'⟩ ==> False"
by(induct vs arbitrary: es')(auto elim: reds1.cases elim!: red1_cases)

lemma red1_hext_incr: "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> hext (hp s) (hp s')"
  and reds1_hext_incr: "P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es', s'⟩ ==> hext (hp s) (hp s')"
apply(induct rule: red1_reds1.inducts)
apply(auto simp del: fun_upd_apply intro: hext_new hext_upd_arr hext_upd_obj dest: new_Addr_SomeD red_external_hext)
done

lemma red1_no_Throw [dest]:
  "P \<turnstile>1 ⟨Throw a, s⟩ -ta-> ⟨e', s'⟩ ==> False"
by(auto elim: red1.cases)

lemma red1_max_vars_decr: "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> max_vars e' ≤ max_vars e" 
  and reds1_max_varss_decr: "P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es', s'⟩ ==> max_varss es' ≤ max_varss es"
apply(induct rule: red1_reds1.inducts)
apply(auto)
done 

lemma red1_new_thread_heap: "[|P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩; NewThread t ex h ∈ set \<lbrace>ta\<rbrace>t |] ==> h = hp s'"
  and reds1_new_thread_heap: "[|P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es', s'⟩; NewThread t ex h ∈ set \<lbrace>ta\<rbrace>t |] ==> h = hp s'"
apply(induct rule: red1_reds1.inducts)
apply(fastsimp dest: red_ext_new_thread_heap)+
done


lemma red1_changes: "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> e ≠ e'"
  and reds1_changes: "P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es', s'⟩ ==> es ≠ es'"
proof(induct rule: red1_reds1.inducts)
  case (Red1CallExternal s a T M vs ta va h' e' s')
  thus ?case by(cases va) auto
qed auto

lemma red1_new_threadD:
  "[| P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩; NewThread t x H ∈ set \<lbrace>ta\<rbrace>t |]
  ==> ∃a M vs va T. P \<turnstile> ⟨a•M(vs), hp s⟩ -ta->ext ⟨va, hp s'⟩ ∧ typeofhp s (Addr a) = ⌊T⌋ ∧ is_external_call P T M"
  and reds1_new_threadD:
  "[| P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es', s'⟩; NewThread t x H ∈ set \<lbrace>ta\<rbrace>t |]
  ==> ∃a M vs va T. P \<turnstile> ⟨a•M(vs), hp s⟩ -ta->ext ⟨va, hp s'⟩ ∧ typeofhp s (Addr a) = ⌊T⌋ ∧ is_external_call P T M"
by(induct rule: red1_reds1.inducts)(fastsimp split: heapobj.split_asm)+

primrec call1 :: "('a, 'b) exp => (addr × mname × val list) option"
  and calls1 :: "('a, 'b) exp list => (addr × mname × val list) option"
where
  "call1 (new C) = None"
| "call1 (newA T⌊e⌉) = call1 e"
| "call1 (Cast C e) = call1 e"
| "call1 (Val v) = None"
| "call1 (Var V) = None"
| "call1 (V:=e) = call1 e"
| "call1 (e «bop» e') = (if is_val e then call1 e' else call1 e)"
| "call1 (a⌊i⌉) = (if is_val a then call1 i else call1 a)"
| "call1 (AAss a i e) = (if is_val a then (if is_val i then call1 e else call1 i) else call1 a)"
| "call1 (a•length) = call1 a"
| "call1 (e•F{D}) = call1 e"
| "call1 (FAss e F D e') = (if is_val e then call1 e' else call1 e)"
| "call1 (e•M(es)) = (if is_val e then
                     (if is_vals es ∧ is_addr e then ⌊(THE a. e = addr a, M, THE vs. es = map Val vs)⌋ else calls1 es) 
                     else call1 e)"
| "call1 ({V:T=vo; e}) = (case vo of None => call1 e | Some v => None)"
| "call1 (syncV (o') e) = call1 o'"
| "call1 (insyncV (a) e) = call1 e"
| "call1 (e;;e') = call1 e"
| "call1 (if (e) e1 else e2) = call1 e"
| "call1 (while(b) e) = None"
| "call1 (throw e) = call1 e"
| "call1 (try e1 catch(C V) e2) = call1 e1"

| "calls1 [] = None"
| "calls1 (e#es) = (if is_val e then calls1 es else call1 e)"

lemma call1_callE:
  assumes "call1 (obj•M(pns)) = ⌊(a, M', vs)⌋"
  obtains (CallObj) "call1 obj = ⌊(a, M', vs)⌋"
  | (CallParams) v where "obj = Val v" "calls1 pns = ⌊(a, M', vs)⌋"
  | (Call) "obj = addr a" "pns = map Val vs" "M = M'"
using assms by(auto split: split_if_asm simp add: is_vals_conv)

lemma calls1_map_Val_append [simp]:
  "calls1 (map Val vs @ es) = calls1 es"
by(induct vs) simp_all

lemma calls1_map_Val [simp]:
  "calls1 (map Val vs) = None"
by(induct vs) simp_all

lemma fixes e :: "('a, 'b) exp" and es :: "('a, 'b) exp list"
  shows call1_imp_call: "call1 e = ⌊aMvs⌋ ==> call e = ⌊aMvs⌋"
  and calls1_imp_calls: "calls1 es = ⌊aMvs⌋ ==> calls es = ⌊aMvs⌋"
by(induct e and es) auto

lemma fixes e :: "('a,'b) exp" and es :: "('a,'b) exp list"
  shows inline_call_max_vars1: "call1 e = ⌊aMvs⌋ ==> max_vars (inline_call e' e) ≤ max_vars e + max_vars e'"
  and inline_calls_max_varss1: "calls1 es = ⌊aMvs⌋ ==> max_varss (inline_calls e' es) ≤ max_varss es + max_vars e'"
apply(induct e and es)
apply(auto)
done

fun blocks1 :: "nat => ty list => (nat,'b) exp => (nat,'b) exp"
where 
  "blocks1 n [] e = e"
| "blocks1 n (T#Ts) e = {n:T=None; blocks1 (Suc n) Ts e}"

lemma expr_locks_blocks1 [simp]:
  "expr_locks (blocks1 n Ts e) = expr_locks e"
by(induct n Ts e rule: blocks1.induct) simp_all

inductive Red1 :: "J1_prog => (expr1 × locals1) => (expr1 × locals1) list => heap => J1_thread_action =>
                           (expr1 × locals1) => (expr1 × locals1) list => heap => bool"
                ("_ \<turnstile>1 ((1⟨_'/_,/_⟩) -_->/ (1⟨_'/_,/_⟩))" [51,0,0,0,0,0,0,0] 81)
for P ::J1_prog
where

  red1Red:
  "P \<turnstile>1 ⟨e, (h, x)⟩ -ta-> ⟨e', (h', x')⟩
  ==> P \<turnstile>1 ⟨(e, x)/exs, h⟩ -extTA2J1 P ta-> ⟨(e', x')/exs, h'⟩"

| red1Call:
  "[| call1 e = ⌊(a, M, vs)⌋; h a = ⌊Obj C fs⌋; ¬ is_external_call P (Class C) M; P \<turnstile> C sees M:Ts->T = body in D; 
     size vs = size Ts |]
  ==> P \<turnstile>1 ⟨(e, x)/exs, h⟩ -ε-> ⟨(blocks1 0 (Class D#Ts) body, Addr a # vs @ replicate (max_vars body) undefined)/(e, x)#exs, h⟩"

| red1Return:
  "final e' ==> P \<turnstile>1 ⟨(e', x')/(e, x)#exs, h⟩ -ε-> ⟨(inline_call e' e, x)/exs, h⟩"

inductive IUF :: "('a, 'b) exp => ('l,'t,'m,'x,'w,'o option) thread_action => ('a, 'b) exp => bool"
  and IUFs :: "('a, 'b) exp list => ('l,'t,'m,'x,'w,'o option) thread_action => ('a, 'b) exp list => bool"
where
  IUFFail: "final e ==> IUF (insyncv(a) e) (ε\<lbrace>l UnlockFail->l\<rbrace>) (THROW IllegalMonitorState)"
| IUFNewArray: "IUF e ta e' ==> IUF (newA T⌊e⌉) ta (newA T⌊e'⌉)"
| IUFCast: "IUF e ta e' ==> IUF (Cast T e) ta (Cast T e')"
| IUFBinOp1: "IUF e ta e' ==> IUF (e«bop»e'') ta (e'«bop»e'')"
| IUFBinOp2: "IUF e ta e' ==> IUF (e''«bop»e) ta (e''«bop»e')"
| IUFLAss: "IUF e ta e' ==> IUF (V := e) ta (V := e')"
| IUFAAcc1: "IUF a ta a' ==> IUF (a⌊i⌉) ta (a'⌊i⌉)"
| IUFAAcc2: "IUF i ta i' ==> IUF (a⌊i⌉) ta (a⌊i'⌉)"
| IUFAAss1: "IUF a ta a' ==> IUF (a⌊i⌉ := e) ta (a'⌊i⌉ := e)"
| IUFAAss2: "IUF i ta i' ==> IUF (a⌊i⌉ := e) ta (a⌊i'⌉ := e)"
| IUFAAss3: "IUF e ta e' ==> IUF (a⌊i⌉ := e) ta (a⌊i⌉ := e')"
| IUFALength: "IUF a ta a' ==> IUF (a•length) ta (a'•length)"
| IUFFAcc: "IUF e ta e' ==> IUF (e•F{D}) ta (e'•F{D})"
| IUFFAss1: "IUF e ta e' ==> IUF (e•F{D} := e'') ta (e'•F{D} := e'')"
| IUFFAss2: "IUF e ta e' ==> IUF (e''•F{D} := e) ta (e''•F{D} := e')"
| IUFCallObj: "IUF e ta e' ==> IUF (e•M(ps)) ta (e'•M(ps))"
| IUFCallParams: "IUFs ps ta ps' ==> IUF (e•M(ps)) ta (e•M(ps'))"
| IUFBlock: "IUF e ta e' ==> IUF {V:T=vo; e} ta {V:T=vo'; e'}"
| IUFSync: "IUF e ta e' ==> IUF (syncV(e) e'') ta (syncV(e') e'')"
| IUFInSync: "IUF e ta e' ==> IUF (insyncV(a) e) ta (insyncV(a) e')"
| IUFSeq: "IUF e ta e' ==> IUF (e;;e'') ta (e';;e'')"
| IUFCond: "IUF b ta b' ==> IUF (if (b) e else e') ta (if (b') e else e')"
| IUFThrow: "IUF e ta e' ==> IUF (throw e) ta (throw e')"
| IUFTry: "IUF e ta e' ==> IUF (try e catch(C V) e'') ta (try e' catch(C V) e'')"
| IUFList1: "IUF e ta e' ==> IUFs (e # es) ta (e' # es)"
| IUFList2: "IUFs es ta es' ==> IUFs (e # es) ta (e # es')"

inductive_cases IUF_cases [elim!]:
  "IUF (newA T⌊e⌉) ta e'"
  "IUF e ta (newA T⌊e'⌉)"
  "IUF (Cast T e) ta e'"
  "IUF e ta (Cast T e')"
  "IUF (e«bop»e') ta e''"
  "IUF e ta (e'«bop»e'')"
  "IUF (V := e) ta e'"
  "IUF e' ta (V := e')"
  "IUF (a⌊i⌉) ta e"
  "IUF e ta (a⌊i⌉)"
  "IUF (AAss a i e) ta e'"
  "IUF e ta (AAss a i e')"
  "IUF (a•length) ta e"
  "IUF e ta (a•length)"
  "IUF (e•F{D}) ta e'"
  "IUF e ta (e'•F{D})"
  "IUF (FAss e F D e') ta e''"
  "IUF e ta (FAss e' F D e'')"
  "IUF (e•M(ps)) ta e'"
  "IUF e ta (e'•M(ps))"
  "IUF {V:T=vo; e} ta e'"
  "IUF e ta {v:T=vo; e'}"
  "IUF (syncV(e) e') ta e''"
  "IUF e ta (syncV(e') e'')"
  "IUF (insyncV(a) e) ta e'"
  "IUF e ta (insyncV(a) e')"
  "IUF (e;;e') ta e''"
  "IUF e ta (e';;e'')"
  "IUF (if (b) e else e') ta e''"
  "IUF e ta (if (b) e' else e'')"
  "IUF (throw e) ta e'"
  "IUF e ta (throw e')"
  "IUF (try e catch(C V) e') ta e''"
  "IUF e ta (try e' catch(C v) e'')"

inductive_cases IUFs_cases [elim!]:
  "IUFs (e # es) ta es'"
  "IUFs es ta (e # es')"

lemma IUF_const_exprs [iff]:
  "IUF (new C) ta e = False"
  "IUF e ta (new C) = False"
  "IUF (Var V) ta e = False"
  "IUF e ta (Var V) = False"
  "IUF (Val v) ta e = False"
  "IUF e ta (Val v) = False"
  "IUF (while(b) c) ta e = False"
  "IUF e ta (while(b) c) = False"
  "IUFs [] ta es = False"
  "IUFs es ta [] = False"
apply(auto elim: IUF.cases IUFs.cases)
done

lemma IUFs_map_Val [iff]:
  "IUFs (map Val vs) ta es = False"
  "IUFs es ta (map Val vs) = False"
by(induct vs arbitrary: es) auto

declare IUF_IUFs.intros [intro!]

lemma IUF_simps [simp]:
  "IUF (newA T⌊e⌉) ta (newA T⌊e'⌉) <-> IUF e ta e'"
  "IUF (Cast T e) ta (Cast T e') <-> IUF e ta e'"
  "IUF (e«bop»e') ta (e''«bop»e''') <-> IUF e ta e'' ∧ e' = e''' ∨ IUF e' ta e''' ∧ e = e''"
  "IUF (V := e) ta (V := e') <-> IUF e ta e'"
  "IUF (a⌊i⌉) ta (a'⌊i'⌉) <-> IUF a ta a' ∧ i = i' ∨ IUF i ta i' ∧ a = a'"
  "IUF (AAss a i e) ta (AAss a' i' e') <-> IUF a ta a' ∧ i = i' ∧ e = e' ∨ IUF i ta i' ∧ a = a' ∧ e = e' ∨ IUF e ta e' ∧ a = a' ∧ i = i'"
  "IUF (a•length) ta (a'•length) <-> IUF a ta a'"
  "IUF (e•F{D}) ta (e'•F{D}) <-> IUF e ta e'"
  "IUF (FAss e F D e') ta (FAss e'' F D e''') <-> IUF e ta e'' ∧ e' = e''' ∨ IUF e' ta e''' ∧ e = e''"
  "IUF (e•M(ps)) ta (e'•M(ps')) <-> IUF e ta e' ∧ ps = ps' ∨ IUFs ps ta ps' ∧ e = e'"
  "IUF {V:T=vo; e} ta {V:T=vo'; e'} <-> IUF e ta e'"
  "IUF (syncV(e) e') ta (syncV(e'') e''') <-> IUF e ta e'' ∧ e' = e'''"
  "IUF (insyncV(ad) e) ta (insyncV(ad) e') <-> IUF e ta e'"
  "IUF (e;;e') ta (e'';;e''') <-> IUF e ta e'' ∧ e' = e'''"
  "IUF (if (b) e else e') ta (if (b') e'' else e''') <-> IUF b ta b' ∧ e = e'' ∧ e' = e'''"
  "IUF (throw e) ta (throw e') <-> IUF e ta e'"
  "IUF (try e catch(C V) e') ta (try e'' catch(C V) e''') <-> IUF e ta e'' ∧ e' = e'''"
by auto

lemma IUF_same_False [iff]:
  fixes e :: "('a, 'b) exp" and es :: "('a, 'b) exp list"
  shows "IUF e ta e = False" and "IUFs es ta es = False"
proof -
  have "IUF e ta e ==> False" and "IUFs es ta es ==> False"
    by(induct e and es) auto
  thus "IUF e ta e = False" "IUFs es ta es = False" by auto
qed

lemma IUF_taD:
  fixes e :: "('a, 'b) exp" and es :: "('a, 'b) exp list"
  shows "IUF e ta e' ==> ∃l. ta = ε\<lbrace>l UnlockFail->l\<rbrace>"
    and "IUFs es ta es' ==> ∃l. ta = ε\<lbrace>l UnlockFail->l\<rbrace>"
by(induct rule: IUF_IUFs.inducts) auto

definition IUFL :: "(('a, 'b) exp × 'c) => 'd => ('l,'t,'x,'m,'w,'o option) thread_action => (('a, 'b) exp × 'c) => 'd => bool"
where "IUFL ex exs ta ex' exs' <-> exs = exs' ∧ IUF (fst ex) ta (fst ex')"

abbreviation mred1' :: "J1_prog => (addr,addr,(expr1 × locals1) × (expr1 × locals1) list,heap,addr,obs_event) semantics"
where "mred1' P ≡ λ((ex, exs), h) ta ((ex', exs'), h'). P \<turnstile>1 ⟨ex/exs, h⟩ -ta-> ⟨ex'/exs', h'⟩ ∧ ¬ IUFL ex exs ta ex' exs'"

abbreviation mred1 :: "J1_prog => (addr,addr,(expr1 × locals1) × (expr1 × locals1) list,heap,addr,obs_event) semantics"
where "mred1 P ≡ λ((ex, exs), h) ta ((ex', exs'), h'). P \<turnstile>1 ⟨ex/exs, h⟩ -ta-> ⟨ex'/exs', h'⟩"
lemma red1_call_synthesized: "[| P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩; call1 e = ⌊aMvs⌋ |] ==> synthesized_call P (hp s) aMvs" -- "Move to J1"
  and reds1_calls_synthesized: "[| P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es', s'⟩; calls1 es = ⌊aMvs⌋ |] ==> synthesized_call P (hp s) aMvs"
apply(induct rule: red1_reds1.inducts)
apply(auto split: split_if_asm simp add: is_vals_conv append_eq_map_conv synthesized_call_conv)
done

section {* Silent moves *}

primrec τmove1 :: "'m prog => heap => ('a, 'b) exp => bool"
  and τmoves1 :: "'m prog => heap => ('a, 'b) exp list => bool"
where
  "τmove1 P h (new C) <-> False"
| "τmove1 P h (newA T⌊e⌉) <-> τmove1 P h e ∨ (∃a. e = Throw a)"
| "τmove1 P h (Cast U e) <-> τmove1 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v)"
| "τmove1 P h (e «bop» e') <-> τmove1 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v ∧ (τmove1 P h e' ∨ (∃a. e' = Throw a) ∨ (∃v. e' = Val v)))"
| "τmove1 P h (Val v) <-> False"
| "τmove1 P h (Var V) <-> True"
| "τmove1 P h (V := e) <-> τmove1 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v)"
| "τmove1 P h (a⌊i⌉) <-> τmove1 P h a ∨ (∃ad. a = Throw ad) ∨ (∃v. a = Val v ∧ (τmove1 P h i ∨ (∃a. i = Throw a)))"
| "τmove1 P h (AAss a i e) <-> τmove1 P h a ∨ (∃ad. a = Throw ad) ∨ (∃v. a = Val v ∧ (τmove1 P h i ∨ (∃a. i = Throw a) ∨ (∃v. i = Val v ∧ (τmove1 P h e ∨ (∃a. e = Throw a)))))"
| "τmove1 P h (a•length) <-> τmove1 P h a ∨ (∃ad. a = Throw ad)"
| "τmove1 P h (e•F{D}) <-> τmove1 P h e ∨ (∃a. e = Throw a)"
| "τmove1 P h (FAss e F D e') <-> τmove1 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v ∧ (τmove1 P h e' ∨ (∃a. e' = Throw a)))"
| "τmove1 P h (e•M(es)) <-> τmove1 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v ∧ 
   (τmoves1 P h es ∨ (∃vs a es'. es = map Val vs @ Throw a # es') ∨ 
    (∃vs. es = map Val vs ∧ (v = Null ∨ (∀T. typeofh v = ⌊T⌋ --> ¬ is_external_call P T M)))))"
| "τmove1 P h ({V:T=vo; e}) <-> (τmove1 P h e ∧ vo = None) ∨ (((∃a. e = Throw a) ∨ (∃v. e = Val v)) ∧ vo = None) ∨ vo ≠ None"
| "τmove1 P h (syncV'(e) e') <-> τmove1 P h e ∨ (∃a. e = Throw a)"
| "τmove1 P h (insyncV'(ad) e) <-> τmove1 P h e"
| "τmove1 P h (e;;e') <-> τmove1 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v)"
| "τmove1 P h (if (e) e' else e'') <-> τmove1 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v)"
| "τmove1 P h (while (e) e') = True"
| "τmove1 P h (throw e) <-> τmove1 P h e ∨ (∃a. e = Throw a) ∨ e = null"
| "τmove1 P h (try e catch(C V) e') <-> τmove1 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v)"

| "τmoves1 P h [] <-> False"
| "τmoves1 P h (e # es) <-> τmove1 P h e ∨ (∃v. e = Val v ∧ τmoves1 P h es)"

lemma τmove1_τmoves1_intros:
  fixes e :: "('a, 'b) exp" and es :: "('a, 'b) exp list"
  shows τmove1NewArray: "τmove1 P h e ==> τmove1 P h (newA T⌊e⌉)"
  and τmove1Cast: "τmove1 P h e ==> τmove1 P h (Cast U e)"
  and τmove1CastRed: "τmove1 P h (Cast U (Val v))"
  and τmove1BinOp1: "τmove1 P h e ==> τmove1 P h (e«bop»e')"
  and τmove1BinOp2: "τmove1 P h e ==> τmove1 P h (Val v«bop»e)"
  and τmove1BinOp: "τmove1 P h (Val v«bop»Val v')"
  and τmove1Var: "τmove1 P h (Var V)"
  and τmove1LAss: "τmove1 P h e ==> τmove1 P h (V := e)"
  and τmove1LAssRed: "τmove1 P h (V := Val v)"
  and τmove1AAcc1: "τmove1 P h e ==> τmove1 P h (e⌊e'⌉)"
  and τmove1AAcc2: "τmove1 P h e ==> τmove1 P h (Val v⌊e⌉)"
  and τmove1AAss1: "τmove1 P h e ==> τmove1 P h (AAss e e' e'')"
  and τmove1AAss2: "τmove1 P h e ==> τmove1 P h (AAss (Val v) e e')"
  and τmove1AAss3: "τmove1 P h e ==> τmove1 P h (AAss (Val v) (Val v') e)"
  and τmove1ALength: "τmove1 P h e ==> τmove1 P h (e•length)"
  and τmove1FAcc: "τmove1 P h e ==> τmove1 P h (e•F{D})"
  and τmove1FAss1: "τmove1 P h e ==> τmove1 P h (FAss e F D e')"
  and τmove1FAss2: "τmove1 P h e ==> τmove1 P h (FAss (Val v) F D e)"
  and τmove1CallObj: "τmove1 P h obj ==> τmove1 P h (obj•M(ps))"
  and τmove1CallParams: "τmoves1 P h ps ==> τmove1 P h (Val v•M(ps))"
  and τmove1Call: "(!!T. typeofh v = ⌊T⌋ ==> ¬ is_external_call P T M) ==> τmove1 P h (Val v•M(map Val vs))"
  and τmove1BlockSome: "τmove1 P h {V:T=⌊v⌋; e}"
  and τmove1Block: "τmove1 P h e ==> τmove1 P h {V:T=None; e}"
  and τmove1BlockRed: "τmove1 P h {V:T=None; Val v}"
  and τmove1Sync: "τmove1 P h e ==> τmove1 P h (syncV' (e) e')"
  and τmove1InSync: "τmove1 P h e ==> τmove1 P h (insyncV' (a) e)"
  and τmove1Seq: "τmove1 P h e ==> τmove1 P h (e;;e')"
  and τmove1SeqRed: "τmove1 P h (Val v;; e)"
  and τmove1Cond: "τmove1 P h e ==> τmove1 P h (if (e) e1 else e2)"
  and τmove1CondRed: "τmove1 P h (if (Val v) e1 else e2)"
  and τmove1WhileRed: "τmove1 P h (while (c) e)"
  and τmove1Throw: "τmove1 P h e ==> τmove1 P h (throw e)"
  and τmove1ThrowNull: "τmove1 P h (throw null)"
  and τmove1Try: "τmove1 P h e ==> τmove1 P h (try e catch(C V) e'')"
  and τmove1TryRed: "τmove1 P h (try Val v catch(C V) e)"
  and τmove1TryThrow: "τmove1 P h (try Throw a catch(C V) e)"
  and τmove1NewArrayThrow: "τmove1 P h (newA T⌊Throw a⌉)"
  and τmove1CastThrow: "τmove1 P h (Cast T (Throw a))"
  and τmove1BinOpThrow1: "τmove1 P h (Throw a «bop» e2)"
  and τmove1BinOpThrow2: "τmove1 P h (Val v «bop» Throw a)"
  and τmove1LAssThrow: "τmove1 P h (V:=(Throw a))"
  and τmove1AAccThrow1: "τmove1 P h (Throw a⌊e⌉)"
  and τmove1AAccThrow2: "τmove1 P h (Val v⌊Throw a⌉)"
  and τmove1AAssThrow1: "τmove1 P h (AAss (Throw a) e e')"
  and τmove1AAssThrow2: "τmove1 P h (AAss (Val v) (Throw a) e')"
  and τmove1AAssThrow3: "τmove1 P h (AAss (Val v) (Val v') (Throw a))"
  and τmove1ALengthThrow: "τmove1 P h (Throw a•length)"
  and τmove1FAccThrow: "τmove1 P h (Throw a•F{D})"
  and τmove1FAssThrow1: "τmove1 P h (Throw a•F{D} := e)"
  and τmove1FAssThrow2: "τmove1 P h (FAss (Val v) F D (Throw a))"
  and τmove1CallThrowObj: "τmove1 P h (Throw a•M(es))"
  and τmove1CallThrowParams: "τmove1 P h (Val v•M(map Val vs @ Throw a # es))"
  and τmove1BlockThrow: "τmove1 P h {V:T=None; Throw a}"
  and τmove1SyncThrow: "τmove1 P h (syncV' (Throw a) e)"
  and τmove1SeqThrow: "τmove1 P h (Throw a;;e)"
  and τmove1CondThrow: "τmove1 P h (if (Throw a) e1 else e2)"
  and τmove1ThrowThrow: "τmove1 P h (throw (Throw a))"

  and τmoves1Hd: "τmove1 P h e ==> τmoves1 P h (e # es)"
  and τmoves1Tl: "τmoves1 P h es ==> τmoves1 P h (Val v # es)"
by fastsimp+

lemma τmoves1_map_Val [dest!]:
  "τmoves1 P h (map Val es) ==> False"
by(induct es)(auto)

lemma fixes e :: "('a, 'b) exp" and es :: "('a, 'b) exp list"
  shows τmove1_not_call1: "call1 e = ⌊aMvs⌋ ==> τmove1 P h e <-> ¬ synthesized_call P h aMvs"
  and τmoves1_not_calls1: "calls1 es = ⌊aMvs⌋ ==> τmoves1 P h es <-> ¬ synthesized_call P h aMvs"
apply(induct e and es)
apply(auto split: split_if_asm simp add: is_vals_conv)
apply(auto simp add: synthesized_call_def map_eq_append_conv)
done


lemma red1_τ_taD: "[| P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩; τmove1 P (hp s) e |] ==> ta = ε"
  and reds1_τ_taD: "[| P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es', s'⟩; τmoves1 P (hp s) es |] ==> ta = ε"
apply(induct rule: red1_reds1.inducts)
apply(fastsimp simp add: map_eq_append_conv)+
done

lemma τmove1_heap_unchanged: "[| P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩; τmove1 P (hp s) e |] ==> hp s' = hp s"
  and τmoves1_heap_unchanged: "[| P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es', s'⟩; τmoves1 P (hp s) es |] ==> hp s' = hp s"
apply(induct rule: red1_reds1.inducts)
apply(auto)
apply(fastsimp simp add: map_eq_append_conv)
done

lemma red1_hext:
  "[| P \<turnstile>1 ⟨e, s⟩ -ε-> ⟨e', s'⟩; hp s = hp s'; hext (hp s) h; τmove1 P (hp s) e |]
  ==> P \<turnstile>1 ⟨e, (h, lcl s)⟩ -ε-> ⟨e', (h, lcl s')⟩"

  and reds1_hext:
  "[| P \<turnstile>1 ⟨es, s⟩ [-ε->] ⟨es', s'⟩; hp s = hp s'; hext (hp s) h; τmoves1 P (hp s) es |]
  ==> P \<turnstile>1 ⟨es, (h, lcl s)⟩ [-ε->] ⟨es', (h, lcl s')⟩"
proof(induct e s ta"ε :: external_thread_action" e' s'
        and es s ta"ε :: external_thread_action" es' s'
       rule: red1_reds1.inducts)
  case Red1New thus ?case by(fastsimp dest: new_Addr_SomeD simp add: expand_fun_eq split: split_if_asm)
next
  case Red1NewFail thus ?case
    by(fastsimp simp add: new_Addr_def dest: hext_objarrD split: split_if_asm intro!: red1_reds1.Red1NewFail)
next
  case Red1Cast thus ?case by(fastsimp dest: hext_typeof_mono intro: red1_reds1.Red1Cast)
next
  case Red1CastFail thus ?case by(fastsimp dest: hext_typeof_mono intro: red1_reds1.Red1CastFail)
next
  case Red1TryCatch thus ?case by(auto dest: hext_objD intro: red1_reds1.intros)
next
  case Red1TryFail thus ?case by(auto dest!: hext_objD)(auto intro: red1_reds1.intros)
next
  case Red1CallExternal thus ?case by(fastsimp simp add: map_eq_append_conv)
qed(fastsimp intro: red1_reds1.intros simp add: expand_finfun_eq expand_fun_eq finfun_upd_apply split: split_if_asm)+

fun τMove1 :: "'m prog => heap => (('a, 'b) exp × 'c) × (('a, 'b) exp × 'd) list => bool"
where
  "τMove1 P h ((e, x), exs) = (τmove1 P h e ∨ final e)"

lemma τMove1_iff:
  "τMove1 P h exexs <-> (let ((e, _), _) = exexs in τmove1 P h e ∨ final e)"
by(cases exexs)(auto)

definition τred1 :: "J1_prog => heap => (expr1 × locals1) => (expr1 × locals1) => bool"
where "τred1 P h exs e'xs' = (P \<turnstile>1 ⟨fst exs, (h, snd exs)⟩ -ε-> ⟨fst e'xs', (h, snd e'xs')⟩ ∧ τmove1 P h (fst exs))"

definition τreds1 :: "J1_prog => heap => (expr1 list × locals1) => (expr1 list × locals1) => bool"
where "τreds1 P h esxs es'xs' = (P \<turnstile>1 ⟨fst esxs, (h, snd esxs)⟩ [-ε->] ⟨fst es'xs', (h, snd es'xs')⟩ ∧ τmoves1 P h (fst esxs))"

abbreviation τred1t :: "J1_prog => heap => (expr1 × locals1) => (expr1 × locals1) => bool"
where "τred1t P h ≡ (τred1 P h)^++"

abbreviation τreds1t :: "J1_prog => heap => (expr1 list × locals1) => (expr1 list × locals1) => bool"
where "τreds1t P h ≡ (τreds1 P h)^++"

abbreviation τred1r :: "J1_prog => heap => (expr1 × locals1) => (expr1 × locals1) => bool"
where "τred1r P h ≡ (τred1 P h)^**"

abbreviation τreds1r :: "J1_prog => heap => (expr1 list × locals1) => (expr1 list × locals1) => bool"
where "τreds1r P h ≡ (τreds1 P h)^**"

lemma τred1_iff [iff]:
  "τred1 P h (e, xs) (e', xs') = (P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩ ∧ τmove1 P h e)"
by(simp add: τred1_def)

lemma τreds1_iff [iff]:
  "τreds1 P h (es, xs) (es', xs') = (P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩ ∧ τmoves1 P h es)"
by(simp add: τreds1_def)

lemma τred1t_1step:
  "[| P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove1 P h e |]
  ==> τred1t P h (e, xs) (e', xs')"
by(blast intro: tranclp.r_into_trancl)

lemma τred1t_2step:
  "[| P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove1 P h e; 
     P \<turnstile>1 ⟨e', (h, xs')⟩ -ε-> ⟨e'', (h, xs'')⟩; τmove1 P h e' |]
  ==> τred1t P h (e, xs) (e'', xs'')"
by(blast intro: tranclp.trancl_into_trancl[OF τred1t_1step])

lemma τred1t_3step:
  "[| P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove1 P h e; 
     P \<turnstile>1 ⟨e', (h, xs')⟩ -ε-> ⟨e'', (h, xs'')⟩; τmove1 P h e';
     P \<turnstile>1 ⟨e'', (h, xs'')⟩ -ε-> ⟨e''', (h, xs''')⟩; τmove1 P h e'' |]
  ==> τred1t P h (e, xs) (e''', xs''')"
by(blast intro: tranclp.trancl_into_trancl[OF τred1t_2step])

lemma τreds1t_1step:
  "[| P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves1 P h es |]
  ==> τreds1t P h (es, xs) (es', xs')"
by(blast intro: tranclp.r_into_trancl)

lemma τreds1t_2step:
  "[| P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves1 P h es; 
     P \<turnstile>1 ⟨es', (h, xs')⟩ [-ε->] ⟨es'', (h, xs'')⟩; τmoves1 P h es' |]
  ==> τreds1t P h (es, xs) (es'', xs'')"
by(blast intro: tranclp.trancl_into_trancl[OF τreds1t_1step])

lemma τreds1t_3step:
  "[| P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves1 P h es; 
     P \<turnstile>1 ⟨es', (h, xs')⟩ [-ε->] ⟨es'', (h, xs'')⟩; τmoves1 P h es';
     P \<turnstile>1 ⟨es'', (h, xs'')⟩ [-ε->] ⟨es''', (h, xs''')⟩; τmoves1 P h es'' |]
  ==> τreds1t P h (es, xs) (es''', xs''')"
by(blast intro: tranclp.trancl_into_trancl[OF τreds1t_2step])

lemma τred1r_1step:
  "[| P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove1 P h e |]
  ==> τred1r P h (e, xs) (e', xs')"
by(blast intro: r_into_rtranclp)

lemma τred1r_2step:
  "[| P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove1 P h e; 
     P \<turnstile>1 ⟨e', (h, xs')⟩ -ε-> ⟨e'', (h, xs'')⟩; τmove1 P h e' |]
  ==> τred1r P h (e, xs) (e'', xs'')"
by(blast intro: rtranclp.rtrancl_into_rtrancl[OF τred1r_1step])

lemma τred1r_3step:
  "[| P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove1 P h e; 
     P \<turnstile>1 ⟨e', (h, xs')⟩ -ε-> ⟨e'', (h, xs'')⟩; τmove1 P h e';
     P \<turnstile>1 ⟨e'', (h, xs'')⟩ -ε-> ⟨e''', (h, xs''')⟩; τmove1 P h e'' |]
  ==> τred1r P h (e, xs) (e''', xs''')"
by(blast intro: rtranclp.rtrancl_into_rtrancl[OF τred1r_2step])

lemma τreds1r_1step:
  "[| P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves1 P h es |]
  ==> τreds1r P h (es, xs) (es', xs')"
by(blast intro: r_into_rtranclp)

lemma τreds1r_2step:
  "[| P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves1 P h es; 
     P \<turnstile>1 ⟨es', (h, xs')⟩ [-ε->] ⟨es'', (h, xs'')⟩; τmoves1 P h es' |]
  ==> τreds1r P h (es, xs) (es'', xs'')"
by(blast intro: rtranclp.rtrancl_into_rtrancl[OF τreds1r_1step])

lemma τreds1r_3step:
  "[| P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves1 P h es; 
     P \<turnstile>1 ⟨es', (h, xs')⟩ [-ε->] ⟨es'', (h, xs'')⟩; τmoves1 P h es';
     P \<turnstile>1 ⟨es'', (h, xs'')⟩ [-ε->] ⟨es''', (h, xs''')⟩; τmoves1 P h es'' |]
  ==> τreds1r P h (es, xs) (es''', xs''')"
by(blast intro: rtranclp.rtrancl_into_rtrancl[OF τreds1r_2step])

lemma τred1t_preserves_len: "τred1t P h (e, xs) (e', xs') ==> length xs' = length xs"
by(induct rule: tranclp_induct2)(auto dest: red1_preserves_len)

lemma τred1r_preserves_len: "τred1r P h (e, xs) (e', xs') ==> length xs' = length xs"
by(induct rule: rtranclp_induct2)(auto dest: red1_preserves_len)

lemma τred1t_inj_τreds1t: "τred1t P h (e, xs) (e', xs') ==> τreds1t P h (e # es, xs) (e' # es, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl List1Red1 τmoves1Hd)

lemma τreds1t_cons_τreds1t: "τreds1t P h (es, xs) (es', xs') ==> τreds1t P h (Val v # es, xs) (Val v # es', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl List1Red2 τmoves1Tl)

lemma τred1r_inj_τreds1r: "τred1r P h (e, xs) (e', xs') ==> τreds1r P h (e # es, xs) (e' # es, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl List1Red1 τmoves1Hd)

lemma τreds1r_cons_τreds1r: "τreds1r P h (es, xs) (es', xs') ==> τreds1r P h (Val v # es, xs) (Val v # es', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl List1Red2 τmoves1Tl)

lemma NewArray_τred1t_xt:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (newA T⌊e⌉, xs) (newA T⌊e'⌉, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl New1ArrayRed τmove1NewArray)

lemma Cast_τred1t_xt:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (Cast T e, xs) (Cast T e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Cast1Red τmove1Cast)

lemma BinOp_τred1t_xt1:
  "τred1t P h (e1, xs) (e1', xs') ==> τred1t P h (e1 «bop» e2, xs) (e1' «bop» e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Bin1OpRed1 τmove1BinOp1)

lemma BinOp_τred1t_xt2:
  "τred1t P h (e2, xs) (e2', xs') ==> τred1t P h (Val v «bop» e2, xs) (Val v «bop» e2', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Bin1OpRed2 τmove1BinOp2)

lemma LAss_τred1t:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (V := e, xs) (V := e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl LAss1Red τmove1LAss)

lemma AAcc_τred1t_xt1:
  "τred1t P h (a, xs) (a', xs') ==> τred1t P h (a⌊i⌉, xs) (a'⌊i⌉, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAcc1Red1 τmove1AAcc1)

lemma AAcc_τred1t_xt2:
  "τred1t P h (i, xs) (i', xs') ==> τred1t P h (Val a⌊i⌉, xs) (Val a⌊i'⌉, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAcc1Red2 τmove1AAcc2)

lemma AAss_τred1t_xt1:
  "τred1t P h (a, xs) (a', xs') ==> τred1t P h (a⌊i⌉ := e, xs) (a'⌊i⌉ := e, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAss1Red1 τmove1AAss1)

lemma AAss_τred1t_xt2:
  "τred1t P h (i, xs) (i', xs') ==> τred1t P h (Val a⌊i⌉ := e, xs) (Val a⌊i'⌉ := e, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAss1Red2 τmove1AAss2)

lemma AAss_τred1t_xt3:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (Val a⌊Val i⌉ := e, xs) (Val a⌊Val i⌉ := e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAss1Red3 τmove1AAss3)

lemma ALength_τred1t_xt:
  "τred1t P h (a, xs) (a', xs') ==> τred1t P h (a•length, xs) (a'•length, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl ALength1Red τmove1ALength)

lemma FAcc_τred1t_xt:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (e•F{D}, xs) (e'•F{D}, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl FAcc1Red τmove1FAcc)

lemma FAss_τred1t_xt1:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (e•F{D} := e2, xs) (e'•F{D} := e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl FAss1Red1 τmove1FAss1)

lemma FAss_τred1t_xt2:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (Val v•F{D} := e, xs) (Val v•F{D} := e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl FAss1Red2 τmove1FAss2)

lemma Call_τred1t_obj:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (e•M(ps), xs) (e'•M(ps), xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Call1Obj τmove1CallObj)

lemma Call_τred1t_param:
  "τreds1t P h (es, xs) (es', xs') ==> τred1t P h (Val v•M(es), xs) (Val v•M(es'), xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Call1Params τmove1CallParams)

lemma Block_None_τred1t_xt:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h ({V:T=None; e}, xs) ({V:T=None; e'}, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl τmove1Block elim!: Block1Red)

lemma Block_τred1t_Some:
  "[| τred1t P h (e, xs[V := v]) (e', xs'); V < length xs |] 
  ==> τred1t P h ({V:Ty=⌊v⌋; e}, xs) ({V:Ty=None; e'}, xs')"
by(blast intro: tranclp_into_tranclp2 Block1Some τmove1BlockSome Block_None_τred1t_xt)

lemma Sync_τred1t_xt:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (syncV (e) e2, xs) (syncV (e') e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Synchronized1Red1 τmove1Sync)

lemma InSync_τred1t_xt:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (insyncV (a) e, xs) (insyncV (a) e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Synchronized1Red2 τmove1InSync)

lemma Seq_τred1t_xt:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (e;;e2, xs) (e';;e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Seq1Red τmove1Seq)

lemma Cond_τred1t_xt:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (if (e) e1 else e2, xs) (if (e') e1 else e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Cond1Red τmove1Cond)

lemma Throw_τred1t_xt:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (throw e, xs) (throw e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Throw1Red τmove1Throw)

lemma Try_τred1t_xt:
  "τred1t P h (e, xs) (e', xs') ==> τred1t P h (try e catch(C V) e2, xs) (try e' catch(C V) e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Try1Red τmove1Try)


lemma NewArray_τred1r_xt:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (newA T⌊e⌉, xs) (newA T⌊e'⌉, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl New1ArrayRed τmove1NewArray)

lemma Cast_τred1r_xt:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (Cast T e, xs) (Cast T e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Cast1Red τmove1Cast)

lemma BinOp_τred1r_xt1:
  "τred1r P h (e1, xs) (e1', xs') ==> τred1r P h (e1 «bop» e2, xs) (e1' «bop» e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Bin1OpRed1 τmove1BinOp1)

lemma BinOp_τred1r_xt2:
  "τred1r P h (e2, xs) (e2', xs') ==> τred1r P h (Val v «bop» e2, xs) (Val v «bop» e2', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Bin1OpRed2 τmove1BinOp2)

lemma LAss_τred1r:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (V := e, xs) (V := e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl LAss1Red τmove1LAss)

lemma AAcc_τred1r_xt1:
  "τred1r P h (a, xs) (a', xs') ==> τred1r P h (a⌊i⌉, xs) (a'⌊i⌉, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAcc1Red1 τmove1AAcc1)

lemma AAcc_τred1r_xt2:
  "τred1r P h (i, xs) (i', xs') ==> τred1r P h (Val a⌊i⌉, xs) (Val a⌊i'⌉, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAcc1Red2 τmove1AAcc2)

lemma AAss_τred1r_xt1:
  "τred1r P h (a, xs) (a', xs') ==> τred1r P h (a⌊i⌉ := e, xs) (a'⌊i⌉ := e, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAss1Red1 τmove1AAss1)

lemma AAss_τred1r_xt2:
  "τred1r P h (i, xs) (i', xs') ==> τred1r P h (Val a⌊i⌉ := e, xs) (Val a⌊i'⌉ := e, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAss1Red2 τmove1AAss2)

lemma AAss_τred1r_xt3:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (Val a⌊Val i⌉ := e, xs) (Val a⌊Val i⌉ := e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAss1Red3 τmove1AAss3)

lemma ALength_τred1r_xt:
  "τred1r P h (a, xs) (a', xs') ==> τred1r P h (a•length, xs) (a'•length, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl ALength1Red τmove1ALength)

lemma FAcc_τred1r_xt:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (e•F{D}, xs) (e'•F{D}, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl FAcc1Red τmove1FAcc)

lemma FAss_τred1r_xt1:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (e•F{D} := e2, xs) (e'•F{D} := e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl FAss1Red1 τmove1FAss1)

lemma FAss_τred1r_xt2:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (Val v•F{D} := e, xs) (Val v•F{D} := e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl FAss1Red2 τmove1FAss2)

lemma Call_τred1r_obj:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (e•M(ps), xs) (e'•M(ps), xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Call1Obj τmove1CallObj)

lemma Call_τred1r_param:
  "τreds1r P h (es, xs) (es', xs') ==> τred1r P h (Val v•M(es), xs) (Val v•M(es'), xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Call1Params τmove1CallParams)

lemma Block_None_τred1r_xt:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h ({V:T=None; e}, xs) ({V:T=None; e'}, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl τmove1Block elim!: Block1Red)

lemma Block_τred1r_Some:
  "[| τred1r P h (e, xs[V := v]) (e', xs'); V < length xs |] 
  ==> τred1r P h ({V:Ty=⌊v⌋; e}, xs) ({V:Ty=None; e'}, xs')"
by(blast intro: converse_rtranclp_into_rtranclp Block1Some τmove1BlockSome Block_None_τred1r_xt)

lemma Sync_τred1r_xt:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (syncV (e) e2, xs) (syncV (e') e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Synchronized1Red1 τmove1Sync)

lemma InSync_τred1r_xt:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (insyncV (a) e, xs) (insyncV (a) e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Synchronized1Red2 τmove1InSync)

lemma Seq_τred1r_xt:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (e;;e2, xs) (e';;e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Seq1Red τmove1Seq)

lemma Cond_τred1r_xt:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (if (e) e1 else e2, xs) (if (e') e1 else e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Cond1Red τmove1Cond)

lemma Throw_τred1r_xt:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (throw e, xs) (throw e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Throw1Red τmove1Throw)

lemma Try_τred1r_xt:
  "τred1r P h (e, xs) (e', xs') ==> τred1r P h (try e catch(C V) e2, xs) (try e' catch(C V) e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Try1Red τmove1Try)

lemma τred1t_ThrowD [dest]: "τred1t P h (Throw a, xs) (e'', xs'') ==> e'' = Throw a ∧ xs'' = xs"
by(induct rule: tranclp_induct2)(auto)

lemma τred1r_ThrowD [dest]: "τred1r P h (Throw a, xs) (e'', xs'') ==> e'' = Throw a ∧ xs'' = xs"
by(induct rule: rtranclp_induct2)(auto)

definition τRed1 :: "J1_prog => heap => (expr1 × locals1) × ((expr1 × locals1) list) =>
                            (expr1 × locals1) × ((expr1 × locals1) list) => bool"
where "τRed1 P h exexs ex'exs' = (P \<turnstile>1 ⟨fst exexs/snd exexs, h⟩ -ε-> ⟨fst ex'exs'/snd ex'exs', h⟩ ∧ τMove1 P h exexs)"

lemma τRed1_conv [iff]:
  "τRed1 P h (ex, exs) (ex', exs') = (P \<turnstile>1 ⟨ex/exs, h⟩ -ε-> ⟨ex'/exs', h⟩ ∧ τMove1 P h (ex, exs))"
by(simp add: τRed1_def)

abbreviation τRed1t :: "J1_prog => heap => (expr1 × locals1) × ((expr1 × locals1) list) =>
                                        (expr1 × locals1) × ((expr1 × locals1) list) => bool"
where "τRed1t P h ≡ (τRed1 P h)^++"

abbreviation τRed1r :: "J1_prog => heap => (expr1 × locals1) × ((expr1 × locals1) list) =>
                                        (expr1 × locals1) × ((expr1 × locals1) list) => bool"
where "τRed1r P h ≡ (τRed1 P h)^**"

lemma τred1t_into_τRed1t:
  "τred1t P h (e, xs) (e'', xs'') ==> τRed1t P h ((e, xs), exs) ((e'', xs''), exs)"
by(induct rule: tranclp_induct2)(fastsimp dest: red1Red intro: τmove1Block tranclp.intros)+

lemma τred1r_into_τRed1r:
  "τred1r P h (e, xs) (e'', xs'') ==> τRed1r P h ((e, xs), exs) ((e'', xs''), exs)"
by(induct rule: rtranclp_induct2)(fastsimp dest: red1Red intro: τmove1Block rtranclp.intros)+

lemma red1_max_vars: "P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> max_vars e' ≤ max_vars e"
  and reds1_max_varss: "P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es', s'⟩ ==> max_varss es' ≤ max_varss es"
by(induct rule: red1_reds1.inducts) auto

lemma τred1t_max_vars: "τred1t P h (e, xs) (e', xs') ==> max_vars e' ≤ max_vars e"
by(induct rule: tranclp_induct2)(auto dest: red1_max_vars)

lemma τred1r_max_vars: "τred1r P h (e, xs) (e', xs') ==> max_vars e' ≤ max_vars e"
by(induct rule: rtranclp_induct2)(auto dest: red1_max_vars)




definition τred1' :: "J1_prog => heap => (expr1 × locals1) => (expr1 × locals1) => bool"
where
  "τred1' P h exs e'xs' =
  (P \<turnstile>1 ⟨fst exs, (h, snd exs)⟩ -ε-> ⟨fst e'xs', (h, snd e'xs')⟩ ∧ τmove1 P h (fst exs) ∧ ¬ IUF (fst exs) (ε :: J1_thread_action) (fst e'xs'))"

definition τreds1' :: "J1_prog => heap => (expr1 list × locals1) => (expr1 list × locals1) => bool"
where
  "τreds1' P h esxs es'xs' =
  (P \<turnstile>1 ⟨fst esxs, (h, snd esxs)⟩ [-ε->] ⟨fst es'xs', (h, snd es'xs')⟩ ∧ τmoves1 P h (fst esxs) ∧ ¬ IUFs (fst esxs) (ε:: J1_thread_action) (fst es'xs'))"

abbreviation τred1't :: "J1_prog => heap => (expr1 × locals1) => (expr1 × locals1) => bool"
where "τred1't P h ≡ (τred1' P h)^++"

abbreviation τreds1't :: "J1_prog => heap => (expr1 list × locals1) => (expr1 list × locals1) => bool"
where "τreds1't P h ≡ (τreds1' P h)^++"

abbreviation τred1'r :: "J1_prog => heap => (expr1 × locals1) => (expr1 × locals1) => bool"
where "τred1'r P h ≡ (τred1' P h)^**"

abbreviation τreds1'r :: "J1_prog => heap => (expr1 list × locals1) => (expr1 list × locals1) => bool"
where "τreds1'r P h ≡ (τreds1' P h)^**"

lemma τred1'_iff [iff]:
  "τred1' P h (e, xs) (e', xs') = (P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩ ∧ τmove1 P h e ∧ ¬ IUF e (ε :: J1_thread_action) e')"
by(simp add: τred1'_def)

lemma τreds1'_iff [iff]:
  "τreds1' P h (es, xs) (es', xs') = (P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩ ∧ τmoves1 P h es ∧ ¬  IUFs es (ε :: J1_thread_action) es')"
by(simp add: τreds1'_def)

lemma τred1't_1step:
  "[| P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove1 P h e; ¬ IUF e (ε :: J1_thread_action) e' |]
  ==> τred1't P h (e, xs) (e', xs')"
by(blast intro: tranclp.r_into_trancl)

lemma τred1't_2step:
  "[| P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove1 P h e; ¬ IUF e (ε :: J1_thread_action) e';
     P \<turnstile>1 ⟨e', (h, xs')⟩ -ε-> ⟨e'', (h, xs'')⟩; τmove1 P h e'; ¬ IUF e' (ε :: J1_thread_action) e'' |]
  ==> τred1't P h (e, xs) (e'', xs'')"
by(blast intro: tranclp.trancl_into_trancl[OF τred1't_1step])

lemma τred1't_3step:
  "[| P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove1 P h e; ¬ IUF e (ε :: J1_thread_action) e';
     P \<turnstile>1 ⟨e', (h, xs')⟩ -ε-> ⟨e'', (h, xs'')⟩; τmove1 P h e'; ¬ IUF e' (ε :: J1_thread_action) e'';
     P \<turnstile>1 ⟨e'', (h, xs'')⟩ -ε-> ⟨e''', (h, xs''')⟩; τmove1 P h e''; ¬ IUF e'' (ε :: J1_thread_action) e''' |]
  ==> τred1't P h (e, xs) (e''', xs''')"
by(blast intro: tranclp.trancl_into_trancl[OF τred1't_2step])

lemma τreds1't_1step:
  "[| P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves1 P h es; ¬ IUFs es (ε :: J1_thread_action) es' |]
  ==> τreds1't P h (es, xs) (es', xs')"
by(blast intro: tranclp.r_into_trancl)

lemma τreds1't_2step:
  "[| P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves1 P h es; ¬ IUFs es (ε :: J1_thread_action) es';
     P \<turnstile>1 ⟨es', (h, xs')⟩ [-ε->] ⟨es'', (h, xs'')⟩; τmoves1 P h es'; ¬ IUFs es' (ε :: J1_thread_action) es'' |]
  ==> τreds1't P h (es, xs) (es'', xs'')"
by(blast intro: tranclp.trancl_into_trancl[OF τreds1't_1step])

lemma τreds1't_3step:
  "[| P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves1 P h es; ¬ IUFs es (ε :: J1_thread_action) es';
     P \<turnstile>1 ⟨es', (h, xs')⟩ [-ε->] ⟨es'', (h, xs'')⟩; τmoves1 P h es'; ¬ IUFs es' (ε :: J1_thread_action) es'';
     P \<turnstile>1 ⟨es'', (h, xs'')⟩ [-ε->] ⟨es''', (h, xs''')⟩; τmoves1 P h es''; ¬ IUFs es'' (ε :: J1_thread_action) es''' |]
  ==> τreds1't P h (es, xs) (es''', xs''')"
by(blast intro: tranclp.trancl_into_trancl[OF τreds1't_2step])

lemma τred1'r_1step:
  "[| P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove1 P h e; ¬ IUF e (ε :: J1_thread_action) e' |]
  ==> τred1'r P h (e, xs) (e', xs')"
by(blast intro: r_into_rtranclp)

lemma τred1'r_2step:
  "[| P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove1 P h e; ¬ IUF e (ε :: J1_thread_action) e';
     P \<turnstile>1 ⟨e', (h, xs')⟩ -ε-> ⟨e'', (h, xs'')⟩; τmove1 P h e'; ¬ IUF e' (ε :: J1_thread_action) e'' |]
  ==> τred1'r P h (e, xs) (e'', xs'')"
by(blast intro: rtranclp.rtrancl_into_rtrancl[OF τred1'r_1step])

lemma τred1'r_3step:
  "[| P \<turnstile>1 ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove1 P h e; ¬ IUF e (ε :: J1_thread_action) e';
     P \<turnstile>1 ⟨e', (h, xs')⟩ -ε-> ⟨e'', (h, xs'')⟩; τmove1 P h e'; ¬ IUF e' (ε :: J1_thread_action) e'';
     P \<turnstile>1 ⟨e'', (h, xs'')⟩ -ε-> ⟨e''', (h, xs''')⟩; τmove1 P h e''; ¬ IUF e'' (ε :: J1_thread_action) e''' |]
  ==> τred1'r P h (e, xs) (e''', xs''')"
by(blast intro: rtranclp.rtrancl_into_rtrancl[OF τred1'r_2step])

lemma τreds1'r_1step:
  "[| P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves1 P h es; ¬ IUFs es (ε :: J1_thread_action) es' |]
  ==> τreds1'r P h (es, xs) (es', xs')"
by(blast intro: r_into_rtranclp)

lemma τreds1'r_2step:
  "[| P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves1 P h es; ¬ IUFs es (ε :: J1_thread_action) es';
     P \<turnstile>1 ⟨es', (h, xs')⟩ [-ε->] ⟨es'', (h, xs'')⟩; τmoves1 P h es'; ¬ IUFs es' (ε :: J1_thread_action) es'' |]
  ==> τreds1'r P h (es, xs) (es'', xs'')"
by(blast intro: rtranclp.rtrancl_into_rtrancl[OF τreds1'r_1step])

lemma τreds1'r_3step:
  "[| P \<turnstile>1 ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves1 P h es; ¬ IUFs es (ε :: J1_thread_action) es';
     P \<turnstile>1 ⟨es', (h, xs')⟩ [-ε->] ⟨es'', (h, xs'')⟩; τmoves1 P h es'; ¬ IUFs es' (ε :: J1_thread_action) es'';
     P \<turnstile>1 ⟨es'', (h, xs'')⟩ [-ε->] ⟨es''', (h, xs''')⟩; τmoves1 P h es''; ¬ IUFs es'' (ε :: J1_thread_action) es''' |]
  ==> τreds1'r P h (es, xs) (es''', xs''')"
by(blast intro: rtranclp.rtrancl_into_rtrancl[OF τreds1'r_2step])

lemma τred1't_preserves_len: "τred1't P h (e, xs) (e', xs') ==> length xs' = length xs"
by(induct rule: tranclp_induct2)(auto dest: red1_preserves_len)

lemma τred1'r_preserves_len: "τred1'r P h (e, xs) (e', xs') ==> length xs' = length xs"
by(induct rule: rtranclp_induct2)(auto dest: red1_preserves_len)

lemma τred1't_inj_τreds1't: "τred1't P h (e, xs) (e', xs') ==> τreds1't P h (e # es, xs) (e' # es, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl List1Red1 τmoves1Hd)

lemma τreds1't_cons_τreds1't: "τreds1't P h (es, xs) (es', xs') ==> τreds1't P h (Val v # es, xs) (Val v # es', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl List1Red2 τmoves1Tl)

lemma τred1'r_inj_τreds1'r: "τred1'r P h (e, xs) (e', xs') ==> τreds1'r P h (e # es, xs) (e' # es, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl List1Red1 τmoves1Hd)

lemma τreds1'r_cons_τreds1'r: "τreds1'r P h (es, xs) (es', xs') ==> τreds1'r P h (Val v # es, xs) (Val v # es', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl List1Red2 τmoves1Tl)

lemma NewArray_τred1't_xt:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (newA T⌊e⌉, xs) (newA T⌊e'⌉, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl New1ArrayRed τmove1NewArray)

lemma Cast_τred1't_xt:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (Cast T e, xs) (Cast T e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Cast1Red τmove1Cast)

lemma BinOp_τred1't_xt1:
  "τred1't P h (e1, xs) (e1', xs') ==> τred1't P h (e1 «bop» e2, xs) (e1' «bop» e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Bin1OpRed1 τmove1BinOp1)

lemma BinOp_τred1't_xt2:
  "τred1't P h (e2, xs) (e2', xs') ==> τred1't P h (Val v «bop» e2, xs) (Val v «bop» e2', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Bin1OpRed2 τmove1BinOp2)

lemma LAss_τred1't:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (V := e, xs) (V := e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl LAss1Red τmove1LAss)

lemma AAcc_τred1't_xt1:
  "τred1't P h (a, xs) (a', xs') ==> τred1't P h (a⌊i⌉, xs) (a'⌊i⌉, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAcc1Red1 τmove1AAcc1)

lemma AAcc_τred1't_xt2:
  "τred1't P h (i, xs) (i', xs') ==> τred1't P h (Val a⌊i⌉, xs) (Val a⌊i'⌉, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAcc1Red2 τmove1AAcc2)

lemma AAss_τred1't_xt1:
  "τred1't P h (a, xs) (a', xs') ==> τred1't P h (a⌊i⌉ := e, xs) (a'⌊i⌉ := e, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAss1Red1 τmove1AAss1)

lemma AAss_τred1't_xt2:
  "τred1't P h (i, xs) (i', xs') ==> τred1't P h (Val a⌊i⌉ := e, xs) (Val a⌊i'⌉ := e, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAss1Red2 τmove1AAss2)

lemma AAss_τred1't_xt3:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (Val a⌊Val i⌉ := e, xs) (Val a⌊Val i⌉ := e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAss1Red3 τmove1AAss3)

lemma ALength_τred1't_xt:
  "τred1't P h (a, xs) (a', xs') ==> τred1't P h (a•length, xs) (a'•length, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl ALength1Red τmove1ALength)

lemma FAcc_τred1't_xt:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (e•F{D}, xs) (e'•F{D}, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl FAcc1Red τmove1FAcc)

lemma FAss_τred1't_xt1:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (e•F{D} := e2, xs) (e'•F{D} := e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl FAss1Red1 τmove1FAss1)

lemma FAss_τred1't_xt2:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (Val v•F{D} := e, xs) (Val v•F{D} := e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl FAss1Red2 τmove1FAss2)

lemma Call_τred1't_obj:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (e•M(ps), xs) (e'•M(ps), xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Call1Obj τmove1CallObj)

lemma Call_τred1't_param:
  "τreds1't P h (es, xs) (es', xs') ==> τred1't P h (Val v•M(es), xs) (Val v•M(es'), xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Call1Params τmove1CallParams)

lemma Block_None_τred1't_xt:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h ({V:T=None; e}, xs) ({V:T=None; e'}, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl τmove1Block elim!: Block1Red)

lemma Block_τred1't_Some:
  "[| τred1't P h (e, xs[V := v]) (e', xs'); V < length xs |] 
  ==> τred1't P h ({V:Ty=⌊v⌋; e}, xs) ({V:Ty=None; e'}, xs')"
by(blast intro: tranclp_into_tranclp2 Block1Some τmove1BlockSome Block_None_τred1't_xt)

lemma Sync_τred1't_xt:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (syncV (e) e2, xs) (syncV (e') e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Synchronized1Red1 τmove1Sync)

lemma InSync_τred1't_xt:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (insyncV (a) e, xs) (insyncV (a) e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Synchronized1Red2 τmove1InSync)

lemma Seq_τred1't_xt:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (e;;e2, xs) (e';;e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Seq1Red τmove1Seq)

lemma Cond_τred1't_xt:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (if (e) e1 else e2, xs) (if (e') e1 else e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Cond1Red τmove1Cond)

lemma Throw_τred1't_xt:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (throw e, xs) (throw e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Throw1Red τmove1Throw)

lemma Try_τred1't_xt:
  "τred1't P h (e, xs) (e', xs') ==> τred1't P h (try e catch(C V) e2, xs) (try e' catch(C V) e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl Try1Red τmove1Try)


lemma NewArray_τred1'r_xt:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (newA T⌊e⌉, xs) (newA T⌊e'⌉, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl New1ArrayRed τmove1NewArray)

lemma Cast_τred1'r_xt:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (Cast T e, xs) (Cast T e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Cast1Red τmove1Cast)

lemma BinOp_τred1'r_xt1:
  "τred1'r P h (e1, xs) (e1', xs') ==> τred1'r P h (e1 «bop» e2, xs) (e1' «bop» e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Bin1OpRed1 τmove1BinOp1)

lemma BinOp_τred1'r_xt2:
  "τred1'r P h (e2, xs) (e2', xs') ==> τred1'r P h (Val v «bop» e2, xs) (Val v «bop» e2', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Bin1OpRed2 τmove1BinOp2)

lemma LAss_τred1'r:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (V := e, xs) (V := e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl LAss1Red τmove1LAss)

lemma AAcc_τred1'r_xt1:
  "τred1'r P h (a, xs) (a', xs') ==> τred1'r P h (a⌊i⌉, xs) (a'⌊i⌉, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAcc1Red1 τmove1AAcc1)

lemma AAcc_τred1'r_xt2:
  "τred1'r P h (i, xs) (i', xs') ==> τred1'r P h (Val a⌊i⌉, xs) (Val a⌊i'⌉, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAcc1Red2 τmove1AAcc2)

lemma AAss_τred1'r_xt1:
  "τred1'r P h (a, xs) (a', xs') ==> τred1'r P h (a⌊i⌉ := e, xs) (a'⌊i⌉ := e, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAss1Red1 τmove1AAss1)

lemma AAss_τred1'r_xt2:
  "τred1'r P h (i, xs) (i', xs') ==> τred1'r P h (Val a⌊i⌉ := e, xs) (Val a⌊i'⌉ := e, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAss1Red2 τmove1AAss2)

lemma AAss_τred1'r_xt3:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (Val a⌊Val i⌉ := e, xs) (Val a⌊Val i⌉ := e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAss1Red3 τmove1AAss3)

lemma ALength_τred1'r_xt:
  "τred1'r P h (a, xs) (a', xs') ==> τred1'r P h (a•length, xs) (a'•length, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl ALength1Red τmove1ALength)

lemma FAcc_τred1'r_xt:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (e•F{D}, xs) (e'•F{D}, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl FAcc1Red τmove1FAcc)

lemma FAss_τred1'r_xt1:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (e•F{D} := e2, xs) (e'•F{D} := e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl FAss1Red1 τmove1FAss1)

lemma FAss_τred1'r_xt2:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (Val v•F{D} := e, xs) (Val v•F{D} := e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl FAss1Red2 τmove1FAss2)

lemma Call_τred1'r_obj:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (e•M(ps), xs) (e'•M(ps), xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Call1Obj τmove1CallObj)

lemma Call_τred1'r_param:
  "τreds1'r P h (es, xs) (es', xs') ==> τred1'r P h (Val v•M(es), xs) (Val v•M(es'), xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Call1Params τmove1CallParams)

lemma Block_None_τred1'r_xt:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h ({V:T=None; e}, xs) ({V:T=None; e'}, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl τmove1Block elim!: Block1Red)

lemma Block_τred1'r_Some:
  "[| τred1'r P h (e, xs[V := v]) (e', xs'); V < length xs |] 
  ==> τred1'r P h ({V:Ty=⌊v⌋; e}, xs) ({V:Ty=None; e'}, xs')"
by(blast intro: converse_rtranclp_into_rtranclp Block1Some τmove1BlockSome Block_None_τred1'r_xt)

lemma Sync_τred1'r_xt:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (syncV (e) e2, xs) (syncV (e') e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Synchronized1Red1 τmove1Sync)

lemma InSync_τred1'r_xt:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (insyncV (a) e, xs) (insyncV (a) e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Synchronized1Red2 τmove1InSync)

lemma Seq_τred1'r_xt:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (e;;e2, xs) (e';;e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Seq1Red τmove1Seq)

lemma Cond_τred1'r_xt:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (if (e) e1 else e2, xs) (if (e') e1 else e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Cond1Red τmove1Cond)

lemma Throw_τred1'r_xt:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (throw e, xs) (throw e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Throw1Red τmove1Throw)

lemma Try_τred1'r_xt:
  "τred1'r P h (e, xs) (e', xs') ==> τred1'r P h (try e catch(C V) e2, xs) (try e' catch(C V) e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl Try1Red τmove1Try)

lemma τred1't_ThrowD [dest]: "τred1't P h (Throw a, xs) (e'', xs'') ==> e'' = Throw a ∧ xs'' = xs"
by(induct rule: tranclp_induct2)(auto)

lemma τred1'r_ThrowD [dest]: "τred1'r P h (Throw a, xs) (e'', xs'') ==> e'' = Throw a ∧ xs'' = xs"
by(induct rule: rtranclp_induct2)(auto)

definition τRed1' :: "J1_prog => heap => (expr1 × locals1) × ((expr1 × locals1) list) =>
                            (expr1 × locals1) × ((expr1 × locals1) list) => bool"
where
  "τRed1' P h exexs ex'exs' =
  (P \<turnstile>1 ⟨fst exexs/snd exexs, h⟩ -ε-> ⟨fst ex'exs'/snd ex'exs', h⟩ ∧ τMove1 P h exexs ∧ ¬ IUFL (fst exexs) (snd exexs) (ε :: J1_thread_action) (fst ex'exs') (snd ex'exs'))"

lemma τRed1'_conv [iff]:
  "τRed1' P h (ex, exs) (ex', exs') = (P \<turnstile>1 ⟨ex/exs, h⟩ -ε-> ⟨ex'/exs', h⟩ ∧ τMove1 P h (ex, exs) ∧ ¬ IUFL ex exs (ε :: J1_thread_action) ex' exs')"
by(simp add: τRed1'_def)

abbreviation τRed1't :: "J1_prog => heap => (expr1 × locals1) × ((expr1 × locals1) list) =>
                                        (expr1 × locals1) × ((expr1 × locals1) list) => bool"
where "τRed1't P h ≡ (τRed1' P h)^++"

abbreviation τRed1'r :: "J1_prog => heap => (expr1 × locals1) × ((expr1 × locals1) list) =>
                                        (expr1 × locals1) × ((expr1 × locals1) list) => bool"
where "τRed1'r P h ≡ (τRed1' P h)^**"

lemma τred1't_into_τRed1't:
  "τred1't P h (e, xs) (e'', xs'') ==> τRed1't P h ((e, xs), exs) ((e'', xs''), exs)"
by(induct rule: tranclp_induct2)(fastsimp dest: red1Red intro: τmove1Block tranclp.intros simp add: IUFL_def)+

lemma τred1'r_into_τRed1'r:
  "τred1'r P h (e, xs) (e'', xs'') ==> τRed1'r P h ((e, xs), exs) ((e'', xs''), exs)"
by(induct rule: rtranclp_induct2)(fastsimp dest: red1Red intro: τmove1Block rtranclp.intros simp add: IUFL_def)+

lemma τred1't_max_vars: "τred1't P h (e, xs) (e', xs') ==> max_vars e' ≤ max_vars e"
by(induct rule: tranclp_induct2)(auto dest: red1_max_vars)

lemma τred1'r_max_vars: "τred1'r P h (e, xs) (e', xs') ==> max_vars e' ≤ max_vars e"
by(induct rule: rtranclp_induct2)(auto dest: red1_max_vars)

abbreviation τMOVE1 :: "'m prog => (((expr1 × locals1) × (expr1 × locals1) list) × heap,
                       (addr,addr,(expr1 × locals1) × (expr1 × locals1) list,heap,addr, obs_event option) thread_action) trsys"
where "τMOVE1 P ≡ λ(exexs, h) ta s. τMove1 P h exexs ∧ ta = ε"

abbreviation final_expr1 :: "(expr1 × locals1) × (expr1 × locals1) list => bool" where
  "final_expr1 ≡ λ(ex, exs). final (fst ex) ∧ exs = []"

lemma Red1'_mthr: "multithreaded (mred1' P)"
apply(unfold_locales)
apply(fastsimp elim!: Red1.cases dest: red1_new_thread_heap)
done

interpretation Red1'_mthr: multithreaded final_expr1 "mred1' P" for P
by(rule Red1'_mthr)

interpretation Red1'_τmthr: τmultithreaded final_expr1 "mred1' P" "τMOVE1 P" for P
by(unfold_locales)

interpretation Red1'_mthr: final_thread_wf final_expr1 "mred1' P" for P
by(unfold_locales)(auto elim!: Red1.cases simp add: final_iff)

lemma red1_τmove1_heap_unchanged: "[| P \<turnstile>1 ⟨e, s⟩ -ta-> ⟨e', s'⟩; τmove1 P (hp s) e |] ==> hp s' = hp s"
  and red1_τmoves1_heap_unchanged: "[| P \<turnstile>1 ⟨es, s⟩ [-ta->] ⟨es', s'⟩; τmoves1 P (hp s) es |] ==> hp s' = hp s"
apply(induct rule: red1_reds1.inducts)
apply(fastsimp simp add: map_eq_append_conv)+
done

lemma Red1'_τmthr_wf: "τmultithreaded_wf final_expr1 (mred1' P) (τMOVE1 P) wfs"
proof
  fix x1 m1 ta1 x1' m1'
  assume "mred1' P (x1, m1) ta1 (x1', m1')" "τMOVE1 P (x1, m1) ta1 (x1', m1')"
  thus "m1 = m1'" by(cases x1)(fastsimp elim!: Red1.cases dest: red1_τmove1_heap_unchanged)
next
  fix s ta s'
  assume "τMOVE1 P s ta s'"
  thus "ta = ε" by(simp add: split_beta)
qed

interpretation Red1'_τmthr_wf: τmultithreaded_wf final_expr1 "mred1' P" "τMOVE1 P" wfs for P wfs
by(rule Red1'_τmthr_wf)

lemma Red1_mthr: "multithreaded (mred1 P)"
apply(unfold_locales)
apply(fastsimp elim!: Red1.cases dest: red1_new_thread_heap)
done

interpretation Red1_mthr: multithreaded final_expr1 "mred1 P" for P
by(rule Red1_mthr)

interpretation Red1_τmthr : τmultithreaded final_expr1 "mred1 P" "τMOVE1 P" for P
.

interpretation Red1_mthr: final_thread_wf final_expr1 "mred1 P" for P
by(unfold_locales)(auto elim!: Red1.cases simp add: final_iff)

lemma Red1_τmthr_wf: "τmultithreaded_wf final_expr1 (mred1 P) (τMOVE1 P) wfs"
proof
  fix x1 m1 ta1 x1' m1'
  assume "mred1 P (x1, m1) ta1 (x1', m1')" "τMOVE1 P (x1, m1) ta1 (x1', m1')"
  thus "m1 = m1'" by(cases x1)(fastsimp elim!: Red1.cases dest: red1_τmove1_heap_unchanged)
next
  fix s ta s'
  assume "τMOVE1 P s ta s'"
  thus "ta = ε" by(simp add: split_beta)
qed

interpretation Red'_τmthr_wf: τmultithreaded_wf final_expr1 "mred1 P" "τMOVE1 P" wfs for P wfs
by(rule Red1_τmthr_wf)

end