Theory Compose

(*
    Author:      Norbert Schirmer
    Maintainer:  Norbert Schirmer, norbert.schirmer at web de

Copyright (C) 2006-2008 Norbert Schirmer
Copyright (c) 2022 Apple Inc. All rights reserved.

*)

section "Experiments on State Composition"


theory Compose imports "../HoareTotalProps" begin

text ‹
We develop some theory to support state-space modular development of programs.
These experiments aim at the representation of state-spaces with records.
If we use statespaces› instead we get this kind of compositionality for free.
›


subsection ‹Changing the State-Space›

(* Lift a command on statespace 'b to work on statespace 'a *)

definition liftf:: "('S  's)  ('S  's  'S)  ('s  's)  ('S  'S)"
  where "liftf prj inject f = (λS. inject S (f (prj S)))"

definition lifts:: "('S  's)  's set  'S set"
  where "lifts prj A = {S. prj S  A}"

definition liftr:: "('S  's)  ('S  's  'S)  ('s × 's) set
                        ('S × 'S) set"
where
"liftr prj inject R = {(S,T). (prj S,prj T)  R  T=inject S (prj T)}"


primrec liftc:: "('S  's)  ('S  's  'S)  ('s,'p,'f) com  ('S,'p,'f) com"
where
"liftc prj inject Skip = Skip" |
"liftc prj inject (Basic f) = Basic (liftf prj inject f)" |
"liftc prj inject (Spec r) = Spec (liftr prj inject r)" |
"liftc prj inject (Seq c1 c2)  =
  (Seq (liftc prj inject c1) (liftc prj inject c2))" |
"liftc prj inject (Cond b c1 c2) =
  Cond (lifts prj b) (liftc prj inject c1) (liftc prj inject c2)" |
"liftc prj inject (While b c) =
  While (lifts prj b) (liftc prj inject c)" |
"liftc prj inject (Call p) = Call p" |
"liftc prj inject (DynCom c) = DynCom (λs. liftc prj inject (c (prj s)))" |
"liftc prj inject (Guard f g c) = Guard f (lifts prj g) (liftc prj inject c)" |
"liftc prj inject Throw = Throw" |
"liftc prj inject (Catch c1 c2) =
  Catch (liftc prj inject c1) (liftc prj inject c2)"



lemma liftc_Skip: "(liftc prj inject c = Skip) = (c = Skip)"
  by (cases c) auto

lemma liftc_Basic:
  "(liftc prj inject c = Basic lf) = (f. c = Basic f  lf = liftf prj inject f)"
  by (cases c) auto

lemma liftc_Spec:
  "(liftc prj inject c = Spec lr) = (r. c = Spec r  lr = liftr prj inject r)"
  by (cases c) auto

lemma liftc_Seq:
  "(liftc prj inject c = Seq lc1 lc2) =
     ( c1 c2. c = Seq c1 c2 
               lc1 = liftc prj inject c1  lc2 = liftc prj inject c2 )"
    by (cases c) auto

lemma liftc_Cond:
  "(liftc prj inject c = Cond lb lc1 lc2) =
     (b c1 c2. c = Cond b c1 c2  lb = lifts prj b 
                lc1 = liftc prj inject c1  lc2 = liftc prj inject c2 )"
  by (cases c) auto

lemma liftc_While:
  "(liftc prj inject c = While lb lc') =
     (b c'. c = While b c'  lb = lifts prj b 
               lc' = liftc prj inject c')"
  by (cases c) auto

lemma liftc_Call:
  "(liftc prj inject c = Call p) = (c = Call p)"
  by (cases c) auto

lemma liftc_DynCom:
  "(liftc prj inject c = DynCom lc) =
     (C. c=DynCom C  lc = (λs. liftc prj inject (C (prj s))))"
  by (cases c) auto

lemma liftc_Guard:
  "(liftc prj inject c = Guard f lg lc') =
     (g c'. c = Guard f g c'  lg = lifts prj g 
             lc' = liftc prj inject c')"
   by (cases c) auto

lemma liftc_Throw:
  "(liftc prj inject c = Throw) = (c = Throw)"
  by (cases c) auto

lemma liftc_Catch:
  "(liftc prj inject c = Catch lc1 lc2) =
     ( c1 c2. c = Catch c1 c2 
               lc1 = liftc prj inject c1  lc2 = liftc prj inject c2 )"
    by (cases c) auto



definition xstate_map:: "('S  's)  ('S,'f) xstate  ('s,'f) xstate"
where
"xstate_map g x = (case x of
                      Normal s  Normal (g s)
                    | Abrupt s  Abrupt (g s)
                    | Fault f  Fault f
                    | Stuck  Stuck)"

lemma xstate_map_simps [simp]:
"xstate_map g (Normal s) = Normal (g s)"
"xstate_map g (Abrupt s) = Abrupt (g s)"
"xstate_map g (Fault f) = (Fault f)"
"xstate_map g Stuck = Stuck"
  by (auto simp add: xstate_map_def)

lemma xstate_map_Normal_conv:
  "xstate_map g S = Normal s = (s'. S=Normal s'  s = g s')"
  by (cases S) auto

lemma xstate_map_Abrupt_conv:
  "xstate_map g S = Abrupt s = (s'. S=Abrupt s'  s = g s')"
  by (cases S) auto

lemma xstate_map_Fault_conv:
  "xstate_map g S = Fault f = (S=Fault f)"
  by (cases S) auto

lemma xstate_map_Stuck_conv:
  "xstate_map g S = Stuck = (S=Stuck)"
  by (cases S) auto

lemmas xstate_map_convs = xstate_map_Normal_conv xstate_map_Abrupt_conv
 xstate_map_Fault_conv xstate_map_Stuck_conv

definition state:: "('s,'f) xstate  's"
where
"state x = (case x of
               Normal s  s
             | Abrupt s  s
             | Fault g  undefined
             | Stuck  undefined)"

lemma state_simps [simp]:
"state (Normal s) = s"
"state (Abrupt s) = s"
  by (auto simp add: state_def )


locale lift_state_space =
  fixes project::"'S  's"
  fixes "inject"::"'S  's  'S"
  fixes "projectx"::"('S,'f) xstate  ('s,'f) xstate"
  fixes "lifte"::"('s,'p,'f) body  ('S,'p,'f) body"
  fixes liftc:: "('s,'p,'f) com  ('S,'p,'f) com"
  fixes liftf:: "('s  's)  ('S  'S)"
  fixes lifts:: "'s set  'S set"
  fixes liftr:: "('s × 's) set  ('S × 'S) set"
  assumes proj_inj_commute: "S s.  project (inject S s) = s"
  defines "liftc  Compose.liftc project inject"
  defines "projectx  xstate_map project"
  defines "lifte  (λΓ p. map_option liftc (Γ p))"
  defines "liftf  Compose.liftf project inject"
  defines "lifts  Compose.lifts project"
  defines "liftr  Compose.liftr project inject"


lemma (in lift_state_space) liftf_simp:
 "liftf f  λS. inject S (f (project S))"
  by (simp add: liftf_def Compose.liftf_def)

lemma (in lift_state_space) lifts_simp:
  "lifts A  {S. project S  A}"
  by  (simp add: lifts_def Compose.lifts_def)

lemma (in lift_state_space) liftr_simp:
"liftr R  {(S,T). (project S,project T)  R  T=inject S (project T)}"
  by  (simp add: liftr_def Compose.liftr_def)

(* Causes loop when instantiating locale
lemmas (in lift_state_space) liftf_simp  = Compose.liftf_def
 [of project "inject", folded liftf_def]
lemmas (in lift_state_space) lifts_simp  = Compose.lifts_def
 [of project, folded lifts_def]
lemmas (in lift_state_space) liftr_simp  = Compose.liftr_def
 [of project "inject", folded liftr_def]
*)
lemma (in lift_state_space) liftc_Skip_simp [simp]:
 "liftc Skip = Skip"
  by (simp add: liftc_def)
lemma (in lift_state_space) liftc_Basic_simp [simp]:
"liftc (Basic f) = Basic (liftf f)"
  by (simp add: liftc_def liftf_def)
lemma (in lift_state_space) liftc_Spec_simp [simp]:
"liftc (Spec r) = Spec (liftr r)"
  by (simp add: liftc_def liftr_def)
lemma (in lift_state_space) liftc_Seq_simp [simp]:
"liftc (Seq c1 c2)  =
  (Seq (liftc c1) (liftc c2))"
  by (simp add: liftc_def)
lemma (in lift_state_space) liftc_Cond_simp [simp]:
"liftc (Cond b c1 c2) =
  Cond (lifts b) (liftc c1) (liftc c2)"
  by (simp add: liftc_def lifts_def)
lemma (in lift_state_space) liftc_While_simp [simp]:
"liftc (While b c) =
  While (lifts b) (liftc c)"
  by (simp add: liftc_def lifts_def)
lemma (in lift_state_space) liftc_Call_simp [simp]:
"liftc (Call p) = Call p"
  by (simp add: liftc_def)
lemma (in lift_state_space) liftc_DynCom_simp [simp]:
"liftc (DynCom c) = DynCom (λs. liftc (c (project s)))"
  by (simp add: liftc_def)
lemma (in lift_state_space) liftc_Guard_simp [simp]:
"liftc (Guard f g c) = Guard f (lifts g) (liftc c)"
  by (simp add: liftc_def lifts_def)
lemma (in lift_state_space) liftc_Throw_simp [simp]:
"liftc Throw = Throw"
  by (simp add: liftc_def)
lemma (in lift_state_space) liftc_Catch_simp [simp]:
"liftc (Catch c1 c2) =
  Catch (liftc c1) (liftc c2)"
  by (simp add: liftc_def)

lemma (in lift_state_space) projectx_def':
"projectx s  (case s of
                 Normal s  Normal (project s)
                | Abrupt s  Abrupt (project s)
                | Fault f  Fault f
                | Stuck  Stuck)"
  by (simp add: xstate_map_def projectx_def)

lemma (in lift_state_space) lifte_def':
  "lifte Γ p  (case Γ p of Some bdy  Some (liftc bdy) | None  None)"
  by (simp add: lifte_def map_option_case)




text ‹
The problem is that @{term "(liftc project inject  Γ)"} is quite
a strong premise. The problem is that @{term "Γ"} is a function here.
A map would be better. We only have to lift those procedures in the domain
of @{term "Γ"}:
Γ p = Some bdy ⟶ Γ' p = Some liftc project inject bdy›.
We then can com up with theorems that allow us to extend the domains
of @{term Γ} and preserve validity.
›


lemma (in lift_state_space)
"{(S,T). t. (project S,t)  r  T=inject S t}
  {(S,T). (project S,project T)  r  T=inject S (project T)}"
  apply clarsimp
  apply (rename_tac S t)
  apply (simp add: proj_inj_commute)
  done

lemma (in lift_state_space)
"{(S,T). (project S,project T)  r  T=inject S (project T)}
  {(S,T). t. (project S,t)  r  T=inject S t}"
  apply clarsimp
  apply (rename_tac S T)
  apply (rule_tac x="project T" in exI)
  apply simp
  done


lemma (in lift_state_space) lift_exec:
assumes exec_lc: "(lifte Γ)lc,s  t"
shows "c.  liftc c = lc 
              Γc,projectx s   projectx t"
using exec_lc
proof (induct)
  case Skip thus ?case
    by (auto simp add: projectx_def liftc_Skip liftc_def intro: exec.Skip)
next
  case Guard thus ?case
    by (auto simp add: projectx_def lifts_def Compose.lifts_def liftc_Guard liftc_def
      intro: exec.Guard)
next
  case GuardFault thus ?case
    by (auto simp add: projectx_def lifts_def Compose.lifts_def liftc_Guard liftc_def
      intro: exec.GuardFault)
next
  case FaultProp thus ?case
    by (fastforce simp add: projectx_def)
next
  case Basic
  thus ?case
    by (fastforce simp add: projectx_def liftc_Basic liftf_def Compose.liftf_def
      liftc_def
        proj_inj_commute
        intro: exec.Basic)
next
  case Spec
  thus ?case
    by (fastforce simp add: projectx_def liftc_Spec liftf_def Compose.liftf_def
        liftr_def Compose.liftr_def liftc_def
        proj_inj_commute
        intro: exec.Spec)
next
  case (SpecStuck s r)
  thus ?case
    apply (simp add: projectx_def)
    apply (clarsimp simp add: liftc_Spec liftc_def)
    apply (unfold liftr_def Compose.liftr_def)
    apply (rule exec.SpecStuck)
    apply (rule allI)
    apply (erule_tac x="inject s t" in allE)
    apply clarsimp
    apply (simp add: proj_inj_commute)
    done
next
  case Seq
  thus ?case
    by (fastforce simp add: projectx_def liftc_Seq liftc_def intro: exec.intros)
next
  case CondTrue
  thus ?case
     by (auto simp add: projectx_def lifts_def Compose.lifts_def liftc_Cond liftc_def
         intro: exec.CondTrue)
next
  case CondFalse
  thus ?case
     by (auto simp add: projectx_def lifts_def Compose.lifts_def liftc_Cond liftc_def
         intro: exec.CondFalse)
next
  case WhileTrue
  thus ?case
     by (fastforce simp add: projectx_def lifts_def Compose.lifts_def
         liftc_While liftc_def
         intro: exec.WhileTrue)
next
  case WhileFalse
  thus ?case
     by (fastforce simp add: projectx_def lifts_def Compose.lifts_def
         liftc_While liftc_def
         intro: exec.WhileFalse)
next
  case Call
  thus ?case
    by (fastforce simp add:
               projectx_def liftc_Call liftf_def Compose.liftf_def liftc_def
               lifte_def
          intro: exec.Call)
next
  case CallUndefined
  thus ?case
    by (fastforce simp add:
               projectx_def liftc_Call liftf_def Compose.liftf_def liftc_def
               lifte_def
          intro: exec.CallUndefined)
next
  case StuckProp thus ?case
    by (fastforce simp add: projectx_def)
next
  case DynCom
  thus ?case
    by (fastforce simp add:
               projectx_def liftc_DynCom liftf_def Compose.liftf_def liftc_def
          intro: exec.DynCom)
next
  case Throw thus ?case
    by (fastforce simp add: projectx_def liftc_Throw liftc_def intro: exec.Throw)
next
  case AbruptProp thus ?case
    by (fastforce simp add: projectx_def)
next
  case CatchMatch
  thus ?case
    by (fastforce simp add: projectx_def liftc_Catch liftc_def intro: exec.CatchMatch)
next
  case (CatchMiss c1 s t c2 c)
  thus ?case
    by (cases t)
       (fastforce simp add: projectx_def liftc_Catch liftc_def intro: exec.CatchMiss)+
qed

lemma (in lift_state_space) lift_exec':
assumes exec_lc: "(lifte Γ)liftc c,s  t"
shows "Γc,projectx s  projectx t"
  using lift_exec [OF exec_lc]
  by simp



lemma (in lift_state_space) lift_valid:
  assumes valid: "Γ⊨⇘/FP c Q,A"
  shows
   "(lifte Γ)⊨⇘/F(lifts P) (liftc c) (lifts Q),(lifts A)"
proof (rule validI)
  fix s t
  assume lexec:
    "(lifte Γ)liftc c,Normal s  t"
  assume lP: "s  lifts P"
  assume noFault: "t  Fault ` F"
  show "t  Normal ` lifts Q  Abrupt ` lifts A"
  proof -
    from lexec
    have "Γ c,projectx (Normal s)  (projectx t)"
      by (rule lift_exec) (simp_all)
    moreover
    from lP have "project s  P"
      by (simp add: lifts_def Compose.lifts_def projectx_def)
    ultimately
    have "projectx t  Normal ` Q  Abrupt ` A"
      using valid noFault
      apply (clarsimp simp add: valid_def projectx_def)
      apply (cases t)
      apply auto
      done
    thus ?thesis
      apply (simp add: lifts_def Compose.lifts_def)
      apply (cases t)
      apply (auto simp add: projectx_def)
      done
  qed
qed

lemma (in lift_state_space) lift_hoarep:
  assumes deriv: "Γ,{}⊢⇘/FP c Q,A"
  shows
   "(lifte Γ),{}⊢⇘/F(lifts P) (liftc c) (lifts Q),(lifts A)"
apply (rule hoare_complete)
apply (insert hoare_sound [OF deriv])
apply (rule lift_valid)
apply (simp add: cvalid_def)
done

lemma (in lift_state_space) lift_hoarep':
  "Z. Γ,{}⊢⇘/F(P Z) c (Q Z),(A Z) 
    Z. (lifte Γ),{}⊢⇘/F(lifts (P Z)) (liftc c)
                                  (lifts (Q Z)),(lifts (A Z))"
apply (iprover intro: lift_hoarep)
done



lemma (in lift_state_space) lift_termination:
assumes termi: "Γcs"
shows "S. projectx S = s 
  lifte Γ (liftc c)S"
  using termi
proof (induct)
  case Skip thus ?case
    by (clarsimp simp add: terminates.Skip projectx_def xstate_map_convs)
next
  case Basic thus ?case
    by (fastforce simp add: projectx_def xstate_map_convs intro: terminates.intros)
next
  case Spec thus ?case
    by (fastforce simp add: projectx_def xstate_map_convs intro: terminates.intros)
next
  case Guard thus ?case
    by (auto simp add: projectx_def xstate_map_convs intro: terminates.intros)
next
  case GuardFault thus ?case
    by (auto simp add: projectx_def xstate_map_convs lifts_def Compose.lifts_def
           intro: terminates.intros)
next
  case Fault thus ?case by (clarsimp simp add: projectx_def xstate_map_convs)
next
  case (Seq c1 s c2)
  have "projectx S = Normal s" by fact
  then obtain s' where S: "S=Normal s'" and s: "s = project s'"
    by (auto simp add: projectx_def xstate_map_convs)
  from Seq have "lifte Γliftc c1  S"
    by simp
  moreover
  {
    fix w
    assume exec_lc1: "lifte Γliftc c1,Normal s'  w"
    have "lifte Γliftc c2  w"
    proof (cases w)
      case (Normal w')
      with lift_exec [where c=c1, OF exec_lc1] s
      have "Γc1,Normal s  Normal (project w')"
        by (simp add: projectx_def)
      from Seq.hyps (3) [rule_format, OF this] Normal
      show "lifte Γliftc c2  w"
        by (auto simp add: projectx_def xstate_map_convs)
    qed (auto)
  }
  ultimately show ?case
    using S s
    by (auto intro: terminates.intros)
next
  case CondTrue thus ?case
    by (fastforce simp add: projectx_def lifts_def Compose.lifts_def xstate_map_convs
      intro: terminates.intros)
next
  case CondFalse thus ?case
    by (fastforce simp add: projectx_def lifts_def Compose.lifts_def xstate_map_convs
      intro: terminates.intros)
next
  case (WhileTrue s b c)
  have "projectx S = Normal s" by fact
  then obtain s' where S: "S=Normal s'" and s: "s = project s'"
    by (auto simp add: projectx_def xstate_map_convs)
  from WhileTrue have "lifte Γliftc c  S"
    by simp
  moreover
  {
    fix w
    assume exec_lc: "lifte Γliftc c,Normal s'  w"
    have "lifte Γliftc (While b c)  w"
    proof (cases w)
      case (Normal w')
      with lift_exec [where c=c, OF exec_lc] s
      have "Γc,Normal s  Normal (project w')"
        by (simp add: projectx_def)
      from WhileTrue.hyps (4) [rule_format, OF this] Normal
      show "lifte Γliftc (While b c)  w"
        by (auto simp add: projectx_def xstate_map_convs)
    qed (auto)
  }
  ultimately show ?case
    using S s
    by (auto intro: terminates.intros)
next
  case WhileFalse thus ?case
    by (fastforce simp add: projectx_def lifts_def Compose.lifts_def xstate_map_convs
      intro: terminates.intros)
next
  case Call thus ?case
    by (fastforce simp add: projectx_def xstate_map_convs lifte_def
      intro: terminates.intros)
next
  case CallUndefined thus ?case
    by (fastforce simp add: projectx_def xstate_map_convs lifte_def
      intro: terminates.intros)
next
  case Stuck thus ?case
    by (fastforce simp add: projectx_def xstate_map_convs)
next
  case DynCom thus ?case
    by (fastforce simp add: projectx_def xstate_map_convs
      intro: terminates.intros)
next
  case Throw thus ?case
    by (fastforce simp add: projectx_def xstate_map_convs
      intro: terminates.intros)
next
  case Abrupt thus ?case
    by (fastforce simp add: projectx_def xstate_map_convs
      intro: terminates.intros)
next
  case (Catch c1 s c2)
  have "projectx S = Normal s" by fact
  then obtain s' where S: "S=Normal s'" and s: "s = project s'"
    by (auto simp add: projectx_def xstate_map_convs)
  from Catch have "lifte Γliftc c1  S"
    by simp
  moreover
  {
    fix w
    assume exec_lc1: "lifte Γliftc c1,Normal s'  Abrupt w"
    have "lifte Γliftc c2  Normal w"
    proof -
      from lift_exec [where c=c1, OF exec_lc1] s
      have "Γc1,Normal s  Abrupt (project w)"
        by (simp add: projectx_def)
      from Catch.hyps (3) [rule_format, OF this]
      show "lifte Γliftc c2  Normal w"
        by (auto simp add: projectx_def xstate_map_convs)
    qed
  }
  ultimately show ?case
    using S s
    by (auto intro: terminates.intros)
qed

lemma (in lift_state_space) lift_termination':
assumes termi: "Γcprojectx S"
shows "lifte Γ (liftc c)S"
  using lift_termination [OF termi]
  by iprover


lemma (in lift_state_space) lift_validt:
  assumes valid: "Γt⇘/FP c Q,A"
  shows "(lifte Γ)t⇘/F(lifts P) (liftc c) (lifts Q),(lifts A)"
proof -
  from valid
  have "(lifte Γ)⊨⇘/F(lifts P) (liftc c) (lifts Q),(lifts A)"
    by (auto intro: lift_valid simp add: validt_def)
  moreover
  {
    fix S
    assume "S  lifts P"
    hence "project S  P"
      by (simp add: lifts_def Compose.lifts_def)
    with valid have "Γc  projectx (Normal S)"
      by (simp add: validt_def projectx_def)
    hence "lifte Γliftc c  Normal S"
      by (rule lift_termination')
  }
  ultimately show ?thesis
    by (simp add: validt_def)
qed

lemma (in lift_state_space) lift_hoaret:
  assumes deriv: "Γ,{}t⇘/FP c Q,A"
  shows
   "(lifte Γ),{}t⇘/F(lifts P) (liftc c) (lifts Q),(lifts A)"
apply (rule hoaret_complete)
apply (insert hoaret_sound [OF deriv])
apply (rule lift_validt)
apply (simp add: cvalidt_def)
done


locale lift_state_space_ext = lift_state_space +
  assumes inj_proj_commute: "S. inject S (project S) = S"
  assumes inject_last: "S s t. inject (inject S s) t = inject S t"


(* ∃x. state t = inject (state s) x *)
lemma (in lift_state_space_ext) lift_exec_inject_same:
assumes exec_lc: "(lifte Γ)lc,s  t"
shows "c. liftc c = lc; t  (Fault ` UNIV)  {Stuck} 
              state t = inject (state s) (project (state t))"
using exec_lc
proof (induct)
  case Skip thus ?case
    by (clarsimp simp add: inj_proj_commute)
next
  case Guard thus ?case
    by (clarsimp simp add: liftc_Guard liftc_def)
next
  case GuardFault thus ?case
    by simp
next
  case FaultProp thus ?case by simp
next
  case Basic thus ?case
    by (clarsimp simp add: liftf_def Compose.liftf_def
        proj_inj_commute liftc_Basic liftc_def)
next
  case (Spec r) thus ?case
    by (clarsimp simp add: Compose.liftr_def liftc_Spec liftc_def)
next
  case SpecStuck
  thus ?case by simp
next
  case (Seq lc1 s s' lc2 t c)
  have t: "t  Fault ` UNIV  {Stuck}" by fact
  have "liftc c = Seq lc1 lc2" by fact
  then obtain c1 c2 where
    c: "c = Seq c1 c2" and
    lc1: "lc1 = liftc c1" and
    lc2: "lc2 = liftc c2"
    by (auto simp add: liftc_Seq liftc_def)
  show ?case
  proof (cases s')
    case (Normal s'')
    from Seq.hyps (2) [OF lc1 [symmetric]] this
    have "s'' = inject s (project s'')"
      by auto
    moreover from Seq.hyps (4) [OF lc2 [symmetric]] Normal t
    have "state t = inject s'' (project (state t))"
      by auto
    ultimately have "state t = inject (inject s (project s'')) (project (state t))"
      by simp
    then show ?thesis
      by (simp add: inject_last)
  next
    case (Abrupt s'')
    from Seq.hyps (2) [OF lc1 [symmetric]] this
    have "s'' = inject s (project s'')"
      by auto
    moreover from Seq.hyps (4) [OF lc2 [symmetric]] Abrupt t
    have "state t = inject s'' (project (state t))"
      by auto
    ultimately have "state t = inject (inject s (project s'')) (project (state t))"
      by simp
    then show ?thesis
      by (simp add: inject_last)
  next
    case (Fault f)
    with Seq
    have "t = Fault f"
      by (auto dest: Fault_end)
    with t have False by simp
    thus ?thesis ..
  next
    case Stuck
    with Seq
    have "t = Stuck"
      by (auto dest: Stuck_end)
    with t have False by simp
    thus ?thesis ..
  qed
next
  case CondTrue thus ?case
    by (clarsimp simp add: liftc_Cond liftc_def)
next
  case CondFalse thus ?case
    by (clarsimp simp add: liftc_Cond liftc_def)
next
  case (WhileTrue s lb lc' s' t c)
  have t: "t  Fault ` UNIV  {Stuck}" by fact
  have lw: "liftc c = While lb lc'" by fact
  then obtain b c' where
    c: "c = While b c'" and
    lb: "lb = lifts b" and
    lc: "lc' = liftc c'"
    by (auto simp add: liftc_While lifts_def liftc_def)
  show ?case
  proof (cases s')
    case (Normal s'')
    from WhileTrue.hyps (3) [OF lc [symmetric]] this
    have "s'' = inject s (project s'')"
      by auto
    moreover from WhileTrue.hyps (5) [OF lw] Normal t
    have "state t = inject s'' (project (state t))"
      by auto
    ultimately have "state t = inject (inject s (project s'')) (project (state t))"
      by simp
    then show ?thesis
      by (simp add: inject_last)
  next
    case (Abrupt s'')
    from WhileTrue.hyps (3) [OF lc [symmetric]] this
    have "s'' = inject s (project s'')"
      by auto
    moreover from WhileTrue.hyps (5) [OF lw] Abrupt t
    have "state t = inject s'' (project (state t))"
      by auto
    ultimately have "state t = inject (inject s (project s'')) (project (state t))"
      by simp
    then show ?thesis
      by (simp add: inject_last)
  next
    case (Fault f)
    with WhileTrue
    have "t = Fault f"
      by (auto dest: Fault_end)
    with t have False by simp
    thus ?thesis ..
  next
    case Stuck
    with WhileTrue
    have "t = Stuck"
      by (auto dest: Stuck_end)
    with t have False by simp
    thus ?thesis ..
  qed
next
  case WhileFalse thus ?case
    by (clarsimp simp add: liftc_While inj_proj_commute)
next
  case Call thus ?case
    by (clarsimp simp add: inject_last liftc_Call lifte_def liftc_def)
next
  case CallUndefined thus ?case by simp
next
  case StuckProp thus ?case by simp
next
  case DynCom
  thus ?case
    by (clarsimp simp add: liftc_DynCom liftc_def)
next
  case Throw thus ?case
    by (simp add: inj_proj_commute)
next
  case AbruptProp thus ?case by (simp add: inj_proj_commute)
next
  case (CatchMatch lc1 s s' lc2 t c)
  have t: "t  Fault ` UNIV  {Stuck}" by fact
  have "liftc c = Catch lc1 lc2" by fact
  then obtain c1 c2 where
    c: "c = Catch c1 c2" and
    lc1: "lc1 = liftc c1" and
    lc2: "lc2 = liftc c2"
    by (auto simp add: liftc_Catch liftc_def)
  from CatchMatch.hyps (2) [OF lc1 [symmetric]] this
  have "s' = inject s (project s')"
    by auto
  moreover
  from CatchMatch.hyps (4) [OF lc2 [symmetric]] t
  have "state t = inject s' (project (state t))"
    by auto
  ultimately have "state t = inject (inject s (project s')) (project (state t))"
    by simp
  then show ?case
    by (simp add: inject_last)
next
  case CatchMiss
  thus ?case
    by (clarsimp simp add: liftc_Catch liftc_def)
qed

lemma (in lift_state_space_ext) valid_inject_project:
 assumes noFaultStuck:
  "Γc,Normal (project σ) ⇒∉(Fault ` UNIV  {Stuck})"
 shows "lifte Γ⊨⇘/F{σ} liftc c
                {t. t=inject σ (project t)}, {t. t=inject σ (project t)}"
proof (rule validI)
  fix s t
  assume exec: "lifte Γliftc c,Normal s  t"
  assume P: "s  {σ}"
  assume noFault: "t  Fault ` F"
  show "t  Normal ` {t. t = inject σ (project t)} 
        Abrupt ` {t. t = inject σ (project t)}"
  proof -
    from lift_exec [OF exec]
    have "Γc,projectx (Normal s)  projectx t"
      by simp
    with noFaultStuck P have t: "t  Fault ` UNIV  {Stuck}"
      by (auto simp add: final_notin_def projectx_def)
    from lift_exec_inject_same [OF exec refl this] P
    have "state t = inject σ (project (state t))"
      by simp
    with t show ?thesis
      by (cases t) auto
  qed
qed

lemma (in lift_state_space_ext) lift_exec_inject_same':
assumes exec_lc: "(lifte Γ)liftc c,S  T"
shows "c. T  (Fault ` UNIV)  {Stuck} 
              state T = inject (state S) (project (state T))"
  using lift_exec_inject_same [OF exec_lc]
  by simp

lemma (in lift_state_space_ext) valid_lift_modifies:
  assumes valid: "s. Γ⊨⇘/F{s} c (Modif s),(ModifAbr s)"
  shows "(lifte Γ)⊨⇘/F{S} (liftc c)
           {T. T  lifts (Modif (project S))  T=inject S (project T)},
           {T. T  lifts (ModifAbr (project S))  T=inject S (project T)}"
proof (rule validI)
  fix s t
  assume exec: "lifte Γliftc c,Normal s  t"
  assume P: "s  {S}"
  assume noFault: "t  Fault ` F"
  show "t  Normal `
                 {t  lifts (Modif (project S)).
                  t = inject S (project t)} 
                 Abrupt `
                 {t  lifts (ModifAbr (project S)).
                  t = inject S (project t)}"
  proof -
    from lift_exec [OF exec]
    have "Γ c,projectx (Normal s)  projectx t"
      by auto
    moreover
    from noFault have "projectx t  Fault ` F"
      by (cases "t") (auto simp add: projectx_def)
    ultimately
    have "projectx t 
            Normal ` (Modif (project s))  Abrupt ` (ModifAbr (project s))"
      using valid [rule_format, of "(project s)"]
      by (auto simp add: valid_def projectx_def)
    hence t: "t  Normal ` lifts (Modif (project s)) 
               Abrupt ` lifts (ModifAbr (project s))"
      by (cases t) (auto simp add: projectx_def lifts_def Compose.lifts_def)
    then have "t  Fault ` UNIV  {Stuck}"
      by (cases t) auto
    from lift_exec_inject_same [OF exec _ this]
    have "state t = inject (state (Normal s)) (project (state t))"
      by simp
    with t show ?thesis
      using P by auto
  qed
qed

lemma (in lift_state_space_ext) hoare_lift_modifies:
  assumes deriv: "σ. Γ,{}⊢⇘/F{σ} c (Modif σ),(ModifAbr σ)"
  shows "σ. (lifte Γ),{}⊢⇘/F{σ} (liftc c)
           {T. T  lifts (Modif (project σ))  T=inject σ (project T)},
           {T. T  lifts (ModifAbr (project σ))  T=inject σ (project T)}"
apply (rule allI)
apply (rule hoare_complete)
apply (rule valid_lift_modifies)
apply (rule allI)
apply (insert hoare_sound [OF deriv [rule_format]])
apply (simp add: cvalid_def)
done

lemma (in lift_state_space_ext) hoare_lift_modifies':
  assumes deriv: "σ. Γ,{}⊢⇘/F{σ} c (Modif σ),(ModifAbr σ)"
  shows "σ. (lifte Γ),{}⊢⇘/F{σ} (liftc c)
           {T. T  lifts (Modif (project σ)) 
                   (T'. T=inject σ T')},
           {T. T  lifts (ModifAbr (project σ)) 
                   (T'. T=inject σ T')}"
apply (rule allI)
apply (rule HoarePartialDef.conseq [OF hoare_lift_modifies [OF deriv]])
apply blast
done

subsection ‹Renaming Procedures›

primrec rename:: "('p  'q)  ('s,'p,'f) com  ('s,'q,'f) com"
where
"rename N Skip = Skip" |
"rename N (Basic f) = Basic f" |
"rename N (Spec r) = Spec r" |
"rename N (Seq c1 c2)  = (Seq (rename N c1) (rename N c2))" |
"rename N (Cond b c1 c2) = Cond b (rename N c1) (rename N c2)" |
"rename N (While b c) = While b (rename N c)" |
"rename N (Call p) = Call (N p)" |
"rename N (DynCom c) = DynCom (λs. rename N (c s))" |
"rename N (Guard f g c) = Guard f g (rename N c)" |
"rename N Throw = Throw" |
"rename N (Catch c1 c2) = Catch (rename N c1) (rename N c2)"

lemma rename_Skip: "rename h c = Skip = (c=Skip)"
  by (cases c) auto

lemma rename_Basic:
  "(rename h c = Basic f) = (c=Basic f)"
  by (cases c) auto

lemma rename_Spec:
  "(rename h c = Spec r) = (c=Spec r)"
  by (cases c) auto

lemma rename_Seq:
  "(rename h c = Seq rc1 rc2) =
     ( c1 c2. c = Seq c1 c2 
               rc1 = rename h c1  rc2 = rename h c2 )"
    by (cases c) auto

lemma rename_Cond:
  "(rename h c = Cond b rc1 rc2) =
     (c1 c2. c = Cond b c1 c2   rc1 = rename h c1  rc2 = rename h c2 )"
  by (cases c) auto

lemma rename_While:
  "(rename h c = While b rc') = (c'. c = While b c'  rc' = rename h c')"
  by (cases c) auto

lemma rename_Call:
  "(rename h c = Call q) = (p. c = Call p  q=h p)"
  by (cases c) auto

lemma rename_DynCom:
  "(rename h c = DynCom rc) = (C. c=DynCom C  rc = (λs. rename h (C s)))"
  by (cases c) auto

lemma rename_Guard:
  "(rename h c = Guard f g rc') =
     (c'. c = Guard f g c'  rc' = rename h c')"
   by (cases c) auto

lemma rename_Throw:
  "(rename h c = Throw) = (c = Throw)"
  by (cases c) auto

lemma rename_Catch:
  "(rename h c = Catch rc1 rc2) =
     (c1 c2. c = Catch c1 c2  rc1 = rename h c1  rc2 = rename h c2 )"
    by (cases c) auto

lemma exec_rename_to_exec:
  assumes Γ: "p bdy. Γ p = Some bdy  Γ' (h p) = Some (rename h bdy)"
  assumes exec: "Γ'rc,s  t"
  shows "c. rename h c = rc  t'. Γc,s  t'  (t'=Stuck  t'=t)"
using exec
proof (induct)
  case Skip thus ?case by (fastforce intro: exec.intros simp add: rename_Skip)
next
  case Guard thus ?case by (fastforce intro: exec.intros simp add: rename_Guard)
next
  case GuardFault thus ?case by (fastforce intro: exec.intros simp add: rename_Guard)
next
  case FaultProp thus ?case by (fastforce intro: exec.intros)
next
  case Basic thus ?case by (fastforce intro: exec.intros simp add: rename_Basic)
next
  case Spec thus ?case by (fastforce intro: exec.intros simp add: rename_Spec)
next
  case SpecStuck thus ?case by (fastforce intro: exec.intros simp add: rename_Spec)
next
  case Seq thus ?case by (fastforce intro: exec.intros simp add: rename_Seq)
next
  case CondTrue thus ?case by (fastforce intro: exec.intros simp add: rename_Cond)
next
  case CondFalse thus ?case by (fastforce intro: exec.intros simp add: rename_Cond)
next
  case WhileTrue thus ?case by (fastforce intro: exec.intros simp add: rename_While)
next
  case WhileFalse thus ?case by (fastforce intro: exec.intros simp add: rename_While)
next
  case (Call p rbdy s t)
  have rbdy: "Γ' p = Some rbdy" by fact
  have "rename h c = Call p" by fact
  then obtain q where c: "c=Call q" and p: "p=h q"
    by (auto simp add: rename_Call)
  show ?case
  proof (cases "Γ q")
    case None
    with c show ?thesis by (auto intro: exec.CallUndefined)
  next
    case (Some bdy)
    from Γ [rule_format, OF this] p rbdy
    have "rename h bdy = rbdy" by simp
    with Call.hyps c Some
    show ?thesis
      by (fastforce intro: exec.intros)
  qed
next
  case (CallUndefined p s)
  have undef: "Γ' p = None" by fact
  have "rename h c = Call p" by fact
  then obtain q where c: "c=Call q" and p: "p=h q"
    by (auto simp add: rename_Call)
  from undef p Γ have "Γ q = None"
    by (cases "Γ q") auto
  with p c show ?case
    by (auto intro: exec.intros)
next
  case StuckProp thus ?case by (fastforce intro: exec.intros)
next
  case DynCom thus ?case by (fastforce intro: exec.intros simp add: rename_DynCom)
next
  case Throw thus ?case by (fastforce intro: exec.intros simp add: rename_Throw)
next
  case AbruptProp thus ?case by (fastforce intro: exec.intros)
next
  case CatchMatch thus ?case by (fastforce intro: exec.intros simp add: rename_Catch)
next
  case CatchMiss thus ?case by (fastforce intro: exec.intros simp add: rename_Catch)
qed



lemma exec_rename_to_exec':
  assumes Γ: "p bdy. Γ p = Some bdy  Γ' (N p) = Some (rename N bdy)"
  assumes exec: "Γ'rename N c,s  t"
  shows "t'. Γc,s  t'  (t'=Stuck  t'=t)"
  using exec_rename_to_exec [OF Γ exec]
  by  auto



lemma valid_to_valid_rename:
  assumes Γ: "p bdy. Γ p = Some bdy  Γ' (N p) = Some (rename N bdy)"
  assumes valid: "Γ⊨⇘/FP c Q,A"
  shows "Γ'⊨⇘/FP (rename N c) Q,A"
proof (rule validI)
  fix s t
  assume execr: "Γ' rename N c,Normal s  t"
  assume P: "s  P"
  assume noFault: "t  Fault ` F"
  show "t  Normal ` Q  Abrupt ` A"
  proof -
    from exec_rename_to_exec [OF Γ execr]
    obtain t' where
      exec: "Γ c,Normal s  t'"  and t': "(t' = Stuck  t' = t)"
      by auto
    with valid noFault P show ?thesis
      by (auto simp add: valid_def)
  qed
qed

lemma hoare_to_hoare_rename:
  assumes Γ: "p bdy. Γ p = Some bdy  Γ' (N p) = Some (rename N bdy)"
  assumes deriv: "Γ,{}⊢⇘/FP c Q,A"
  shows "Γ',{}⊢⇘/FP (rename N c) Q,A"
apply (rule hoare_complete)
apply (insert hoare_sound [OF deriv])
apply (rule valid_to_valid_rename)
apply  (rule Γ)
apply (simp add: cvalid_def)
done

lemma hoare_to_hoare_rename':
  assumes Γ: "p bdy. Γ p = Some bdy  Γ' (N p) = Some (rename N bdy)"
  assumes deriv: "Z. Γ,{}⊢⇘/F(P Z) c (Q Z),(A Z)"
  shows "Z. Γ',{}⊢⇘/F(P Z) (rename N c) (Q Z),(A Z)"
apply rule
apply (rule hoare_to_hoare_rename [OF Γ])
apply (rule deriv[rule_format])
done

lemma terminates_to_terminates_rename:
  assumes Γ: "p bdy. Γ p = Some bdy  Γ' (N p) = Some (rename N bdy)"
  assumes termi: "Γ c  s"
  assumes noStuck: "Γ c,s ⇒∉{Stuck}"
  shows "Γ' rename N c  s"
using termi noStuck
proof (induct)
  case Skip thus ?case by (fastforce intro: terminates.intros)
next
  case Basic thus ?case by (fastforce intro: terminates.intros)
next
  case Spec thus ?case by (fastforce intro: terminates.intros)
next
  case Guard thus ?case by (fastforce intro: terminates.intros
    simp add: final_notin_def exec.intros)
next
  case GuardFault thus ?case by (fastforce intro: terminates.intros)
next
  case Fault thus ?case by (fastforce intro: terminates.intros)
next
  case Seq
  thus ?case
    by (force intro!: terminates.intros exec.intros dest: exec_rename_to_exec [OF Γ]
         simp add: final_notin_def)
next
  case CondTrue thus ?case by (fastforce intro: terminates.intros
    simp add: final_notin_def exec.intros)
next
  case CondFalse thus ?case by (fastforce intro: terminates.intros
    simp add: final_notin_def exec.intros)
next
  case (WhileTrue s b c)
  have s_in_b: "s  b" by fact
  have noStuck: "Γ While b c,Normal s ⇒∉{Stuck}" by fact
  with s_in_b have "Γ c,Normal s ⇒∉{Stuck}"
    by (auto simp add: final_notin_def intro: exec.intros)
  with WhileTrue.hyps have "Γ'rename N c  Normal s"
    by simp
  moreover
  {
    fix t
    assume exec_rc: "Γ' rename N c,Normal s  t"
    have "Γ' While b (rename N c)  t"
    proof -
      from exec_rename_to_exec [OF Γ exec_rc] obtain t'
        where exec_c: "Γ c,Normal s  t'" and t': "(t' = Stuck  t' = t)"
        by auto
      with s_in_b noStuck obtain "t'=t" and "Γ While b c,t ⇒∉{Stuck}"
        by (auto simp add: final_notin_def intro: exec.intros)
      with exec_c WhileTrue.hyps
      show ?thesis
        by auto
    qed
  }
  ultimately show ?case
    using s_in_b
    by (auto intro: terminates.intros)
next
  case WhileFalse thus ?case by (fastforce intro: terminates.intros)
next
  case (Call p bdy s)
  have "Γ p = Some bdy" by fact
  from Γ [rule_format, OF this]
  have bdy': "Γ' (N p) = Some (rename N bdy)".
  from Call have "Γ'rename N bdy  Normal s"
    by (auto simp add: final_notin_def intro: exec.intros)
  with bdy' have "Γ'Call (N p)  Normal s"
    by (auto intro: terminates.intros)
  thus ?case by simp
next
  case (CallUndefined p s)
  have "Γ p = None" "Γ Call p,Normal s ⇒∉{Stuck}" by fact+
  hence False by (auto simp add: final_notin_def intro: exec.intros)
  thus ?case ..
next
  case Stuck thus ?case by (fastforce intro: terminates.intros)
next
  case DynCom thus ?case by (fastforce intro: terminates.intros
    simp add: final_notin_def exec.intros)
next
  case Throw thus ?case by (fastforce intro: terminates.intros)
next
  case Abrupt thus ?case by (fastforce intro: terminates.intros)
next
  case (Catch c1 s c2)
  have noStuck: "Γ Catch c1 c2,Normal s ⇒∉{Stuck}" by fact
  hence "Γ c1,Normal s ⇒∉{Stuck}"
    by (fastforce simp add: final_notin_def intro: exec.intros)
  with Catch.hyps have "Γ'rename N c1  Normal s"
    by auto
  moreover
  {
    fix t
    assume exec_rc1:"Γ' rename N c1,Normal s  Abrupt t"
    have "Γ'rename N c2  Normal t"
    proof -
      from exec_rename_to_exec [OF Γ exec_rc1] obtain t'
        where exec_c: "Γ c1,Normal s  t'" and "(t' = Stuck  t' = Abrupt t)"
        by auto
      with noStuck have t': "t'=Abrupt t"
        by (fastforce simp add: final_notin_def intro: exec.intros)
      with exec_c noStuck have "Γ c2,Normal t ⇒∉{Stuck}"
        by (auto simp add: final_notin_def intro: exec.intros)
      with exec_c t' Catch.hyps
      show ?thesis
        by auto
    qed
  }
  ultimately show ?case
    by (auto intro: terminates.intros)
qed

lemma validt_to_validt_rename:
  assumes Γ: "p bdy. Γ p = Some bdy  Γ' (N p) = Some (rename N bdy)"
  assumes valid: "Γt⇘/FP c Q,A"
  shows "Γ't⇘/FP (rename N c) Q,A"
proof -
  from valid
  have "Γ'⊨⇘/FP (rename N c) Q,A"
    by (auto intro: valid_to_valid_rename [OF Γ] simp add: validt_def)
  moreover
  {
    fix s
    assume "s  P"
    with valid obtain "Γc  (Normal s)" "Γ c,Normal s ⇒∉{Stuck}"
      by (auto simp add: validt_def valid_def final_notin_def)
    from terminates_to_terminates_rename [OF Γ this]
    have "Γ'rename N c  Normal s"
      .
  }
  ultimately show ?thesis
    by (simp add: validt_def)
qed

lemma hoaret_to_hoaret_rename:
  assumes Γ: "p bdy. Γ p = Some bdy  Γ' (N p) = Some (rename N bdy)"
  assumes deriv: "Γ,{}t⇘/FP c Q,A"
  shows "Γ',{}t⇘/FP (rename N c) Q,A"
apply (rule hoaret_complete)
apply (insert hoaret_sound [OF deriv])
apply (rule validt_to_validt_rename)
apply  (rule Γ)
apply (simp add: cvalidt_def)
done

lemma hoaret_to_hoaret_rename':
  assumes Γ: "p bdy. Γ p = Some bdy  Γ' (N p) = Some (rename N bdy)"
  assumes deriv: "Z. Γ,{}t⇘/F(P Z) c (Q Z),(A Z)"
  shows "Z. Γ',{}t⇘/F(P Z) (rename N c) (Q Z),(A Z)"
apply rule
apply (rule hoaret_to_hoaret_rename [OF Γ])
apply (rule deriv[rule_format])
done

lemma liftc_whileAnno [simp]: "liftc prj inject (whileAnno b I V c) =
    whileAnno (lifts prj b)
              (lifts prj I) (liftr prj inject V) (liftc prj inject c)"
  by (simp add: whileAnno_def)

lemma liftc_block [simp]: "liftc prj inject (block init bdy return c) =
  block (liftf prj inject init) (liftc prj inject bdy)
        (λs. (liftf prj inject (return (prj s))))
        (λs t. liftc prj inject (c (prj s) (prj t)))"
  by (simp add: block_def block_exn_def)

(*
lemma liftc_block [simp]: "liftc prj inject (block init bdy return c) =
  block (liftf prj inject init) (liftc prj inject bdy)
        (λs t. inject s (return (prj s) (prj t)))
        (λs t. liftc prj inject (c (prj s) (prj t)))"
  apply (simp add: block_def)
  apply (simp add: liftf_def)
*)
lemma liftc_call [simp]: "liftc prj inject (call init p return c) =
  call (liftf prj inject init) p
        (λs. (liftf prj inject (return (prj s))))
        (λs t. liftc prj inject (c (prj s) (prj t)))"
  by (simp add: call_def liftc_block)

lemma rename_whileAnno [simp]: "rename h (whileAnno b I V c) =
   whileAnno b I V (rename h c)"
  by (simp add: whileAnno_def)

lemma rename_block [simp]: "rename h (block init bdy return c) =
  block init (rename h bdy) return (λs t. rename h (c s t))"
  by (simp add: block_def block_exn_def)

lemma rename_call [simp]: "rename h (call init p return c) =
  call init (h p) return (λs t. rename h (c s t))"
  by (simp add: call_def)


end