Theory J0

Up to index of Isabelle/HOL/JinjaThreads

theory J0
imports Threaded FWBisimulation

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

header {*
  \chapter{Compilation}\label{cha:comp}
  \isaheader{The JinjaThreads source language with explicit call stacks}
*}
theory J0 imports
  "../J/WWellForm"
  "../J/WellType"
  "../J/Threaded" 
  "../Framework/FWBisimulation" 
begin

declare widen_refT [elim]

consts
  call :: "('a,'b) exp => (addr × mname × val list) option"
  calls :: "('a,'b) exp list => (addr × mname × val list) option"

primrec
  "call (new C) = None"
  "call (newA T⌊e⌉) = call e"
  "call (Cast C e) = call e"
  "call (Val v) = None"
  "call (Var V) = None"
  "call (V:=e) = call e"
  "call (e «bop» e') = (if is_val e then call e' else call e)"
  "call (a⌊i⌉) = (if is_val a then call i else call a)"
  "call (AAss a i e) = (if is_val a then (if is_val i then call e else call i) else call a)"
  "call (a•length) = call a"
  "call (e•F{D}) = call e"
  "call (FAss e F D e') = (if is_val e then call e' else call e)"
  "call (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 calls es) 
                     else call e)"
  "call ({V:T=vo; e}) = call e"
  "call (syncV (o') e) = call o'"
  "call (insyncV (a) e) = call e"
  "call (e;;e') = call e"
  "call (if (e) e1 else e2) = call e"
  "call (while(b) e) = None"
  "call (throw e) = call e"
  "call (try e1 catch(C V) e2) = call e1"

  "calls [] = None"
  "calls (e#es) = (if is_val e then calls es else call e)"

declare domIff[iff, simp del]

lemma calls_append [simp]:
  "calls (es @ es') = (if calls es = None ∧ is_vals es then calls es' else calls es)"
apply(induct es, auto)
done

lemma call_callE [consumes 1, case_names CallObj CallParams Call]:
  "[| call (obj•M(pns)) = ⌊(a, M', vs)⌋;
     call obj = ⌊(a, M', vs)⌋ ==> thesis; 
     !!v. [| obj = Val v; calls pns = ⌊(a, M', vs)⌋ |] ==> thesis;
     [| obj = addr a; pns = map Val vs; M = M' |] ==> thesis |] ==> thesis"
by(auto split: split_if_asm simp add: is_vals_conv)

lemma calls_conv:
  "calls es = ⌊aMvs⌋ <-> (∃vs e es'. es = map Val vs @ e # es' ∧ call e = ⌊aMvs⌋)"
proof(induct es)
  case Nil thus ?case by simp
next
  case (Cons e es)
  note IH = `(calls es = ⌊aMvs⌋) = (∃vs e es'. es = map Val vs @ e # es' ∧ call e = ⌊aMvs⌋)`
  show ?case
  proof(cases "is_val e")
    case True
    then obtain v where e: "e = Val v" by auto
    hence "calls (e # es) = calls es" by(auto)
    moreover from e
    have "(calls es = ⌊aMvs⌋) = (∃vs e' es'. e # es = map Val (v # vs) @ e' # es' ∧ call e' = ⌊aMvs⌋)"
      unfolding IH by(auto)
    also from e have "… = (∃vs e' es'. e # es = map Val vs @ e' # es' ∧ call e' = ⌊aMvs⌋)"
      apply(auto simp add: Cons_eq_append_conv)
      apply(rule_tac x="v # vs" in exI)
      by(clarsimp)
    finally show ?thesis .
  next
    case False
    show ?thesis
    proof(rule iffI)
      assume "calls (e # es) = ⌊aMvs⌋"
      with False have "call e = ⌊aMvs⌋" by(auto)
      hence "e # es = map Val [] @ e # es" "call e = ⌊aMvs⌋" by auto
      thus "∃vs e' es'. e # es = map Val vs @ e' # es' ∧ call e' = ⌊aMvs⌋" by blast
    next
      assume "∃vs e' es'. e # es = map Val vs @ e' # es' ∧ call e' = ⌊aMvs⌋"
      then obtain vs e' es' where "e # es = map Val vs @ e' # es'" "call e' = ⌊aMvs⌋" by(blast)
      moreover
      with False have "vs = []" 
        by-(erule contrapos_np, auto simp add: neq_Nil_conv)
      ultimately show "calls (e # es) = ⌊aMvs⌋" by(auto)
    qed
  qed
qed

lemma calls_map_Val [simp]:
  "calls (map Val vs) = None"
by(induct vs, auto)

lemma call_not_is_val [dest]: "call e = ⌊aMvs⌋ ==> ¬ is_val e"
by(cases e, auto)

lemma is_calls_not_is_vals [dest]: "calls es = ⌊aMvs⌋ ==> ¬ is_vals es"
by(induct es, auto)


consts
  inline_call :: "('a,'b) exp => ('a,'b) exp => ('a,'b) exp"
  inline_calls :: "('a,'b) exp => ('a,'b) exp list => ('a,'b) exp list"

primrec
  "inline_call f (new C) = new C"
  "inline_call f (newA T⌊e⌉) = newA T⌊inline_call f e⌉"
  "inline_call f (Cast C e) = Cast C (inline_call f e)"
  "inline_call f (Val v) = Val v"
  "inline_call f (Var V) = Var V"
  "inline_call f (V:=e) = V := inline_call f e"
  "inline_call f (e «bop» e') = (if is_val e then (e «bop» inline_call f e') else (inline_call f e «bop» e'))"
  "inline_call f (a⌊i⌉) = (if is_val a then a⌊inline_call f i⌉ else (inline_call f a)⌊i⌉)"
  "inline_call f (AAss a i e) = (if is_val a then if is_val i then AAss a i (inline_call f e) else AAss a (inline_call f i) e else AAss (inline_call f a) i e)"
  "inline_call f (a•length) = inline_call f a•length"
  "inline_call f (e•F{D}) = inline_call f e•F{D}"
  "inline_call f (FAss e F D e') = (if is_val e then FAss e F D (inline_call f e') else FAss (inline_call f e) F D e')"
  "inline_call f (e•M(es)) = (if is_val e then if is_vals es ∧ is_addr e then f else e•M(inline_calls f es) else inline_call f e•M(es))"
  "inline_call f ({V:T=vo; e}) = {V:T=vo; inline_call f e}"
  "inline_call f (syncV (o') e) = syncV (inline_call f o') e"
  "inline_call f (insyncV (a) e) = insyncV (a) (inline_call f e)"
  "inline_call f (e;;e') = inline_call f e;;e'"
  "inline_call f (if (b) e else e') = (if (inline_call f b) e else e')"
  "inline_call f (while (b) e) = while (b) e"
  "inline_call f (throw e) = throw (inline_call f e)"
  "inline_call f (try e1 catch(C V) e2) = try inline_call f e1 catch(C V) e2"

  "inline_calls f [] = []"
  "inline_calls f (e#es) = (if is_val e then e # inline_calls f es else inline_call f e # es)"

lemma inline_calls_map_Val_append [simp]:
  "inline_calls f (map Val vs @ es) = map Val vs @ inline_calls f es"
by(induct vs, auto)

lemma inline_call_eq_Val_aux:
  "inline_call e E = Val v ==> call E = ⌊aMvs⌋ ==> e = Val v"
by(induct E)(auto split: split_if_asm)

lemmas inline_call_eq_Val [dest] = inline_call_eq_Val_aux inline_call_eq_Val_aux[OF sym, THEN sym]

lemma inline_calls_eq_empty [simp]: "inline_calls e es = [] <-> es = []"
by(cases es, auto)

lemma inline_calls_map_Val [simp]: "inline_calls e (map Val vs) = map Val vs"
by(induct vs) auto

lemma  fixes E :: "('a,'b) exp" and Es :: "('a,'b) exp list"
  shows inline_call_eq_Throw [dest]: "inline_call e E = Throw a ==> call E = ⌊aMvs⌋ ==> e = Throw a ∨ e = addr a"
  and True
by(induct E and Es)(fastsimp split:split_if_asm)+

lemma Throw_eq_inline_call_eq [dest]:
  "inline_call e E = Throw a ==> call E = ⌊aMvs⌋ ==> Throw a = e ∨ addr a = e"
by(auto dest: inline_call_eq_Throw[OF sym])

lemma is_vals_inline_calls [dest]:
  "[| is_vals (inline_calls e es); calls es = ⌊aMvs⌋ |] ==> is_val e"
by(induct es, auto split: split_if_asm)

lemma [dest]: "[| inline_calls e es = map Val vs; calls es = ⌊aMvs⌋ |] ==> is_val e"
              "[| map Val vs = inline_calls e es; calls es = ⌊aMvs⌋ |] ==> is_val e"
by(fastsimp intro!: is_vals_inline_calls del: is_val.intros simp add: is_vals_conv elim: sym)+

lemma inline_calls_eq_Val_Throw [dest]:
  "[| inline_calls e es = map Val vs @ Throw a # es'; calls es = ⌊aMvs⌋ |] ==> e = Throw a ∨ is_val e"
apply(induct es arbitrary: vs a es')
apply(auto simp add: Cons_eq_append_conv split: split_if_asm)
done

lemma Val_Throw_eq_inline_calls [dest]:
  "[| map Val vs @ Throw a # es' = inline_calls e es; calls es = ⌊aMvs⌋ |] ==> Throw a = e ∨ is_val e"
by(auto dest: inline_calls_eq_Val_Throw[OF sym])

declare option.split [split del] split_if_asm [split]  split_if [split del]

lemma call_inline_call [simp]:
  "call e = ⌊aMvs⌋ ==> call (inline_call {v:T=vo; e'} e) = call e'"
  "calls es = ⌊aMvs⌋ ==> calls (inline_calls {v:T=vo;e'} es) = call e'"
apply(induct e and es)
apply(fastsimp)
apply(fastsimp)
apply(fastsimp)
apply(fastsimp)
apply(fastsimp split: split_if)
apply(fastsimp)
apply(fastsimp)
apply(fastsimp split: split_if)
apply(clarsimp)
 apply(fastsimp split: split_if)
apply(fastsimp split: split_if)
apply(fastsimp)
apply(fastsimp)
apply(fastsimp split: split_if)
apply(fastsimp split: split_if)
apply(fastsimp)
apply(fastsimp)
apply(fastsimp)
apply(fastsimp)
apply(fastsimp)
apply(fastsimp)
apply(fastsimp)
apply(fastsimp)
apply(fastsimp)
apply(fastsimp split: split_if)
done

declare option.split [split] split_if [split] split_if_asm [split del]

lemma fv_inline_call: "call e = ⌊aMvs⌋ ==> fv (inline_call e' e) ⊆ fv e ∪ fv e'"
  and fvs_inline_calls: "calls es = ⌊aMvs⌋ ==> fvs (inline_calls e' es) ⊆ fvs es ∪ fv e'"
by(induct e and es)(fastsimp split: split_if_asm)+

lemma contains_insync_inline_call_conv:
  "contains_insync (inline_call e e') <-> contains_insync e ∧ call e' ≠ None ∨ contains_insync e'"
  and contains_insyncs_inline_calls_conv:
   "contains_insyncs (inline_calls e es') <-> contains_insync e ∧ calls es' ≠ None ∨ contains_insyncs es'"
by(induct e' and es')(auto split: split_if_asm simp add: is_vals_conv)

lemma contains_insync_inline_call [simp]:
  "call e' = ⌊aMvs⌋ ==> contains_insync (inline_call e e') <-> contains_insync e ∨ contains_insync e'"
  and contains_insyncs_inline_calls [simp]:
  "calls es' = ⌊aMvs⌋ ==> contains_insyncs (inline_calls e es') <-> contains_insync e ∨ contains_insyncs es'"
by(simp_all add: contains_insync_inline_call_conv contains_insyncs_inline_calls_conv)


definition synthesized_call :: "'m prog => heap => (addr × mname × val list) => bool"
where "synthesized_call P h = (λ(a, M, vs). ∃T. typeofh (Addr a) = ⌊T⌋ ∧ is_external_call P T M)"

lemma synthesized_call_conv:
  "synthesized_call P h (a, M, vs) = (∃T. typeofh (Addr a) = ⌊T⌋ ∧ is_external_call P T M)"
by(simp add: synthesized_call_def)

types
  J0_thread_action = "(addr,thread_id,expr × expr list,heap,addr,obs_event option) thread_action"

translations
  "J0_thread_action" <= (type) "(nat,nat,expr × expr list,heap,nat,obs_event option) thread_action"

definition extNTA2J0 :: "J_prog => (cname × mname × addr) => (expr × expr list)"
where
  "extNTA2J0 P = (λ(C, M, a). let (D, _, _, _, body) = method P C M
                               in ({this:Class D=⌊Addr a⌋; body}, [addr a•M([])]))"

lemma extNTA2J0_iff [simp]:
  "extNTA2J0 P (C, M, a) = 
   ({this:Class (fst (method P C M))=⌊Addr a⌋; snd (snd (snd (snd (method P C M))))}, [addr a•M([])])"
by(simp add: extNTA2J0_def split_def)

abbreviation extTA2J0 :: "J_prog => external_thread_action => J0_thread_action"
where "extTA2J0 P ≡ convert_extTA (extNTA2J0 P)"

inductive red0 :: "J_prog => expr => expr list => heap =>
                           J0_thread_action => expr => expr list => heap => bool"
                ("_ \<turnstile>0 ((1⟨_'/_,/_⟩) -_->/ (1⟨_'/_,/_⟩))" [51,0,0,0,0,0,0,0] 81)
for P ::J_prog
where

  red0Red:
  "[| extTA2J0 P,P \<turnstile> ⟨e, (h, empty)⟩ -ta-> ⟨e', (h', xs')⟩;
     ∀aMvs. call e = ⌊aMvs⌋ --> synthesized_call P h aMvs |]
  ==> P \<turnstile>0 ⟨e/es, h⟩ -ta-> ⟨e'/es, h'⟩"

| red0Call:
  "[| call e = ⌊(a, M, vs)⌋; h a = ⌊Obj C fs⌋; ¬ is_external_call P (Class C) M; P \<turnstile> C sees M:Ts->T = (pns, body) in D; 
     size vs = size pns; size Ts = size pns |]
  ==> P \<turnstile>0 ⟨e/es, h⟩ -ε-> ⟨blocks(this#pns, Class D#Ts, Addr a#vs, body)/e#es, h⟩"

| red0Return:
  "final e' ==> P \<turnstile>0 ⟨e'/e#es, h⟩ -ε-> ⟨inline_call e' e/es, h⟩"

lemma fv_extRet2J [simp]: "fv (extRet2J va) = {}"
by(cases va) simp_all

lemma assumes wf: "wwf_J_prog P"
  shows red_fv_subset: "extTA,P \<turnstile> ⟨e, s⟩ -ta-> ⟨e', s'⟩ ==> fv e' ⊆ fv e"
  and reds_fvs_subset: "extTA,P \<turnstile> ⟨es, s⟩ [-ta->] ⟨es', s'⟩ ==> fvs es' ⊆ fvs es"
proof(induct rule: red_reds.inducts)
  case (RedCall s a C fs M Ts T pns body D vs)
  hence "fv body ⊆ {this} ∪ set pns"
    using wf by(fastsimp dest!:sees_wf_mdecl simp:wf_mdecl_def)
  with RedCall show ?case by fastsimp
qed(fastsimp)+

declare domIff[iff del]

lemma assumes wwf: "wwf_J_prog P"
  shows red_fv_ok: "[| extTA,P \<turnstile> ⟨e, s⟩ -ta-> ⟨e', s'⟩; fv e ⊆ dom (lcl s) |] ==> fv e' ⊆ dom (lcl s')"
  and reds_fvs_ok: "[| extTA,P \<turnstile> ⟨es, s⟩ [-ta->] ⟨es', s'⟩; fvs es ⊆ dom (lcl s) |] ==> fvs es' ⊆ dom (lcl s')"
proof(induct rule: red_reds.inducts)
  case (RedCall s a C fs M Ts T pns body D vs)
  from `P \<turnstile> C sees M: Ts->T = (pns, body) in D` have "wwf_J_mdecl P D (M,Ts,t,pns,body)"
    by(auto dest!: sees_wf_mdecl[OF wwf] simp add: wf_mdecl_def)
  with RedCall show ?case by(auto)
next
  case (BlockRed e h x V vo ta e' h' x' T)
  note red = `extTA,P \<turnstile> ⟨e,(h, x(V := vo))⟩ -ta-> ⟨e',(h', x')⟩`
  hence "fv e' ⊆ fv e" by(auto dest: red_fv_subset[OF wwf] del: subsetI)
  moreover from ` fv {V:T=vo; e} ⊆ dom (lcl (h, x))`
  have "fv e - {V} ⊆ dom x" by(simp)
  ultimately have "fv e' - {V} ⊆ dom x - {V}" by(auto)
  moreover from red have "dom (x(V := vo)) ⊆ dom x'"
    by(auto dest: red_lcl_incr del: subsetI)
  ultimately have "fv e' - {V} ⊆ dom x' - {V}"
    by(auto split: split_if_asm)
  thus ?case by(auto simp del: fun_upd_apply)
qed(fastsimp dest: red_lcl_incr del: subsetI)+


lemma is_call_red_state_unchanged: 
  "[| extTA,P \<turnstile> ⟨e, s⟩ -ta-> ⟨e', s'⟩; call e = ⌊aMvs⌋; ¬ synthesized_call P (hp s) aMvs |] ==> s' = s ∧ ta = ε"

  and is_calls_reds_state_unchanged:
  "[| extTA,P \<turnstile> ⟨es, s⟩ [-ta->] ⟨es', s'⟩; calls es = ⌊aMvs⌋; ¬ synthesized_call P (hp s) aMvs |] ==> s' = s ∧ ta = ε"
apply(induct rule: red_reds.inducts)
apply(fastsimp split: split_if_asm simp add: synthesized_call_def)+
done


lemma called_methodD:
        "[| extTA,P \<turnstile> ⟨e, s⟩ -ta-> ⟨e', s'⟩; call e = ⌊(a, M, vs)⌋; ¬ synthesized_call P (hp s) (a, M, vs) |] 
         ==> ∃C fs D Us U pns body. hp s' = hp s ∧ hp s a = ⌊Obj C fs⌋ ∧ P \<turnstile> C sees M: Us->U = (pns, body) in D ∧
                                   length vs = length pns ∧ length Us = length pns"
        (is "[| _; _; _ |] ==>  ?concl")

  and called_methodsD:
        "[| extTA,P \<turnstile> ⟨es, s⟩ [-ta->] ⟨es', s'⟩; calls es = ⌊(a, M, vs)⌋; ¬ synthesized_call P (hp s) (a, M, vs) |] 
         ==> ∃C fs D Us U pns body. hp s' = hp s ∧ hp s a = ⌊Obj C fs⌋ ∧ P \<turnstile> C sees M: Us->U = (pns, body) in D ∧
                                   length vs = length pns ∧ length Us = length pns"
        (is "[| _; _; _ |] ==>  ?concl")
apply(induct rule: red_reds.inducts)
apply(auto split: split_if_asm simp add: synthesized_call_def)
apply(fastsimp)
done

abbreviation mred0 :: "J_prog => (addr,addr,expr × expr list,heap,addr,obs_event) semantics"
where "mred0 P ≡ (λ((e, es), h) ta ((e', es'), h'). red0 P e es h ta e' es' h')"

section {* Silent moves *}

primrec  τmove0 :: "'m prog => heap => ('a, 'b) exp => bool"
  and τmoves0 :: "'m prog => heap => ('a, 'b) exp list => bool"
where
  "τmove0 P h (new C) <-> False"
| "τmove0 P h (newA T⌊e⌉) <-> τmove0 P h e ∨ (∃a. e = Throw a)"
| "τmove0 P h (Cast U e) <-> τmove0 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v)"
| "τmove0 P h (e «bop» e') <-> τmove0 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v ∧
   (τmove0 P h e' ∨ (∃a. e' = Throw a) ∨ (∃v. e' = Val v)))"
| "τmove0 P h (Val v) <-> False"
| "τmove0 P h (Var V) <-> True"
| "τmove0 P h (V := e) <-> τmove0 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v)"
| "τmove0 P h (a⌊i⌉) <-> τmove0 P h a ∨ (∃ad. a = Throw ad) ∨ (∃v. a = Val v ∧ (τmove0 P h i ∨ (∃a. i = Throw a)))"
| "τmove0 P h (AAss a i e) <-> τmove0 P h a ∨ (∃ad. a = Throw ad) ∨ (∃v. a = Val v ∧ 
   (τmove0 P h i ∨ (∃a. i = Throw a) ∨ (∃v. i = Val v ∧ (τmove0 P h e ∨ (∃a. e = Throw a)))))"
| "τmove0 P h (a•length) <-> τmove0 P h a ∨ (∃ad. a = Throw ad)"
| "τmove0 P h (e•F{D}) <-> τmove0 P h e ∨ (∃a. e = Throw a)"
| "τmove0 P h (FAss e F D e') <-> τmove0 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v ∧ (τmove0 P h e' ∨ (∃a. e' = Throw a)))"
| "τmove0 P h (e•M(es)) <-> τmove0 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v ∧
   ((τmoves0 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)))))"
| "τmove0 P h ({V:T=vo; e}) <-> τmove0 P h e ∨ ((∃a. e = Throw a) ∨ (∃v. e = Val v))"
| "τmove0 P h (syncV'(e) e') <-> τmove0 P h e ∨ (∃a. e = Throw a)"
| "τmove0 P h (insyncV'(ad) e) <-> τmove0 P h e"
| "τmove0 P h (e;;e') <-> τmove0 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v)"
| "τmove0 P h (if (e) e' else e'') <-> τmove0 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v)"
| "τmove0 P h (while (e) e') = True"
| "τmove0 P h (throw e) <-> τmove0 P h e ∨ (∃a. e = Throw a) ∨ e = null"
| "τmove0 P h (try e catch(C V) e') <-> τmove0 P h e ∨ (∃a. e = Throw a) ∨ (∃v. e = Val v)"

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

lemma τmove0_τmoves0_intros:
  fixes e e1 e2 e' :: "('a, 'b) exp" and es :: "('a, 'b) exp list"
  shows τmove0NewArray: "τmove0 P h e ==> τmove0 P h (newA T⌊e⌉)"
  and τmove0Cast: "τmove0 P h e ==> τmove0 P h (Cast U e)"
  and τmove0CastRed: "τmove0 P h (Cast U (Val v))"
  and τmove0BinOp1: "τmove0 P h e ==> τmove0 P h (e«bop»e')"
  and τmove0BinOp2: "τmove0 P h e ==> τmove0 P h (Val v«bop»e)"
  and τmove0BinOp: "τmove0 P h (Val v«bop»Val v')"
  and τmove0Var: "τmove0 P h (Var V)"
  and τmove0LAss: "τmove0 P h e ==> τmove0 P h (V := e)"
  and τmove0LAssRed: "τmove0 P h (V := Val v)"
  and τmove0AAcc1: "τmove0 P h e ==> τmove0 P h (e⌊e'⌉)"
  and τmove0AAcc2: "τmove0 P h e ==> τmove0 P h (Val v⌊e⌉)"
  and τmove0AAss1: "τmove0 P h e ==> τmove0 P h (e⌊e1⌉ := e2)"
  and τmove0AAss2: "τmove0 P h e ==> τmove0 P h (Val v⌊e⌉ := e')"
  and τmove0AAss3: "τmove0 P h e ==> τmove0 P h (Val v⌊Val v'⌉ := e)"
  and τmove0ALength: "τmove0 P h e ==> τmove0 P h (e•length)"
  and τmove0FAcc: "τmove0 P h e ==> τmove0 P h (e•F{D})"
  and τmove0FAss1: "τmove0 P h e ==> τmove0 P h (FAss e F D e')"
  and τmove0FAss2: "τmove0 P h e ==> τmove0 P h (Val v•F{D} := e)"
  and τmove0CallObj: "τmove0 P h e ==> τmove0 P h (e•M(es))"
  and τmove0CallParams: "τmoves0 P h es ==> τmove0 P h (Val v•M(es))"
  and τmove0Call: "(!!T. typeofh v = ⌊T⌋ ==> ¬ is_external_call P T M) ==> τmove0 P h (Val v•M(map Val vs))"
  and τmove0Block: "τmove0 P h e ==> τmove0 P h {V:T=vo; e}"
  and τmove0BlockRed: "τmove0 P h {V:T=vo; Val v}"
  and τmove0Sync: "τmove0 P h e ==> τmove0 P h (syncV' (e) e')"
  and τmove0InSync: "τmove0 P h e ==> τmove0 P h (insyncV' (a) e)"
  and τmove0Seq: "τmove0 P h e ==> τmove0 P h (e;;e')"
  and τmove0SeqRed: "τmove0 P h (Val v;; e')"
  and τmove0Cond: "τmove0 P h e ==> τmove0 P h (if (e) e1 else e2)"
  and τmove0CondRed: "τmove0 P h (if (Val v) e1 else e2)"
  and τmove0WhileRed: "τmove0 P h (while (e) e')"
  and τmove0Throw: "τmove0 P h e ==> τmove0 P h (throw e)"
  and τmove0ThrowNull: "τmove0 P h (throw null)"
  and τmove0Try: "τmove0 P h e ==> τmove0 P h (try e catch(C V) e')"
  and τmove0TryRed: "τmove0 P h (try Val v catch(C V) e)"
  and τmove0TryThrow: "τmove0 P h (try Throw a catch(C V) e)"
  and τmove0NewArrayThrow: "τmove0 P h (newA T⌊Throw a⌉)"
  and τmove0CastThrow: "τmove0 P h (Cast T (Throw a))"
  and τmove0BinOpThrow1: "τmove0 P h (Throw a «bop» e')"
  and τmove0BinOpThrow2: "τmove0 P h (Val v «bop» Throw a)"
  and τmove0LAssThrow: "τmove0 P h (V:=(Throw a))"
  and τmove0AAccThrow1: "τmove0 P h (Throw a⌊e⌉)"
  and τmove0AAccThrow2: "τmove0 P h (Val v⌊Throw a⌉)"
  and τmove0AAssThrow1: "τmove0 P h (AAss (Throw a) e e')"
  and τmove0AAssThrow2: "τmove0 P h (AAss (Val v) (Throw a) e')"
  and τmove0AAssThrow3: "τmove0 P h (AAss (Val v) (Val v') (Throw a))"
  and τmove0ALengthThrow: "τmove0 P h (Throw a•length)"
  and τmove0FAccThrow: "τmove0 P h (Throw a•F{D})"
  and τmove0FAssThrow1: "τmove0 P h (Throw a•F{D} := e)"
  and τmove0FAssThrow2: "τmove0 P h (FAss (Val v) F D (Throw a))"
  and τmove0CallThrowObj: "τmove0 P h (Throw a•M(es))"
  and τmove0CallThrowParams: "τmove0 P h (Val v•M(map Val vs @ Throw a # es))"
  and τmove0BlockThrow: "τmove0 P h {V:T=vo; Throw a}"
  and τmove0SyncThrow: "τmove0 P h (syncV' (Throw a) e)"
  and τmove0SeqThrow: "τmove0 P h (Throw a;;e)"
  and τmove0CondThrow: "τmove0 P h (if (Throw a) e1 else e2)"
  and τmove0ThrowThrow: "τmove0 P h (throw (Throw a))"

  and τmoves0Hd: "τmove0 P h e ==> τmoves0 P h (e # es)"
  and τmoves0Tl: "τmoves0 P h es ==> τmoves0 P h (Val v # es)"
apply auto
done

lemma τmoves0_map_Val [iff]:
  "¬ τmoves0 P h (map Val vs)"
by(induct vs) auto

lemma τmoves0_map_Val_append [simp]:
  "τmoves0 P h (map Val vs @ es) = τmoves0 P h es"
by(induct vs)(auto)

lemma no_reds_map_Val_Throw [simp]:
  "extTA,P \<turnstile> ⟨map Val vs @ Throw a # es, s⟩ [-ta->] ⟨es', s'⟩ = False"
by(induct vs arbitrary: es')(auto elim: reds.cases)

lemma red_τ_taD: "[| extTA,P \<turnstile> ⟨e, s⟩ -ta-> ⟨e', s'⟩; τmove0 P (hp s) e |] ==> ta = ε"
  and reds_τ_taD: "[| extTA,P \<turnstile> ⟨es, s⟩ [-ta->] ⟨es', s'⟩; τmoves0 P (hp s) es |] ==> ta = ε"
apply(induct rule: red_reds.inducts)
apply(fastsimp simp add: map_eq_append_conv)+
done

lemma τmove0_heap_unchanged: "[| extTA,P \<turnstile> ⟨e, s⟩ -ta-> ⟨e', s'⟩; τmove0 P (hp s) e |] ==> hp s' = hp s"
  and τmoves0_heap_unchanged: "[| extTA,P \<turnstile> ⟨es, s⟩ [-ta->] ⟨es', s'⟩; τmoves0 P (hp s) es |] ==> hp s' = hp s"
apply(induct rule: red_reds.inducts)
apply(auto)
apply(fastsimp simp add: map_eq_append_conv)
done

primrec τMove0 :: "'m prog => heap => (expr × expr list) => bool"
where
  "τMove0 P h (e, exs) = (τmove0 P h e ∨ final e)"

lemma τMove0_iff:
  "τMove0 P h ees <-> (let (e, _) = ees in τmove0 P h e ∨ final e)"
by(cases ees)(simp)

definition no_call :: "'m prog => heap => ('a, 'b) exp => bool"
where "no_call P h e = (∀aMvs. call e = ⌊aMvs⌋ --> synthesized_call P h aMvs)"

definition no_calls :: "'m prog => heap => ('a, 'b) exp list => bool"
where "no_calls P h es = (∀aMvs. calls es = ⌊aMvs⌋ --> synthesized_call P h aMvs)"

lemma no_call_simps [simp]:
  "no_call P h (new C) = True"
  "no_call P h (newA T⌊e⌉) = no_call P h e"
  "no_call P h (Cast T e) = no_call P h e"
  "no_call P h (Val v) = True"
  "no_call P h (Var V) = True"
  "no_call P h (V := e) = no_call P h e"
  "no_call P h (e «bop» e') = (if is_val e then no_call P h e' else no_call P h e)"
  "no_call P h (a⌊i⌉) = (if is_val a then no_call P h i else no_call P h a)"
  "no_call P h (AAss a i e) = (if is_val a then (if is_val i then no_call P h e else no_call P h i) else no_call P h a)"
  "no_call P h (a•length) = no_call P h a"
  "no_call P h (e•F{D}) = no_call P h e"
  "no_call P h (FAss e F D e') = (if is_val e then no_call P h e' else no_call P h e)"
  "no_call P h (e•M(es)) = (if is_val e then (if is_vals es ∧ is_addr e then synthesized_call P h (THE a. e = addr a, M, THE vs. es = map Val vs) else no_calls P h es) else no_call P h e)"
  "no_call P h ({V:T=vo; e}) = no_call P h e"
  "no_call P h (syncV' (e) e') = no_call P h e"
  "no_call P h (insyncV' (ad) e) = no_call P h e"
  "no_call P h (e;;e') = no_call P h e"
  "no_call P h (if (e) e1 else e2) = no_call P h e"
  "no_call P h (while(e) e') = True"
  "no_call P h (throw e) = no_call P h e"
  "no_call P h (try e catch(C V) e') = no_call P h e"
by(auto simp add: no_call_def no_calls_def)

lemma no_calls_simps [simp]:
  "no_calls P h [] = True"
  "no_calls P h (e # es) = (if is_val e then no_calls P h es else no_call P h e)"
by(simp_all add: no_call_def no_calls_def)

lemma no_calls_map_Val [simp]:
  "no_calls P h (map Val vs)"
by(induct vs) simp_all

definition τred0 :: "(external_thread_action => (addr,thread_id,'x,heap,addr,obs_event option) thread_action) =>
  J_prog => heap => (expr × locals) => (expr × locals) => bool"
where "τred0 extTA P h exs e'xs' = (extTA,P \<turnstile> ⟨fst exs, (h, snd exs)⟩ -ε-> ⟨fst e'xs', (h, snd e'xs')⟩ ∧ τmove0 P h (fst exs) ∧ no_call P h (fst exs))"

definition τreds0 :: "(external_thread_action => (addr,thread_id,'x,heap,addr,obs_event option) thread_action) =>
  J_prog => heap => (expr list × locals) => (expr list × locals) => bool"
where "τreds0 extTA P h esxs es'xs' = (extTA,P \<turnstile> ⟨fst esxs, (h, snd esxs)⟩ [-ε->] ⟨fst es'xs', (h, snd es'xs')⟩ ∧ τmoves0 P h (fst esxs) ∧ no_calls P h (fst esxs))"

abbreviation τred0t :: "(external_thread_action => (addr,thread_id,'x,heap,addr,obs_event option) thread_action) => 
  J_prog => heap => (expr × locals) => (expr × locals) => bool"
where "τred0t extTA P h ≡ (τred0 extTA P h)^++"

abbreviation τreds0t :: "(external_thread_action => (addr,thread_id,'x,heap,addr,obs_event option) thread_action) =>
  J_prog => heap => (expr list × locals) => (expr list × locals) => bool"
where "τreds0t extTA P h ≡ (τreds0 extTA P h)^++"

abbreviation τred0r :: "(external_thread_action => (addr,thread_id,'x,heap,addr,obs_event option) thread_action) => 
  J_prog => heap => (expr × locals) => (expr × locals) => bool"
where "τred0r extTA P h ≡ (τred0 extTA P h)^**"

abbreviation τreds0r :: "(external_thread_action => (addr,thread_id,'x,heap,addr,obs_event option) thread_action) =>
  J_prog => heap => (expr list × locals) => (expr list × locals) => bool"
where "τreds0r extTA P h ≡ (τreds0 extTA P h)^**"

lemma τred0_iff [iff]:
  "τred0 extTA P h (e, xs) (e', xs') = (extTA,P \<turnstile> ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩ ∧ τmove0 P h e ∧ no_call P h e)"
by(simp add: τred0_def)

lemma τreds0_iff [iff]:
  "τreds0 extTA P h (es, xs) (es', xs') = (extTA,P \<turnstile> ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩ ∧ τmoves0 P h es ∧ no_calls P h es)"
by(simp add: τreds0_def)

lemma τred0t_1step:
  "[| extTA,P \<turnstile> ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove0 P h e; no_call P h e |]
  ==> τred0t extTA P h (e, xs) (e', xs')"
by(blast intro: tranclp.r_into_trancl)

lemma τred0t_2step:
  "[| extTA,P \<turnstile> ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove0 P h e; no_call P h e;
     extTA,P \<turnstile> ⟨e', (h, xs')⟩ -ε-> ⟨e'', (h, xs'')⟩; τmove0 P h e'; no_call P h e' |]
  ==> τred0t extTA P h (e, xs) (e'', xs'')"
by(blast intro: tranclp.trancl_into_trancl[OF τred0t_1step])

lemma τred1t_3step:
  "[| extTA,P \<turnstile> ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove0 P h e; no_call P h e; 
     extTA,P \<turnstile> ⟨e', (h, xs')⟩ -ε-> ⟨e'', (h, xs'')⟩; τmove0 P h e'; no_call P h e';
     extTA,P \<turnstile> ⟨e'', (h, xs'')⟩ -ε-> ⟨e''', (h, xs''')⟩; τmove0 P h e''; no_call P h e'' |]
  ==> τred0t extTA P h (e, xs) (e''', xs''')"
by(blast intro: tranclp.trancl_into_trancl[OF τred0t_2step])

lemma τreds0t_1step:
  "[| extTA,P \<turnstile> ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves0 P h es; no_calls P h es |]
  ==> τreds0t extTA P h (es, xs) (es', xs')"
by(blast intro: tranclp.r_into_trancl)

lemma τreds0t_2step:
  "[| extTA,P \<turnstile> ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves0 P h es; no_calls P h es; 
     extTA,P \<turnstile> ⟨es', (h, xs')⟩ [-ε->] ⟨es'', (h, xs'')⟩; τmoves0 P h es'; no_calls P h es' |]
  ==> τreds0t extTA P h (es, xs) (es'', xs'')"
by(blast intro: tranclp.trancl_into_trancl[OF τreds0t_1step])

lemma τreds0t_3step:
  "[| extTA,P \<turnstile> ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves0 P h es; no_calls P h es; 
     extTA,P \<turnstile> ⟨es', (h, xs')⟩ [-ε->] ⟨es'', (h, xs'')⟩; τmoves0 P h es'; no_calls P h es';
     extTA,P \<turnstile> ⟨es'', (h, xs'')⟩ [-ε->] ⟨es''', (h, xs''')⟩; τmoves0 P h es''; no_calls P h es'' |]
  ==> τreds0t extTA P h (es, xs) (es''', xs''')"
by(blast intro: tranclp.trancl_into_trancl[OF τreds0t_2step])

lemma τred0r_1step:
  "[| extTA,P \<turnstile> ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove0 P h e; no_call P h e |]
  ==> τred0r extTA P h (e, xs) (e', xs')"
by(blast intro: r_into_rtranclp)

lemma τred0r_2step:
  "[| extTA,P \<turnstile> ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove0 P h e; no_call P h e;
     extTA,P \<turnstile> ⟨e', (h, xs')⟩ -ε-> ⟨e'', (h, xs'')⟩; τmove0 P h e'; no_call P h e' |]
  ==> τred0r extTA P h (e, xs) (e'', xs'')"
by(blast intro: rtranclp.rtrancl_into_rtrancl[OF τred0r_1step])

lemma τred0r_3step:
  "[| extTA,P \<turnstile> ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩; τmove0 P h e; no_call P h e; 
     extTA,P \<turnstile> ⟨e', (h, xs')⟩ -ε-> ⟨e'', (h, xs'')⟩; τmove0 P h e'; no_call P h e';
     extTA,P \<turnstile> ⟨e'', (h, xs'')⟩ -ε-> ⟨e''', (h, xs''')⟩; τmove0 P h e''; no_call P h e'' |]
  ==> τred0r extTA P h (e, xs) (e''', xs''')"
by(blast intro: rtranclp.rtrancl_into_rtrancl[OF τred0r_2step])

lemma τreds0r_1step:
  "[| extTA,P \<turnstile> ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves0 P h es; no_calls P h es |]
  ==> τreds0r extTA P h (es, xs) (es', xs')"
by(blast intro: r_into_rtranclp)

lemma τreds0r_2step:
  "[| extTA,P \<turnstile> ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves0 P h es; no_calls P h es; 
     extTA,P \<turnstile> ⟨es', (h, xs')⟩ [-ε->] ⟨es'', (h, xs'')⟩; τmoves0 P h es'; no_calls P h es' |]
  ==> τreds0r extTA P h (es, xs) (es'', xs'')"
by(blast intro: rtranclp.rtrancl_into_rtrancl[OF τreds0r_1step])

lemma τreds0r_3step:
  "[| extTA,P \<turnstile> ⟨es, (h, xs)⟩ [-ε->] ⟨es', (h, xs')⟩; τmoves0 P h es; no_calls P h es; 
     extTA,P \<turnstile> ⟨es', (h, xs')⟩ [-ε->] ⟨es'', (h, xs'')⟩; τmoves0 P h es'; no_calls P h es';
     extTA,P \<turnstile> ⟨es'', (h, xs'')⟩ [-ε->] ⟨es''', (h, xs''')⟩; τmoves0 P h es''; no_calls P h es'' |]
  ==> τreds0r extTA P h (es, xs) (es''', xs''')"
by(blast intro: rtranclp.rtrancl_into_rtrancl[OF τreds0r_2step])

lemma τred0t_inj_τreds0t: "τred0t extTA P h (e, xs) (e', xs') ==> τreds0t extTA P h (e # es, xs) (e' # es, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl ListRed1)

lemma τreds0t_cons_τreds0t: "τreds0t extTA P h (es, xs) (es', xs') ==> τreds0t extTA P h (Val v # es, xs) (Val v # es', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl ListRed2)

lemma τred0r_inj_τreds0r: "τred0r extTA P h (e, xs) (e', xs') ==> τreds0r extTA P h (e # es, xs) (e' # es, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl ListRed1)

lemma τreds0r_cons_τreds0r: "τreds0r extTA P h (es, xs) (es', xs') ==> τreds0r extTA P h (Val v # es, xs) (Val v # es', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl ListRed2)

lemma NewArray_τred0t_xt:
  "τred0t extTA P h (e, xs) (e', xs') ==> τred0t extTA P h (newA T⌊e⌉, xs) (newA T⌊e'⌉, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl NewArrayRed)

lemma Cast_τred0t_xt:
  "τred0t extTA P h (e, xs) (e', xs') ==> τred0t extTA P h (Cast T e, xs) (Cast T e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl CastRed)

lemma BinOp_τred0t_xt1:
  "τred0t extTA P h (e1, xs) (e1', xs') ==> τred0t extTA P h (e1 «bop» e2, xs) (e1' «bop» e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl BinOpRed1)

lemma BinOp_τred0t_xt2:
  "τred0t extTA P h (e2, xs) (e2', xs') ==> τred0t extTA P h (Val v «bop» e2, xs) (Val v «bop» e2', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl BinOpRed2)

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

lemma AAcc_τred0t_xt1:
  "τred0t extTA P h (a, xs) (a', xs') ==> τred0t extTA P h (a⌊i⌉, xs) (a'⌊i⌉, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAccRed1)

lemma AAcc_τred0t_xt2:
  "τred0t extTA P h (i, xs) (i', xs') ==> τred0t extTA P h (Val a⌊i⌉, xs) (Val a⌊i'⌉, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAccRed2)

lemma AAss_τred0t_xt1:
  "τred0t extTA P h (a, xs) (a', xs') ==> τred0t extTA P h (a⌊i⌉ := e, xs) (a'⌊i⌉ := e, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAssRed1)

lemma AAss_τred0t_xt2:
  "τred0t extTA P h (i, xs) (i', xs') ==> τred0t extTA P h (Val a⌊i⌉ := e, xs) (Val a⌊i'⌉ := e, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl AAssRed2)

lemma AAss_τred0t_xt3:
  "τred0t extTA P h (e, xs) (e', xs') ==> τred0t extTA 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 AAssRed3)

lemma ALength_τred0t_xt:
  "τred0t extTA P h (a, xs) (a', xs') ==> τred0t extTA P h (a•length, xs) (a'•length, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl ALengthRed)

lemma FAcc_τred0t_xt:
  "τred0t extTA P h (e, xs) (e', xs') ==> τred0t extTA P h (e•F{D}, xs) (e'•F{D}, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl FAccRed)

lemma FAss_τred0t_xt1:
  "τred0t extTA P h (e, xs) (e', xs') ==> τred0t extTA P h (e•F{D} := e2, xs) (e'•F{D} := e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl FAssRed1)

lemma FAss_τred0t_xt2:
  "τred0t extTA P h (e, xs) (e', xs') ==> τred0t extTA 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 FAssRed2)

lemma Call_τred0t_obj:
  "τred0t extTA P h (e, xs) (e', xs') ==> τred0t extTA P h (e•M(ps), xs) (e'•M(ps), xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl CallObj)

lemma Call_τred0t_param:
  "τreds0t extTA P h (es, xs) (es', xs') ==> τred0t extTA P h (Val v•M(es), xs) (Val v•M(es'), xs')"
by(induct rule: tranclp_induct2)(fastsimp intro: tranclp.trancl_into_trancl CallParams)+

lemma Block_τred0t_xt:
  "τred0t extTA P h (e, xs(V := vo)) (e', xs') ==> τred0t extTA P h ({V:T=vo; e}, xs) ({V:T=xs' V; e'}, xs'(V := xs V))"
proof(induct rule: tranclp_induct2)
  case base thus ?case by(auto intro: BlockRed simp del: fun_upd_apply)
next
  case (step e' xs' e'' xs'')
  from `τred0 extTA P h (e', xs') (e'', xs'')` 
  have "extTA,P \<turnstile> ⟨e',(h, xs')⟩ -ε-> ⟨e'',(h, xs'')⟩" "τmove0 P h e'" "no_call P h e'" by auto
  hence "extTA,P \<turnstile> ⟨e',(h, xs'(V := xs V, V := xs' V))⟩ -ε-> ⟨e'',(h, xs'')⟩" by simp
  from BlockRed[OF this, of T] `τmove0 P h e'` `no_call P h e'`
  have "τred0 extTA P h ({V:T=xs' V; e'}, xs'(V := xs V)) ({V:T=xs'' V; e''}, xs''(V := xs V))" by(auto)
  with `τred0t extTA P h ({V:T=vo; e}, xs) ({V:T=xs' V; e'}, xs'(V := xs V))` show ?case ..
qed

lemma Sync_τred0t_xt:
  "τred0t extTA P h (e, xs) (e', xs') ==> τred0t extTA P h (syncV (e) e2, xs) (syncV (e') e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl SynchronizedRed1)

lemma InSync_τred0t_xt:
  "τred0t extTA P h (e, xs) (e', xs') ==> τred0t extTA P h (insyncV (a) e, xs) (insyncV (a) e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl SynchronizedRed2)

lemma Seq_τred0t_xt:
  "τred0t extTA P h (e, xs) (e', xs') ==> τred0t extTA P h (e;;e2, xs) (e';;e2, xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl SeqRed)

lemma Cond_τred0t_xt:
  "τred0t extTA P h (e, xs) (e', xs') ==> τred0t extTA 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 CondRed)

lemma Throw_τred0t_xt:
  "τred0t extTA P h (e, xs) (e', xs') ==> τred0t extTA P h (throw e, xs) (throw e', xs')"
by(induct rule: tranclp_induct2)(auto intro: tranclp.trancl_into_trancl ThrowRed)

lemma Try_τred0t_xt:
  "τred0t extTA P h (e, xs) (e', xs') ==> τred0t extTA 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 TryRed)

lemma NewArray_τred0r_xt:
  "τred0r extTA P h (e, xs) (e', xs') ==> τred0r extTA P h (newA T⌊e⌉, xs) (newA T⌊e'⌉, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl NewArrayRed)

lemma Cast_τred0r_xt:
  "τred0r extTA P h (e, xs) (e', xs') ==> τred0r extTA P h (Cast T e, xs) (Cast T e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl CastRed)

lemma BinOp_τred0r_xt1:
  "τred0r extTA P h (e1, xs) (e1', xs') ==> τred0r extTA P h (e1 «bop» e2, xs) (e1' «bop» e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl BinOpRed1)

lemma BinOp_τred0r_xt2:
  "τred0r extTA P h (e2, xs) (e2', xs') ==> τred0r extTA P h (Val v «bop» e2, xs) (Val v «bop» e2', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl BinOpRed2)

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

lemma AAcc_τred0r_xt1:
  "τred0r extTA P h (a, xs) (a', xs') ==> τred0r extTA P h (a⌊i⌉, xs) (a'⌊i⌉, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAccRed1)

lemma AAcc_τred0r_xt2:
  "τred0r extTA P h (i, xs) (i', xs') ==> τred0r extTA P h (Val a⌊i⌉, xs) (Val a⌊i'⌉, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAccRed2)

lemma AAss_τred0r_xt1:
  "τred0r extTA P h (a, xs) (a', xs') ==> τred0r extTA P h (a⌊i⌉ := e, xs) (a'⌊i⌉ := e, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAssRed1)

lemma AAss_τred0r_xt2:
  "τred0r extTA P h (i, xs) (i', xs') ==> τred0r extTA P h (Val a⌊i⌉ := e, xs) (Val a⌊i'⌉ := e, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl AAssRed2)

lemma AAss_τred0r_xt3:
  "τred0r extTA P h (e, xs) (e', xs') ==> τred0r extTA 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 AAssRed3)

lemma ALength_τred0r_xt:
  "τred0r extTA P h (a, xs) (a', xs') ==> τred0r extTA P h (a•length, xs) (a'•length, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl ALengthRed)

lemma FAcc_τred0r_xt:
  "τred0r extTA P h (e, xs) (e', xs') ==> τred0r extTA P h (e•F{D}, xs) (e'•F{D}, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl FAccRed)

lemma FAss_τred0r_xt1:
  "τred0r extTA P h (e, xs) (e', xs') ==> τred0r extTA P h (e•F{D} := e2, xs) (e'•F{D} := e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl FAssRed1)

lemma FAss_τred0r_xt2:
  "τred0r extTA P h (e, xs) (e', xs') ==> τred0r extTA 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 FAssRed2)

lemma Call_τred0r_obj:
  "τred0r extTA P h (e, xs) (e', xs') ==> τred0r extTA P h (e•M(ps), xs) (e'•M(ps), xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl CallObj)

lemma Call_τred0r_param:
  "τreds0r extTA P h (es, xs) (es', xs') ==> τred0r extTA P h (Val v•M(es), xs) (Val v•M(es'), xs')"
by(induct rule: rtranclp_induct2)(fastsimp intro: rtranclp.rtrancl_into_rtrancl CallParams)+

lemma Block_τred0r_xt:
  "τred0r extTA P h (e, xs(V := vo)) (e', xs') ==> τred0r extTA P h ({V:T=vo; e}, xs) ({V:T=xs' V; e'}, xs'(V := xs V))"
proof(induct rule: rtranclp_induct2)
  case refl thus ?case by(simp del: fun_upd_apply)(auto simp add: fun_upd_apply)
next
  case (step e' xs' e'' xs'')
  from `τred0 extTA P h (e', xs') (e'', xs'')` 
  have "extTA,P \<turnstile> ⟨e',(h, xs')⟩ -ε-> ⟨e'',(h, xs'')⟩" "τmove0 P h e'" "no_call P h e'" by auto
  hence "extTA,P \<turnstile> ⟨e',(h, xs'(V := xs V, V := xs' V))⟩ -ε-> ⟨e'',(h, xs'')⟩" by simp
  from BlockRed[OF this, of T] `τmove0 P h e'` `no_call P h e'`
  have "τred0 extTA P h ({V:T=xs' V; e'}, xs'(V := xs V)) ({V:T=xs'' V; e''}, xs''(V := xs V))" by auto
  with `τred0r extTA P h ({V:T=vo; e}, xs) ({V:T=xs' V; e'}, xs'(V := xs V))` show ?case ..
qed

lemma Sync_τred0r_xt:
  "τred0r extTA P h (e, xs) (e', xs') ==> τred0r extTA P h (syncV (e) e2, xs) (syncV (e') e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl SynchronizedRed1)

lemma InSync_τred0r_xt:
  "τred0r extTA P h (e, xs) (e', xs') ==> τred0r extTA P h (insyncV (a) e, xs) (insyncV (a) e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl SynchronizedRed2)

lemma Seq_τred0r_xt:
  "τred0r extTA P h (e, xs) (e', xs') ==> τred0r extTA P h (e;;e2, xs) (e';;e2, xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl SeqRed)

lemma Cond_τred0r_xt:
  "τred0r extTA P h (e, xs) (e', xs') ==> τred0r extTA 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 CondRed)

lemma Throw_τred0r_xt:
  "τred0r extTA P h (e, xs) (e', xs') ==> τred0r extTA P h (throw e, xs) (throw e', xs')"
by(induct rule: rtranclp_induct2)(auto intro: rtranclp.rtrancl_into_rtrancl ThrowRed)

lemma Try_τred0r_xt:
  "τred0r extTA P h (e, xs) (e', xs') ==> τred0r extTA 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 TryRed)

definition τRed0 :: "J_prog => heap => (expr × expr list) => (expr × expr list) => bool"
where "τRed0 P h ees e'es' = (P \<turnstile>0 ⟨fst ees/snd ees, h⟩ -ε-> ⟨fst e'es'/snd e'es', h⟩ ∧ τMove0 P h ees)"

lemma τRed0_conv [iff]:
  "τRed0 P h (e, es) (e', es') = (P \<turnstile>0 ⟨e/es, h⟩ -ε-> ⟨e'/es', h⟩ ∧ τMove0 P h (e, es))"
by(simp add: τRed0_def)

lemma τred0r_lcl_incr:
  "τred0r extTA P h (e, xs) (e', xs') ==> dom xs ⊆ dom xs'"
by(induct rule: rtranclp_induct2)(auto dest: red_lcl_incr del: subsetI)

lemma τred0t_lcl_incr:
  "τred0t extTA P h (e, xs) (e', xs') ==> dom xs ⊆ dom xs'"
by(rule τred0r_lcl_incr)(rule tranclp_into_rtranclp)

lemma τred0r_dom_lcl:
  assumes wwf: "wwf_J_prog P"
  shows "τred0r extTA P h (e, xs) (e', xs') ==> dom xs' ⊆ dom xs ∪ fv e"
apply(induct rule: converse_rtranclp_induct2)
 apply blast
apply(clarsimp del: subsetI)
apply(frule red_dom_lcl)
 apply(drule red_fv_subset[OF wwf])
apply auto
done

lemma τred0t_dom_lcl:
  assumes wwf: "wwf_J_prog P"
  shows "τred0t extTA P h (e, xs) (e', xs') ==> dom xs' ⊆ dom xs ∪ fv e"
by(rule τred0r_dom_lcl[OF wwf])(rule tranclp_into_rtranclp)

lemma τred0r_fv_subset:
  assumes wwf: "wwf_J_prog P"
  shows "τred0r extTA P h (e, xs) (e', xs') ==> fv e' ⊆ fv e"
by(induct rule: converse_rtranclp_induct2)(auto dest: red_fv_subset[OF wwf])

lemma τred0t_fv_subset:
  assumes wwf: "wwf_J_prog P"
  shows "τred0t extTA P h (e, xs) (e', xs') ==> fv e' ⊆ fv e"
by(rule τred0r_fv_subset[OF wwf])(rule tranclp_into_rtranclp)

abbreviation τRed0r :: "J_prog => heap => (expr × expr list) => (expr × expr list) => bool"
where "τRed0r P h ≡ (τRed0 P h)^**"

abbreviation τRed0t :: "J_prog => heap => (expr × expr list) => (expr × expr list) => bool"
where "τRed0t P h ≡ (τRed0 P h)^++"

lemma fixes e :: "('a, 'b) exp" and es :: "('a, 'b) exp list"
  shows τmove0_not_call: "[| τmove0 P h e; call e = ⌊aMvs⌋ |] ==> ¬ synthesized_call P h aMvs"
  and τmoves0_not_calls: "[| τmoves0 P h es; calls es = ⌊aMvs⌋ |] ==> ¬ synthesized_call P h aMvs"
apply(induct e and es)
apply(auto simp add: is_vals_conv append_eq_map_conv map_eq_append_conv split: split_if_asm)
apply(auto simp add: synthesized_call_def)
done

lemma fixes e :: "('a, 'b) exp" and es :: "('a, 'b) exp list"
  shows τmove0_callD: "call e = ⌊aMvs⌋ ==> τmove0 P h e <-> ¬ synthesized_call P h aMvs"
  and τmoves0_callsD: "calls es = ⌊aMvs⌋ ==> τmoves0 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 τred0_into_τRed0:
  assumes red: "τred0 (extTA2J0 P) P h (e, empty) (e', xs')"
  shows "τRed0 P h (e, es) (e', es)"
proof -
  from red have red: "extTA2J0 P,P \<turnstile> ⟨e, (h, empty)⟩ -ε-> ⟨e', (h, xs')⟩" and "τmove0 P h e" and "no_call P h e" by auto
  hence "P \<turnstile>0 ⟨e/es,h⟩ -ε-> ⟨e'/es,h⟩"
    by-(erule red0Red,auto simp add: no_call_def)
  thus ?thesis using `τmove0 P h e` by(auto)
qed

lemma τred0r_into_τRed0r:
  assumes wwf: "wwf_J_prog P"
  shows
  "[| τred0r (extTA2J0 P) P h (e, empty) (e'', empty); fv e = {} |]
  ==> τRed0r P h (e, es) (e'', es)"
proof(induct e xs"empty :: locals" rule: converse_rtranclp_induct2)
  case refl show ?case by blast
next
  case (step e xs e' xs')
  from `τred0 (extTA2J0 P) P h (e, xs) (e', xs')`
  have red: "extTA2J0 P,P \<turnstile> ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩" and "τmove0 P h e"  and "no_call P h e" by auto
  from wwf red have "fv e' ⊆ fv e" by(rule red_fv_subset)
  with `fv e = {}` have "fv e' = {}" by blast
  moreover from red_dom_lcl[OF red] `fv e = {}` `xs = empty`
  have "dom xs' = {}" by(auto split:split_if_asm)
  hence "xs' = empty" by(auto)
  ultimately have "τRed0r P h (e', es) (e'', es)" by(rule step)
  moreover from red `τmove0 P h e` `xs' = empty` `xs = empty` `no_call P h e`
  have "τRed0 P h (e, es) (e', es)" by(auto simp add: no_call_def intro!: red0Red)
  ultimately show ?case by(blast intro: converse_rtranclp_into_rtranclp)
qed


lemma τred0t_into_τRed0t:
  assumes wwf: "wwf_J_prog P"
  shows
  "[| τred0t (extTA2J0 P) P h (e, empty) (e'', empty); fv e = {} |]
  ==> τRed0t P h (e, es) (e'', es)"
proof(induct e xs"empty :: locals" rule: converse_tranclp_induct2)
  case (base e xs)
  thus ?case by(blast intro!: tranclp.r_into_trancl τred0_into_τRed0)
next
  case (step e xs e' xs')
  from `τred0 (extTA2J0 P) P h (e, xs) (e', xs')` 
  have red: "extTA2J0 P,P \<turnstile> ⟨e, (h, xs)⟩ -ε-> ⟨e', (h, xs')⟩" and "τmove0 P h e" and "no_call P h e" by auto
  from wwf red have "fv e' ⊆ fv e" by(rule red_fv_subset)
  with `fv e = {}` have "fv e' = {}" by blast
  moreover from red_dom_lcl[OF red] `fv e = {}` `xs = empty`
  have "dom xs' = {}" by(auto split:split_if_asm)
  hence "xs' = empty" by auto
  ultimately have "τRed0t P h (e', es) (e'', es)" by(rule step)
  moreover from red `τmove0 P h e` `xs' = empty` `xs = empty` `no_call P h e`
  have "τRed0 P h (e, es) (e', es)" by(auto simp add: no_call_def intro!: red0Red)
  ultimately show ?case by(blast intro: tranclp_into_tranclp2)
qed


abbreviation τMOVE :: "'m prog => ((expr × locals) × heap, J_thread_action) trsys"
where "τMOVE ≡ λP ((e, x), h) ta s'. τmove0 P h e ∧ ta = ε"
  
abbreviation τMOVE0 :: "'m prog => ((expr × expr list) × heap, J0_thread_action) trsys"
where "τMOVE0 ≡ λP (es, h) ta s. τMove0 P h es ∧ ta = ε"

abbreviation final_expr0 :: "expr × expr list => bool" where
  "final_expr0 ≡ λ(e, es). final e ∧ es = []"

lemma red0_mthr: "multithreaded (mred0 P)"
apply(unfold_locales)
apply(auto elim!: red0.cases)
by(auto dest: red_new_thread_heap)

interpretation red0_mthr: multithreaded final_expr0 "mred0 P" for P
by(rule red0_mthr)

interpretation red_τmthr: τmultithreaded final_expr "mred P" "τMOVE P" for P
by(unfold_locales)

interpretation red0_τmthr: τmultithreaded final_expr0 "mred0 P" "τMOVE0 P" for P
.

lemma red0_final_thread_wf: "final_thread_wf final_expr0 (mred0 P)"
by(unfold_locales)(auto elim!: red0.cases)

interpretation red0_mthr: final_thread_wf final_expr0 "mred0 P" for P
by(rule red0_final_thread_wf)

lemma red_τmthr_wf: "τmultithreaded_wf final_expr (mred P) (τMOVE P) wfs"
proof
  fix x1 m1 ta1 x1' m1'
  assume "mred P (x1, m1) ta1 (x1', m1')" "τMOVE P (x1, m1) ta1 (x1', m1')"
  thus "m1 = m1'" by(auto dest: τmove0_heap_unchanged simp add: split_def)
qed(simp add: split_beta)

interpretation red_τmthr_wf: τmultithreaded_wf final_expr "mred P" "τMOVE P" wfs for P wfs
by(rule red_τmthr_wf)

lemma red0_τmthr_wf: "τmultithreaded_wf final_expr0 (mred0 P) (τMOVE0 P) wfs"
proof
  fix x1 m1 ta1 x1' m1'
  assume "mred0 P (x1, m1) ta1 (x1', m1')" "τMOVE0 P (x1, m1) ta1 (x1', m1')"
  thus "m1 = m1'" by(cases x1)(fastsimp elim!: red0.cases dest: τmove0_heap_unchanged)
qed(simp add: split_beta)

interpretation red0_τmthr_wf: τmultithreaded_wf final_expr0 "mred0 P" "τMOVE0 P" wfs for P wfs
by(rule red0_τmthr_wf)

end