Theory Termination

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

Copyright (C) 2004-2008 Norbert Schirmer
Copyright (c) 2022 Apple Inc. All rights reserved.
*)
section ‹Terminating Programs›

theory Termination imports Semantic begin

subsection ‹Inductive Characterisation: Γ⊢c↓s›

inductive "terminates"::"('s,'p,'f) body  ('s,'p,'f) com  ('s,'f) xstate  bool"
  ("__  _" [60,20,60] 89)
  for  Γ::"('s,'p,'f) body"
where
  Skip: "ΓSkip (Normal s)"

| Basic: "ΓBasic f (Normal s)"

| Spec: "ΓSpec r (Normal s)"

| Guard: "sg; Γc(Normal s)
          
          ΓGuard f g c(Normal s)"

| GuardFault: "sg
               
               ΓGuard f g c(Normal s)"


| Fault [intro,simp]: "ΓcFault f"


| Seq: "Γc1Normal s; s'. Γc1,Normal s  s'  Γc2s'
        
        ΓSeq c1 c2(Normal s)"

| CondTrue: "s  b; Γc1(Normal s)
             
             ΓCond b c1 c2(Normal s)"


| CondFalse: "s  b; Γc2(Normal s)
             
             ΓCond b c1 c2(Normal s)"


| WhileTrue: "s  b; Γc(Normal s);
               s'. Γc,Normal s   s'  ΓWhile b cs'
              
              ΓWhile b c(Normal s)"

| WhileFalse: "s  b
               
               ΓWhile b c(Normal s)"

| Call:  "Γ p=Some bdy;Γbdy(Normal s)
          
          ΓCall p(Normal s)"

| CallUndefined:  "Γ p = None
                   
                   ΓCall p(Normal s)"

| Stuck [intro,simp]: "ΓcStuck"

| DynCom:  "Γ(c s)(Normal s)
             
             ΓDynCom c(Normal s)"

| Throw: "ΓThrow(Normal s)"

| Abrupt [intro,simp]: "ΓcAbrupt s"

| Catch: "Γc1Normal s;
           s'. Γc1,Normal s   Abrupt s'  Γc2Normal s'
          
          ΓCatch c1 c2Normal s"


inductive_cases terminates_elim_cases [cases set]:
  "ΓSkip  s"
  "ΓGuard f g c  s"
  "ΓBasic f  s"
  "ΓSpec r  s"
  "ΓSeq c1 c2  s"
  "ΓCond b c1 c2  s"
  "ΓWhile b c  s"
  "ΓCall p  s"
  "ΓDynCom c  s"
  "ΓThrow  s"
  "ΓCatch c1 c2  s"

inductive_cases terminates_Normal_elim_cases [cases set]:
  "ΓSkip  Normal s"
  "ΓGuard f g c  Normal s"
  "ΓBasic f  Normal s"
  "ΓSpec r  Normal s"
  "ΓSeq c1 c2  Normal s"
  "ΓCond b c1 c2  Normal s"
  "ΓWhile b c  Normal s"
  "ΓCall p  Normal s"
  "ΓDynCom c  Normal s"
  "ΓThrow  Normal s"
  "ΓCatch c1 c2  Normal s"

lemma terminates_Skip': "ΓSkip  s"
  by (cases s) (auto intro: terminates.intros)

lemma terminates_Call_body:
 "Γ p=Some bdyΓCall  p s = Γ(the (Γ p))s"
  by (cases s)
     (auto elim: terminates_Normal_elim_cases intro: terminates.intros)

lemma terminates_Normal_Call_body:
 "p  dom Γ 
  ΓCall p Normal s = Γ(the (Γ p))Normal s"
  by (auto elim: terminates_Normal_elim_cases intro: terminates.intros)

lemma terminates_implies_exec:
  assumes terminates: "Γcs"
  shows "t. Γc,s  t"
using terminates
proof (induct)
  case Skip thus ?case by (iprover intro: exec.intros)
next
  case Basic thus ?case by (iprover intro: exec.intros)
next
  case (Spec r s) thus ?case
    by (cases "t. (s,t) r") (auto intro: exec.intros)
next
  case Guard thus ?case by (iprover intro: exec.intros)
next
  case GuardFault thus ?case by (iprover intro: exec.intros)
next
  case Fault thus ?case by (iprover intro: exec.intros)
next
  case Seq thus ?case by (iprover intro: exec_Seq')
next
  case CondTrue thus ?case by (iprover intro: exec.intros)
next
  case CondFalse thus ?case by (iprover intro: exec.intros)
next
  case WhileTrue thus ?case by (iprover intro: exec.intros)
next
  case WhileFalse thus ?case by (iprover intro: exec.intros)
next
  case (Call p bdy s)
  then obtain s' where
    "Γbdy,Normal s   s'"
    by iprover
  moreover have "Γ p = Some bdy" by fact
  ultimately show ?case
    by (cases s') (iprover intro: exec.intros)+
next
  case CallUndefined thus ?case by (iprover intro: exec.intros)
next
  case Stuck thus ?case by (iprover intro: exec.intros)
next
  case DynCom thus ?case by (iprover intro: exec.intros)
next
  case Throw thus ?case by (iprover intro: exec.intros)
next
  case Abrupt thus ?case by (iprover intro: exec.intros)
next
  case (Catch c1 s c2)
  then obtain s' where exec_c1: "Γc1,Normal s   s'"
    by iprover
  thus ?case
  proof (cases s')
    case (Normal s'')
    with exec_c1 show ?thesis by (auto intro!: exec.intros)
  next
    case (Abrupt s'')
    with exec_c1 Catch.hyps
    obtain t where "Γc2,Normal s''   t"
      by auto
    with exec_c1 Abrupt show ?thesis by (auto intro: exec.intros)
  next
    case Fault
    with exec_c1 show ?thesis by (auto intro!: exec.CatchMiss)
  next
    case Stuck
    with exec_c1 show ?thesis by (auto intro!: exec.CatchMiss)
  qed
qed

lemma terminates_block_exn:
"Γbdy  Normal (init s);
  t. Γbdy,Normal (init s)  Normal t  Γc s t  Normal (return s t)
  Γblock_exn init bdy return result_exn c  Normal s"
apply (unfold block_exn_def)
apply (fastforce intro: terminates.intros elim!: exec_Normal_elim_cases
        dest!: not_isAbrD)
  done

lemma terminates_block:
"Γbdy  Normal (init s);
  t. Γbdy,Normal (init s)  Normal t  Γc s t  Normal (return s t)
  Γblock init bdy return c  Normal s"
  unfolding block_def
  by (rule terminates_block_exn)

lemma terminates_block_exn_elim [cases set, consumes 1]:
assumes termi: "Γblock_exn init bdy return result_exn c  Normal s"
assumes e: "Γbdy  Normal (init s);
          t. Γbdy,Normal (init s)  Normal t  Γc s t  Normal (return s t)
           P"
shows P
proof -
  have "ΓBasic init,Normal s  Normal (init s)"
    by (auto intro: exec.intros)
  with termi
  have "Γbdy  Normal (init s)"
    apply (unfold block_exn_def)
    apply (elim terminates_Normal_elim_cases)
    by simp
  moreover
  {
    fix t
    assume exec_bdy: "Γbdy,Normal (init s)  Normal t"
    have "Γc s t  Normal (return s t)"
    proof -
      from exec_bdy
      have "ΓCatch (Seq (Basic init) bdy)
                               (Seq (Basic (λt. result_exn (return s t) t)) Throw),Normal s  Normal t"
        by (fastforce intro: exec.intros)
      with termi have "ΓDynCom (λt. Seq (Basic (return s)) (c s t))  Normal t"
        apply (unfold block_exn_def)
        apply (elim terminates_Normal_elim_cases)
        by simp
      thus ?thesis
        apply (elim terminates_Normal_elim_cases)
        apply (auto intro: exec.intros)
        done
    qed
  }
  ultimately show P by (iprover intro: e)
qed

lemma terminates_block_elim [cases set, consumes 1]:
assumes termi: "Γblock init bdy return c  Normal s"
assumes e: "Γbdy  Normal (init s);
          t. Γbdy,Normal (init s)  Normal t  Γc s t  Normal (return s t)
           P"
shows P
  using termi e unfolding block_def by (rule terminates_block_exn_elim)


lemma terminates_call:
"Γ p = Some bdy; Γbdy  Normal (init s);
  t. Γbdy,Normal (init s)  Normal t  Γc s t  Normal (return s t)
  Γcall init p return c  Normal s"
  apply (unfold call_def)
  apply (rule terminates_block)
  apply  (iprover intro: terminates.intros)
  apply (auto elim: exec_Normal_elim_cases)
  done

lemma terminates_call_exn:
"Γ p = Some bdy; Γbdy  Normal (init s);
  t. Γbdy,Normal (init s)  Normal t  Γc s t  Normal (return s t)
  Γcall_exn init p return result_exn c  Normal s"
  apply (unfold call_exn_def)
  apply (rule terminates_block_exn)
  apply  (iprover intro: terminates.intros)
  apply (auto elim: exec_Normal_elim_cases)
  done

lemma terminates_callUndefined:
"Γ p = None
  Γcall init p return result  Normal s"
  apply (unfold call_def)
  apply (rule terminates_block)
  apply  (iprover intro: terminates.intros)
  apply (auto elim: exec_Normal_elim_cases)
  done

lemma terminates_call_exnUndefined:
"Γ p = None
  Γcall_exn init p return result_exn result  Normal s"
  apply (unfold call_exn_def)
  apply (rule terminates_block_exn)
  apply  (iprover intro: terminates.intros)
  apply (auto elim: exec_Normal_elim_cases)
  done

lemma terminates_call_exn_elim [cases set, consumes 1]:
assumes termi: "Γcall_exn init p return result_exn c  Normal s"
assumes bdy: "bdy. Γ p = Some bdy; Γbdy  Normal (init s);
     t. Γbdy,Normal (init s)  Normal t  Γc s t  Normal (return s t)  P"
assumes undef: "Γ p = None  P"
shows P
apply (cases "Γ p")
apply  (erule undef)
using termi
apply (unfold call_exn_def)
apply (erule terminates_block_exn_elim)
apply (erule terminates_Normal_elim_cases)
apply  simp
apply  (frule (1) bdy)
apply   (fastforce intro: exec.intros)
apply  assumption
apply simp
done

lemma terminates_call_elim [cases set, consumes 1]:
assumes termi: "Γcall init p return c  Normal s"
assumes bdy: "bdy. Γ p = Some bdy; Γbdy  Normal (init s);
     t. Γbdy,Normal (init s)  Normal t  Γc s t  Normal (return s t)  P"
assumes undef: "Γ p = None  P"
shows P
  using termi bdy undef unfolding call_call_exn by (rule terminates_call_exn_elim)


lemma terminates_dynCall:
"Γcall init (p s) return c  Normal s
  ΓdynCall init p return c  Normal s"
  apply (unfold dynCall_def)
  apply (auto intro: terminates.intros terminates_call)
  done

lemma terminates_guards: "Γc  Normal s  Γguards gs c  Normal s"
  by (induct gs) (auto intro: terminates.intros)

lemma terminates_guards_Fault: "find (λ(f, g). s  g) gs = Some (f, g)  Γguards gs c  Normal s"
 by (induct gs) (auto intro: terminates.intros split: if_split_asm prod.splits)

lemma terminates_maybe_guard_Fault: "s  g  Γmaybe_guard f g c  Normal s"
  by (metis UNIV_I maybe_guard_def terminates.GuardFault)

lemma terminates_guards_DynCom: "Γ(c s)  Normal s  Γguards gs (DynCom c)  Normal s"
  by (induct gs) (auto intro: terminates.intros)

lemma terminates_maybe_guard_DynCom: "Γ(c s)  Normal s  Γmaybe_guard f g (DynCom c)  Normal s"
  by (metis maybe_guard_def terminates.DynCom terminates.Guard terminates.GuardFault)


lemma terminates_dynCall_exn:
"Γcall_exn init (p s) return result_exn c  Normal s
  ΓdynCall_exn f g init p return result_exn c  Normal s"
  apply (unfold dynCall_exn_def)
  by (rule terminates_maybe_guard_DynCom)

lemma terminates_dynCall_elim [cases set, consumes 1]:
assumes termi: "ΓdynCall init p return c  Normal s"
assumes "Γcall init (p s) return c  Normal s  P"
shows P
using termi
apply (unfold dynCall_def)
apply (elim terminates_Normal_elim_cases)
apply fact
done

lemma terminates_guards_elim [cases set, consumes 1, case_names noFault someFault]:
  assumes termi: "Γguards gs c  Normal s"
  assumes noFault: "f g. (f, g)  set gs  s  g; Γc  Normal s  P"
  assumes someFault: "f g. find (λ(f,g). s  g) gs = Some (f, g)  P"
  shows P
  using termi noFault someFault
  by (induct gs)
     (auto elim: terminates_Normal_elim_cases split: if_split_asm prod.splits)

lemma terminates_maybe_guard_elim [cases set, consumes 1, case_names noFault someFault]:
  assumes termi: "Γmaybe_guard f g c  Normal s"
  assumes noFault: "s  g; Γc  Normal s  P"
  assumes someFault: "s  g  P"
  shows P
  using termi noFault someFault
  by (metis maybe_guard_def terminates_Normal_elim_cases(2))

lemma terminates_dynCall_exn_elim [cases set, consumes 1, case_names noFault someFault]:
assumes termi: "ΓdynCall_exn f g init p return result_exn c  Normal s"
assumes noFault: "s  g;
 Γcall_exn init (p s) return result_exn c  Normal s  P"
assumes someFault: "s  g  P"
shows P
using termi noFault someFault
  apply (unfold dynCall_exn_def)
  apply (erule terminates_maybe_guard_elim)
  apply (auto elim: terminates_Normal_elim_cases)
  done

(* ************************************************************************* *)
subsection ‹Lemmas about @{const "sequence"}, @{const "flatten"} and
 @{const "normalize"}
(* ************************************************************************ *)

lemma terminates_sequence_app:
  "s. Γsequence Seq xs  Normal s;
        s'. Γsequence Seq xs,Normal s   s'   Γsequence Seq ys  s'
 Γsequence Seq (xs @ ys)  Normal s"
proof (induct xs)
  case Nil
  thus ?case by (auto intro: exec.intros)
next
  case (Cons x xs)
  have termi_x_xs: "Γsequence Seq (x # xs)  Normal s" by fact
  have termi_ys: "s'. Γsequence Seq (x # xs),Normal s   s'  Γsequence Seq ys  s'" by fact
  show ?case
  proof (cases xs)
    case Nil
    with termi_x_xs termi_ys show ?thesis
      by (cases ys) (auto intro: terminates.intros)
  next
    case Cons
    from termi_x_xs Cons
    have "Γx  Normal s"
      by (auto elim: terminates_Normal_elim_cases)
    moreover
    {
      fix s'
      assume exec_x: "Γx,Normal s   s'"
      have "Γsequence Seq (xs @ ys)  s'"
      proof -
        from exec_x termi_x_xs Cons
        have termi_xs: "Γsequence Seq xs  s'"
          by (auto elim: terminates_Normal_elim_cases)
        show ?thesis
        proof (cases s')
          case (Normal s'')
          with exec_x termi_ys Cons
          have "s'. Γsequence Seq xs,Normal s''   s'  Γsequence Seq ys  s'"
            by (auto intro: exec.intros)
          from Cons.hyps [OF termi_xs [simplified Normal] this]
          have "Γsequence Seq (xs @ ys)  Normal s''".
          with Normal show ?thesis by simp
        next
          case Abrupt thus ?thesis by (auto intro: terminates.intros)
        next
          case Fault thus ?thesis by (auto intro: terminates.intros)
        next
          case Stuck thus ?thesis by (auto intro: terminates.intros)
        qed
      qed
    }
    ultimately show ?thesis
      using Cons
      by (auto intro: terminates.intros)
  qed
qed

lemma terminates_sequence_appD:
  "s. Γsequence Seq (xs @ ys)  Normal s
    Γsequence Seq xs  Normal s 
       (s'. Γsequence Seq xs,Normal s   s'   Γsequence Seq ys  s')"
proof (induct xs)
  case Nil
  thus ?case
    by (auto elim: terminates_Normal_elim_cases exec_Normal_elim_cases
         intro: terminates.intros)
next
  case (Cons x xs)
  have termi_x_xs_ys: "Γsequence Seq ((x # xs) @ ys)  Normal s" by fact
  show ?case
  proof (cases xs)
    case Nil
    with termi_x_xs_ys show ?thesis
      by (cases ys)
         (auto elim: terminates_Normal_elim_cases exec_Normal_elim_cases
           intro:  terminates_Skip')
  next
    case Cons
    with termi_x_xs_ys
    obtain termi_x: "Γx  Normal s" and
           termi_xs_ys: "s'. Γx,Normal s   s'   Γsequence Seq (xs@ys)  s'"
      by (auto elim: terminates_Normal_elim_cases)

    have "ΓSeq x (sequence Seq xs)  Normal s"
    proof (rule terminates.Seq [rule_format])
      show "Γx  Normal s" by (rule termi_x)
    next
      fix s'
      assume exec_x: "Γx,Normal s   s'"
      show "Γsequence Seq xs  s'"
      proof -
        from termi_xs_ys [rule_format, OF exec_x]
        have termi_xs_ys': "Γsequence Seq (xs@ys)  s'" .
        show ?thesis
        proof (cases s')
          case (Normal s'')
          from Cons.hyps [OF termi_xs_ys' [simplified Normal]]
          show ?thesis
            using Normal by auto
        next
          case Abrupt thus ?thesis by (auto intro: terminates.intros)
        next
          case Fault thus ?thesis by (auto intro: terminates.intros)
        next
          case Stuck thus ?thesis by (auto intro: terminates.intros)
        qed
      qed
    qed
    moreover
    {
      fix s'
      assume exec_x_xs: "ΓSeq x (sequence Seq xs),Normal s   s'"
      have "Γsequence Seq ys  s'"
      proof -
        from exec_x_xs obtain t where
          exec_x: "Γx,Normal s   t" and
          exec_xs: "Γsequence Seq xs,t   s'"
          by cases
        show ?thesis
        proof (cases t)
          case (Normal t')
          with exec_x termi_xs_ys have "Γsequence Seq (xs@ys)  Normal t'"
            by auto
          from Cons.hyps [OF this] exec_xs Normal
          show ?thesis
            by auto
        next
          case (Abrupt t')
          with exec_xs have "s'=Abrupt t'"
            by (auto dest: Abrupt_end)
          thus ?thesis by (auto intro: terminates.intros)
        next
          case (Fault f)
          with exec_xs have "s'=Fault f"
            by (auto dest: Fault_end)
          thus ?thesis by (auto intro: terminates.intros)
        next
          case Stuck
          with exec_xs have "s'=Stuck"
            by (auto dest: Stuck_end)
          thus ?thesis by (auto intro: terminates.intros)
        qed
      qed
    }
    ultimately show ?thesis
      using Cons
      by auto
  qed
qed

lemma terminates_sequence_appE [consumes 1]:
  "Γsequence Seq (xs @ ys)  Normal s;
    Γsequence Seq xs  Normal s;
     s'. Γsequence Seq xs,Normal s   s'   Γsequence Seq ys  s'  P
    P"
  by (auto dest: terminates_sequence_appD)

lemma terminates_to_terminates_sequence_flatten:
  assumes termi: "Γcs"
  shows "Γsequence Seq (flatten c)s"
using termi
by (induct)
   (auto intro: terminates.intros terminates_sequence_app
     exec_sequence_flatten_to_exec)

lemma terminates_to_terminates_normalize:
  assumes termi: "Γcs"
  shows "Γnormalize cs"
using termi
proof induct
  case Seq
  thus ?case
    by (fastforce intro: terminates.intros terminates_sequence_app
                 terminates_to_terminates_sequence_flatten
        dest: exec_sequence_flatten_to_exec exec_normalize_to_exec)
next
  case WhileTrue
  thus ?case
    by (fastforce intro: terminates.intros terminates_sequence_app
                 terminates_to_terminates_sequence_flatten
        dest: exec_sequence_flatten_to_exec exec_normalize_to_exec)
next
  case Catch
  thus ?case
    by (fastforce intro: terminates.intros terminates_sequence_app
                 terminates_to_terminates_sequence_flatten
        dest: exec_sequence_flatten_to_exec exec_normalize_to_exec)
qed (auto intro: terminates.intros)

lemma terminates_sequence_flatten_to_terminates:
  shows "s. Γsequence Seq (flatten c)s  Γcs"
proof (induct c)
  case (Seq c1 c2)
  have "Γsequence Seq (flatten (Seq c1 c2))  s" by fact
  hence termi_app: "Γsequence Seq (flatten c1 @ flatten c2)  s" by simp
  show ?case
  proof (cases s)
    case (Normal s')
    have "ΓSeq c1 c2  Normal s'"
    proof (rule terminates.Seq [rule_format])
      from termi_app [simplified Normal]
      have "Γsequence Seq (flatten c1)  Normal s'"
        by (cases rule: terminates_sequence_appE)
      with Seq.hyps
      show "Γc1  Normal s'"
        by simp
    next
      fix s''
      assume "Γc1,Normal s'   s''"
      from termi_app [simplified Normal] exec_to_exec_sequence_flatten [OF this]
      have "Γsequence Seq (flatten c2)  s''"
        by (cases rule: terminates_sequence_appE) auto
      with Seq.hyps
      show "Γc2  s''"
        by simp
    qed
    with Normal show ?thesis
      by simp
  qed (auto intro: terminates.intros)
qed (auto intro: terminates.intros)

lemma terminates_normalize_to_terminates:
  shows "s. Γnormalize cs  Γcs"
proof (induct c)
  case Skip thus ?case by (auto intro:  terminates_Skip')
next
  case Basic thus ?case by (cases s) (auto intro: terminates.intros)
next
  case Spec thus ?case by (cases s) (auto intro: terminates.intros)
next
  case (Seq c1 c2)
  have "Γnormalize (Seq c1 c2)  s" by fact
  hence termi_app: "Γsequence Seq (flatten (normalize c1) @ flatten (normalize c2))  s"
    by simp
  show ?case
  proof (cases s)
    case (Normal s')
    have "ΓSeq c1 c2  Normal s'"
    proof (rule terminates.Seq [rule_format])
      from termi_app [simplified Normal]
      have "Γsequence Seq (flatten (normalize c1))   Normal s'"
        by (cases rule: terminates_sequence_appE)
      from terminates_sequence_flatten_to_terminates [OF this] Seq.hyps
      show "Γc1  Normal s'"
        by simp
    next
      fix s''
      assume "Γc1,Normal s'   s''"
      from exec_to_exec_normalize [OF this]
      have "Γnormalize c1,Normal s'   s''" .
      from termi_app [simplified Normal] exec_to_exec_sequence_flatten [OF this]
      have "Γsequence Seq (flatten (normalize c2))   s''"
        by (cases rule: terminates_sequence_appE) auto
      from terminates_sequence_flatten_to_terminates [OF this] Seq.hyps
      show "Γc2  s''"
        by simp
    qed
    with Normal show ?thesis by simp
  qed (auto intro: terminates.intros)
next
  case (Cond b c1 c2)
  thus ?case
    by (cases s)
       (auto intro: terminates.intros elim!: terminates_Normal_elim_cases)
next
  case (While b c)
  have "Γnormalize (While b c)  s" by fact
  hence termi_norm_w: "ΓWhile b (normalize c)  s" by simp
  {
    fix t w
    assume termi_w: "Γ w  t"
    have "w=While b (normalize c)  ΓWhile b c  t"
      using termi_w
    proof (induct)
      case (WhileTrue t' b' c')
      from WhileTrue obtain
        t'_b: "t'  b" and
        termi_norm_c: "Γnormalize c  Normal t'" and
        termi_norm_w': "s'. Γnormalize c,Normal t'   s'  ΓWhile b c  s'"
        by auto
      from While.hyps [OF termi_norm_c]
      have "Γc  Normal t'".
      moreover
      from termi_norm_w'
      have "s'. Γc,Normal t'   s'  ΓWhile b c  s'"
        by (auto intro: exec_to_exec_normalize)
      ultimately show ?case
        using t'_b
        by (auto intro: terminates.intros)
    qed (auto intro: terminates.intros)
  }
  from this [OF termi_norm_w]
  show ?case
    by auto
next
  case Call thus ?case by simp
next
  case DynCom thus ?case
    by (cases s) (auto intro: terminates.intros rangeI elim: terminates_Normal_elim_cases)
next
  case Guard thus ?case
    by (cases s) (auto intro: terminates.intros elim: terminates_Normal_elim_cases)
next
  case Throw thus ?case by (cases s) (auto intro: terminates.intros)
next
  case Catch
  thus ?case
    by (cases s)
       (auto dest: exec_to_exec_normalize elim!: terminates_Normal_elim_cases
         intro!: terminates.Catch)
qed

lemma terminates_iff_terminates_normalize:
"Γnormalize cs = Γcs"
  by (auto intro: terminates_to_terminates_normalize
    terminates_normalize_to_terminates)

(* ************************************************************************* *)
subsection ‹Lemmas about @{const "strip_guards"}
(* ************************************************************************* *)

lemma terminates_strip_guards_to_terminates: "s. Γstrip_guards F cs   Γcs"
proof (induct c)
  case Skip thus ?case by simp
next
  case Basic thus ?case by simp
next
  case Spec thus ?case by simp
next
  case (Seq c1 c2)
  hence "ΓSeq (strip_guards F c1) (strip_guards F c2)  s" by simp
  thus "ΓSeq c1 c2  s"
  proof (cases)
    fix f assume "s=Fault f" thus ?thesis by simp
  next
    assume "s=Stuck" thus ?thesis by simp
  next
    fix s' assume "s=Abrupt s'" thus ?thesis by simp
  next
    fix s'
    assume s: "s=Normal s'"
    assume "Γstrip_guards F c1  Normal s'"
    hence "Γc1  Normal s'"
      by (rule Seq.hyps)
    moreover
    assume c2:
      "s''. Γstrip_guards F c1,Normal s'  s''  Γstrip_guards F c2s''"
    {
      fix s'' assume exec_c1: "Γc1,Normal s'   s''"
      have " Γc2  s''"
      proof (cases s'')
        case (Normal s''')
        with exec_c1
        have "Γstrip_guards F c1,Normal s'   s''"
          by (auto intro: exec_to_exec_strip_guards)
        with c2
        show ?thesis
          by (iprover intro: Seq.hyps)
      next
        case (Abrupt s''')
        with exec_c1
        have "Γstrip_guards F c1,Normal s'   s''"
          by (auto intro: exec_to_exec_strip_guards )
        with c2
        show ?thesis
          by (iprover intro: Seq.hyps)
      next
        case Fault thus ?thesis by simp
      next
        case Stuck thus ?thesis by simp
      qed
    }
    ultimately show ?thesis
      using s
      by (iprover intro: terminates.intros)
  qed
next
  case (Cond b c1 c2)
  hence "ΓCond b (strip_guards F c1) (strip_guards F c2)  s" by simp
  thus "ΓCond b c1 c2  s"
  proof (cases)
    fix f assume "s=Fault f" thus ?thesis by simp
  next
    assume "s=Stuck" thus ?thesis by simp
  next
    fix s' assume "s=Abrupt s'" thus ?thesis by simp
  next
    fix s'
    assume "s'b" "Γstrip_guards F c1  Normal s'" "s = Normal s'"
    thus ?thesis
      by (iprover intro: terminates.intros Cond.hyps)
  next
    fix s'
    assume "s'b" "Γstrip_guards F c2  Normal s'" "s = Normal s'"
    thus ?thesis
      by (iprover intro: terminates.intros Cond.hyps)
  qed
next
  case (While b c)
  have hyp_c: "s. Γstrip_guards F c  s  Γc  s" by fact
  have "ΓWhile b (strip_guards F c)  s" using While.prems by simp
  moreover
  {
    fix sw
    assume "Γsws"
    then have "sw=While b (strip_guards F c) 
      ΓWhile b c  s"
    proof (induct)
      case (WhileTrue s b' c')
      have eqs: "While b' c' = While b (strip_guards F c)" by fact
      with sb' have b: "sb" by simp
      from eqs Γc'  Normal s have "Γstrip_guards F c  Normal s"
        by simp
      hence term_c: "Γc  Normal s"
        by (rule hyp_c)
      moreover
      {
        fix t
        assume exec_c: "Γc,Normal s   t"
        have "ΓWhile b c  t"
        proof (cases t)
          case Fault
          thus ?thesis by simp
        next
          case Stuck
          thus ?thesis by simp
        next
          case (Abrupt t')
          thus ?thesis by simp
        next
          case (Normal t')
          with exec_c
          have "Γstrip_guards F c,Normal s   Normal t'"
            by (auto intro: exec_to_exec_strip_guards)
          with WhileTrue.hyps eqs Normal
          show ?thesis
            by fastforce
        qed
      }
      ultimately
      show ?case
        using b
        by (auto intro: terminates.intros)
    next
      case WhileFalse thus ?case by (auto intro: terminates.intros)
    qed simp_all
  }
  ultimately show "ΓWhile b c  s"
    by auto
next
  case Call thus ?case by simp
next
  case DynCom thus ?case
     by (cases s) (auto elim: terminates_Normal_elim_cases intro: terminates.intros rangeI)
next
  case Guard
  thus ?case
    by (cases s) (auto elim: terminates_Normal_elim_cases intro: terminates.intros
                  split: if_split_asm)
next
  case Throw thus ?case by simp
next
  case (Catch c1 c2)
  hence "ΓCatch (strip_guards F c1) (strip_guards F c2)  s" by simp
  thus "ΓCatch c1 c2  s"
  proof (cases)
    fix f assume "s=Fault f" thus ?thesis by simp
  next
    assume "s=Stuck" thus ?thesis by simp
  next
    fix s' assume "s=Abrupt s'" thus ?thesis by simp
  next
    fix s'
    assume s: "s=Normal s'"
    assume "Γstrip_guards F c1  Normal s'"
    hence "Γc1  Normal s'"
      by (rule Catch.hyps)
    moreover
    assume c2:
      "s''. Γstrip_guards F c1,Normal s'  Abrupt s''
              Γstrip_guards F c2Normal s''"
    {
      fix s'' assume exec_c1: "Γc1,Normal s'   Abrupt s''"
      have " Γc2  Normal s''"
      proof -
        from exec_c1
        have "Γstrip_guards F c1,Normal s'   Abrupt s''"
          by (auto intro: exec_to_exec_strip_guards)
        with c2
        show ?thesis
          by (auto intro: Catch.hyps)
      qed
    }
    ultimately show ?thesis
      using s
      by (iprover intro: terminates.intros)
  qed
qed

lemma terminates_strip_to_terminates:
  assumes termi_strip: "strip F Γcs"
  shows "Γcs"
using termi_strip
proof induct
  case (Seq c1 s c2)
  have "Γc1  Normal s" by fact
  moreover
  {
    fix s'
    assume exec: "Γ c1,Normal s  s'"
    have "Γc2  s'"
    proof (cases "isFault s'")
      case True
      thus ?thesis
        by (auto elim: isFaultE)
    next
      case False
      from exec_to_exec_strip [OF exec this] Seq.hyps
      show ?thesis
        by auto
    qed
  }
  ultimately show ?case
    by (auto intro: terminates.intros)
next
  case (WhileTrue s b c)
  have "Γc  Normal s" by fact
  moreover
  {
    fix s'
    assume exec: "Γ c,Normal s  s'"
    have "ΓWhile b c  s'"
    proof (cases "isFault s'")
      case True
      thus ?thesis
        by (auto elim: isFaultE)
    next
      case False
      from exec_to_exec_strip [OF exec this] WhileTrue.hyps
      show ?thesis
        by auto
    qed
  }
  ultimately show ?case
    by (auto intro: terminates.intros)
next
  case (Catch c1 s c2)
  have "Γc1  Normal s" by fact
  moreover
  {
    fix s'
    assume exec: "Γ c1,Normal s  Abrupt s'"
    from exec_to_exec_strip [OF exec] Catch.hyps
    have "Γc2  Normal s'"
      by auto
  }
  ultimately show ?case
    by (auto intro: terminates.intros)
next
  case Call thus ?case
    by (auto intro: terminates.intros terminates_strip_guards_to_terminates)
qed (auto intro: terminates.intros)

(* ************************************************************************* *)
subsection ‹Lemmas about @{term "c1 g c2"}
(* ************************************************************************* *)

lemma inter_guards_terminates:
  "c c2 s. (c1 g c2) = Some c; Γc1s 
         Γcs"
proof (induct c1)
  case Skip thus ?case by (fastforce simp add: inter_guards_Skip)
next
  case (Basic f) thus ?case by (fastforce simp add: inter_guards_Basic)
next
  case (Spec r) thus ?case by (fastforce simp add: inter_guards_Spec)
next
  case (Seq a1 a2)
  have "(Seq a1 a2 g c2) = Some c" by fact
  then obtain b1 b2 d1 d2 where
    c2: "c2=Seq b1 b2" and
    d1: "(a1 g b1) = Some d1" and d2: "(a2 g b2) = Some d2" and
    c: "c=Seq d1 d2"
    by (auto simp add: inter_guards_Seq)
  have termi_c1: "ΓSeq a1 a2  s" by fact
  have "ΓSeq d1 d2  s"
  proof (cases s)
    case Fault thus ?thesis by simp
  next
    case Stuck thus ?thesis by simp
  next
    case Abrupt thus ?thesis by simp
  next
    case (Normal s')
    note Normal_s = this
    with d1 termi_c1
    have "Γd1  Normal s'"
      by (auto elim: terminates_Normal_elim_cases intro: Seq.hyps)
    moreover
    {
      fix t
      assume exec_d1: "Γd1,Normal s'   t"
      have "Γd2  t"
      proof (cases t)
        case Fault thus ?thesis by simp
      next
        case Stuck thus ?thesis by simp
      next
        case Abrupt thus ?thesis by simp
      next
        case (Normal t')
        with inter_guards_exec_noFault [OF d1 exec_d1]
        have "Γa1,Normal s'   Normal t'"
          by simp
        with termi_c1 Normal_s have "Γa2  Normal t'"
          by (auto elim: terminates_Normal_elim_cases)
        with d2 have "Γd2  Normal t'"
          by (auto intro: Seq.hyps)
        with Normal show ?thesis by simp
      qed
    }
    ultimately have "ΓSeq d1 d2  Normal s'"
      by (fastforce intro: terminates.intros)
    with Normal show ?thesis by simp
  qed
  with c show ?case by simp
next
  case Cond thus ?case
    by - (cases s,
          auto intro: terminates.intros elim!: terminates_Normal_elim_cases
               simp add: inter_guards_Cond)
next
  case (While b bdy1)
  have "(While b bdy1 g c2) = Some c" by fact
  then obtain bdy2 bdy where
    c2: "c2=While b bdy2" and
    bdy: "(bdy1 g bdy2) = Some bdy" and
    c: "c=While b bdy"
    by (auto simp add: inter_guards_While)
  have "ΓWhile b bdy1  s" by fact
  moreover
  {
    fix s w w1 w2
    assume termi_w:  "Γw  s"
    assume w: "w=While b bdy1"
    from termi_w w
    have "ΓWhile b bdy  s"
    proof (induct)
      case (WhileTrue s b' bdy1')
      have eqs: "While b' bdy1' = While b bdy1" by fact
      from WhileTrue have s_in_b: "s  b" by simp
      from WhileTrue have termi_bdy1: "Γbdy1  Normal s" by simp
      show ?case
      proof -
        from bdy termi_bdy1
        have "Γbdy(Normal s)"
          by (rule While.hyps)
        moreover
        {
          fix t
          assume exec_bdy: "Γbdy,Normal s   t"
          have "ΓWhile b bdyt"
          proof (cases t)
            case Fault thus ?thesis by simp
          next
            case Stuck thus ?thesis by simp
          next
            case Abrupt thus ?thesis by simp
          next
            case (Normal t')
            with inter_guards_exec_noFault [OF bdy exec_bdy]
            have "Γbdy1,Normal s   Normal t'"
              by simp
            with WhileTrue have "ΓWhile b bdy  Normal t'"
              by simp
            with Normal show ?thesis by simp
          qed
        }
        ultimately show ?thesis
          using s_in_b
          by (blast intro: terminates.WhileTrue)
      qed
    next
      case WhileFalse thus ?case
        by (blast intro: terminates.WhileFalse)
    qed (simp_all)
  }
  ultimately
  show ?case using c by simp
next
  case Call thus ?case by (simp add: inter_guards_Call)
next
  case (DynCom f1)
  have "(DynCom f1 g c2) = Some c" by fact
  then obtain f2 f where
    c2: "c2=DynCom f2" and
    f_defined: "s. ((f1 s) g (f2 s))  None" and
    c: "c=DynCom (λs. the ((f1 s) g (f2 s)))"
    by (auto simp add: inter_guards_DynCom)
  have termi: "ΓDynCom f1  s" by fact
  show ?case
  proof (cases s)
    case Fault thus ?thesis by simp
  next
    case Stuck thus ?thesis by simp
  next
    case Abrupt thus ?thesis by simp
  next
    case (Normal s')
    from f_defined obtain f where f: "((f1 s') g (f2 s')) = Some f"
      by auto
    from Normal termi
    have "Γf1 s' (Normal s')"
      by (auto elim: terminates_Normal_elim_cases)
    from DynCom.hyps f this
    have "Γf (Normal s')"
      by blast
    with c f Normal
    show ?thesis
      by (auto intro: terminates.intros)
  qed
next
  case (Guard f g1 bdy1)
  have "(Guard f g1 bdy1 g c2) = Some c" by fact
  then obtain g2 bdy2 bdy where
    c2: "c2=Guard f g2 bdy2" and
    bdy: "(bdy1 g bdy2) = Some bdy" and
    c: "c=Guard f (g1  g2) bdy"
    by (auto simp add: inter_guards_Guard)
  have termi_c1: "ΓGuard f g1 bdy1  s" by fact
  show ?case
  proof (cases s)
    case Fault thus ?thesis by simp
  next
    case Stuck thus ?thesis by simp
  next
    case Abrupt thus ?thesis by simp
  next
    case (Normal s')
    show ?thesis
    proof (cases "s'  g1")
      case False
      with Normal c show ?thesis by (auto intro: terminates.GuardFault)
    next
      case True
      note s_in_g1 = this
      show ?thesis
      proof (cases "s'  g2")
        case False
        with Normal c show ?thesis by (auto intro: terminates.GuardFault)
      next
        case True
        with termi_c1 s_in_g1 Normal have "Γbdy1  Normal s'"
          by (auto elim: terminates_Normal_elim_cases)
        with c bdy Guard.hyps Normal True s_in_g1
        show ?thesis by (auto intro: terminates.Guard)
      qed
    qed
  qed
next
  case Throw thus ?case
    by (auto simp add: inter_guards_Throw)
next
  case (Catch a1 a2)
  have "(Catch a1 a2 g c2) = Some c" by fact
  then obtain b1 b2 d1 d2 where
    c2: "c2=Catch b1 b2" and
    d1: "(a1 g b1) = Some d1" and d2: "(a2 g b2) = Some d2" and
    c: "c=Catch d1 d2"
    by (auto simp add: inter_guards_Catch)
  have termi_c1: "ΓCatch a1 a2  s" by fact
  have "ΓCatch d1 d2  s"
  proof (cases s)
    case Fault thus ?thesis by simp
  next
    case Stuck thus ?thesis by simp
  next
    case Abrupt thus ?thesis by simp
  next
    case (Normal s')
    note Normal_s = this
    with d1 termi_c1
    have "Γd1  Normal s'"
      by (auto elim: terminates_Normal_elim_cases intro: Catch.hyps)
    moreover
    {
      fix t
      assume exec_d1: "Γd1,Normal s'   Abrupt t"
      have "Γd2  Normal t"
      proof -
        from inter_guards_exec_noFault [OF d1 exec_d1]
        have "Γa1,Normal s'   Abrupt t"
          by simp
        with termi_c1 Normal_s have "Γa2  Normal t"
          by (auto elim: terminates_Normal_elim_cases)
        with d2 have "Γd2  Normal t"
          by (auto intro: Catch.hyps)
        with Normal show ?thesis by simp
      qed
    }
    ultimately have "ΓCatch d1 d2  Normal s'"
      by (fastforce intro: terminates.intros)
    with Normal show ?thesis by simp
  qed
  with c show ?case by simp
qed

lemma inter_guards_terminates':
  assumes c: "(c1 g c2) = Some c"
  assumes termi_c2: "Γc2s"
  shows "Γcs"
proof -
  from c have "(c2 g c1) = Some c"
    by (rule inter_guards_sym)
  from this termi_c2 show ?thesis
    by (rule inter_guards_terminates)
qed

(* ************************************************************************* *)
subsection ‹Lemmas about @{const "mark_guards"}
(* ************************************************************************ *)

lemma terminates_to_terminates_mark_guards:
  assumes termi: "Γcs"
  shows "Γmark_guards f cs"
using termi
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)
next
  case GuardFault thus ?case by (fastforce intro: terminates.intros)
next
  case Fault thus ?case by (fastforce intro: terminates.intros)
next
  case (Seq c1 s c2)
  have "Γmark_guards f c1  Normal s" by fact
  moreover
  {
    fix t
    assume exec_mark: "Γmark_guards f c1,Normal s   t"
    have "Γmark_guards f c2  t"
    proof -
      from exec_mark_guards_to_exec [OF exec_mark] obtain t' where
        exec_c1: "Γc1,Normal s   t'" and
        t_Fault: "isFault t  isFault t'" and
        t'_Fault_f: "t' = Fault f  t' = t" and
        t'_Fault: "isFault t'  isFault t" and
        t'_noFault: "¬ isFault t'  t' = t"
        by blast
      show ?thesis
      proof (cases "isFault t'")
        case True
        with t'_Fault have "isFault t" by simp
        thus ?thesis
          by (auto elim: isFaultE)
      next
        case False
        with t'_noFault have "t'=t" by simp
        with exec_c1 Seq.hyps
        show ?thesis
          by auto
      qed
    qed
  }
  ultimately show ?case
    by (auto intro: terminates.intros)
next
  case CondTrue thus ?case by (fastforce intro: terminates.intros)
next
  case CondFalse thus ?case by (fastforce intro: terminates.intros)
next
  case (WhileTrue s b c)
  have s_in_b: "s  b" by fact
  have "Γmark_guards f c  Normal s" by fact
  moreover
  {
    fix t
    assume exec_mark: "Γmark_guards f c,Normal s   t"
    have "Γmark_guards f (While b c)  t"
    proof -
      from exec_mark_guards_to_exec [OF exec_mark] obtain t' where
        exec_c1: "Γc,Normal s   t'" and
        t_Fault: "isFault t  isFault t'" and
        t'_Fault_f: "t' = Fault f  t' = t" and
        t'_Fault: "isFault t'  isFault t" and
        t'_noFault: "¬ isFault t'  t' = t"
        by blast
      show ?thesis
      proof (cases "isFault t'")
        case True
        with t'_Fault have "isFault t" by simp
        thus ?thesis
          by (auto elim: isFaultE)
      next
        case False
        with t'_noFault have "t'=t" by simp
        with exec_c1 WhileTrue.hyps
        show ?thesis
          by auto
      qed
    qed
  }
  ultimately show ?case
    by (auto intro: terminates.intros)
next
  case WhileFalse thus ?case by (fastforce intro: terminates.intros)
next
  case Call thus ?case by (fastforce intro: terminates.intros)
next
  case CallUndefined thus ?case by (fastforce intro: terminates.intros)
next
  case Stuck thus ?case by (fastforce intro: terminates.intros)
next
  case DynCom thus ?case by (fastforce intro: terminates.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 "Γmark_guards f c1  Normal s" by fact
  moreover
  {
    fix t
    assume exec_mark: "Γmark_guards f c1,Normal s   Abrupt t"
    have "Γmark_guards f c2  Normal t"
    proof -
      from exec_mark_guards_to_exec [OF exec_mark] obtain t' where
        exec_c1: "Γc1,Normal s   t'" and
        t'_Fault_f: "t' = Fault f  t' = Abrupt t" and
        t'_Fault: "isFault t'  isFault (Abrupt t)" and
        t'_noFault: "¬ isFault t'  t' = Abrupt t"
        by fastforce
      show ?thesis
      proof (cases "isFault t'")
        case True
        with t'_Fault have "isFault (Abrupt t)" by simp
        thus ?thesis by simp
      next
        case False
        with t'_noFault have "t'=Abrupt t" by simp
        with exec_c1 Catch.hyps
        show ?thesis
          by auto
      qed
    qed
  }
  ultimately show ?case
    by (auto intro: terminates.intros)
qed

lemma terminates_mark_guards_to_terminates_Normal:
  "s. Γmark_guards f cNormal s  ΓcNormal s"
proof (induct c)
  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 (Seq c1 c2)
  have "Γmark_guards f (Seq c1 c2)  Normal s" by fact
  then obtain
    termi_merge_c1: "Γmark_guards f c1  Normal s" and
    termi_merge_c2: "s'. Γmark_guards f c1,Normal s   s' 
                           Γmark_guards f c2  s'"
    by (auto elim: terminates_Normal_elim_cases)
  from termi_merge_c1 Seq.hyps
  have "Γc1  Normal s" by iprover
  moreover
  {
    fix s'
    assume exec_c1: "Γc1,Normal s   s'"
    have "Γ c2  s'"
    proof (cases "isFault s'")
      case True
      thus ?thesis by (auto elim: isFaultE)
    next
      case False
      from exec_to_exec_mark_guards [OF exec_c1 False]
      have "Γmark_guards f c1,Normal s   s'" .
      from termi_merge_c2 [rule_format, OF this] Seq.hyps
      show ?thesis
        by (cases s') (auto)
    qed
  }
  ultimately show ?case by (auto intro: terminates.intros)
next
  case Cond thus ?case
    by (fastforce intro: terminates.intros elim: terminates_Normal_elim_cases)
next
  case (While b c)
  {
    fix u c'
    assume termi_c': "Γc'  Normal u"
    assume c': "c' = mark_guards f (While b c)"
    have "ΓWhile b c  Normal u"
      using termi_c' c'
    proof (induct)
      case (WhileTrue s b' c')
      have s_in_b: "s  b" using WhileTrue by simp
      have "Γmark_guards f c  Normal s"
        using WhileTrue by (auto elim: terminates_Normal_elim_cases)
      with While.hyps have "Γc  Normal s"
        by auto
      moreover
      have hyp_w: "w. Γmark_guards f c,Normal s   w  ΓWhile b c  w"
        using WhileTrue by simp
      hence "w. Γc,Normal s   w  ΓWhile b c  w"
        apply -
        apply (rule allI)
        apply (case_tac "w")
        apply (auto dest: exec_to_exec_mark_guards)
        done
      ultimately show ?case
        using s_in_b
        by (auto intro: terminates.intros)
    next
      case WhileFalse thus ?case by (auto intro: terminates.intros)
    qed auto
  }
  with While show ?case by simp
next
  case Call thus ?case
    by (fastforce intro: terminates.intros )
next
  case DynCom thus ?case
    by (fastforce intro: terminates.intros elim: terminates_Normal_elim_cases)
next
  case (Guard f g c)
  thus ?case by (fastforce intro: terminates.intros elim: terminates_Normal_elim_cases)
next
  case Throw thus ?case
    by (fastforce intro: terminates.intros )
next
  case (Catch c1 c2)
  have "Γmark_guards f (Catch c1 c2)  Normal s" by fact
  then obtain
    termi_merge_c1: "Γmark_guards f c1  Normal s" and
    termi_merge_c2: "s'. Γmark_guards f c1,Normal s   Abrupt s' 
                           Γmark_guards f c2  Normal s'"
    by (auto elim: terminates_Normal_elim_cases)
  from termi_merge_c1 Catch.hyps
  have "Γc1  Normal s" by iprover
  moreover
  {
    fix s'
    assume exec_c1: "Γc1,Normal s   Abrupt s'"
    have "Γ c2  Normal s'"
    proof -
      from exec_to_exec_mark_guards [OF exec_c1]
      have "Γmark_guards f c1,Normal s   Abrupt s'" by simp
      from termi_merge_c2 [rule_format, OF this] Catch.hyps
      show ?thesis
        by iprover
    qed
  }
  ultimately show ?case by (auto intro: terminates.intros)
qed

lemma terminates_mark_guards_to_terminates:
  "Γmark_guards f cs  Γc s"
  by (cases s) (auto intro: terminates_mark_guards_to_terminates_Normal)


(* ************************************************************************* *)
subsection ‹Lemmas about @{const "merge_guards"}
(* ************************************************************************ *)

lemma terminates_to_terminates_merge_guards:
  assumes termi: "Γcs"
  shows "Γmerge_guards cs"
using termi
proof (induct)
  case (Guard s g c f)
  have s_in_g: "s  g" by fact
  have termi_merge_c: "Γmerge_guards c  Normal s" by fact
  show ?case
  proof (cases "f' g' c'. merge_guards c = Guard f' g' c'")
    case False
    hence "merge_guards (Guard f g c) = Guard f g (merge_guards c)"
      by (cases "merge_guards c") (auto simp add: Let_def)
    with s_in_g termi_merge_c show ?thesis
      by (auto intro: terminates.intros)
  next
    case True
    then obtain f' g' c' where
      mc: "merge_guards c = Guard f' g' c'"
      by blast
    show ?thesis
    proof (cases "f=f'")
      case False
      with mc have "merge_guards (Guard f g c) = Guard f g (merge_guards c)"
        by (simp add: Let_def)
      with s_in_g termi_merge_c show ?thesis
        by (auto intro: terminates.intros)
    next
      case True
      with mc have "merge_guards (Guard f g c) = Guard f (g  g') c'"
        by simp
      with s_in_g mc True termi_merge_c
      show ?thesis
        by (cases "s  g'")
           (auto intro: terminates.intros elim: terminates_Normal_elim_cases)
    qed
  qed
next
  case (GuardFault s g f c)
  have "s  g" by fact
  thus ?case
    by (cases "merge_guards c")
       (auto intro: terminates.intros split: if_split_asm simp add: Let_def)
qed (fastforce intro: terminates.intros dest: exec_merge_guards_to_exec)+

lemma terminates_merge_guards_to_terminates_Normal:
  shows "s. Γmerge_guards cNormal s  ΓcNormal s"
proof (induct c)
  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 (Seq c1 c2)
  have "Γmerge_guards (Seq c1 c2)  Normal s" by fact
  then obtain
    termi_merge_c1: "Γmerge_guards c1  Normal s" and
    termi_merge_c2: "s'. Γmerge_guards c1,Normal s   s' 
                           Γmerge_guards c2  s'"
    by (auto elim: terminates_Normal_elim_cases)
  from termi_merge_c1 Seq.hyps
  have "Γc1  Normal s" by iprover
  moreover
  {
    fix s'
    assume exec_c1: "Γc1,Normal s   s'"
    have "Γ c2  s'"
    proof -
      from exec_to_exec_merge_guards [OF exec_c1]
      have "Γmerge_guards c1,Normal s   s'" .
      from termi_merge_c2 [rule_format, OF this] Seq.hyps
      show ?thesis
        by (cases s') (auto)
    qed
  }
  ultimately show ?case by (auto intro: terminates.intros)
next
  case Cond thus ?case
    by (fastforce intro: terminates.intros elim: terminates_Normal_elim_cases)
next
  case (While b c)
  {
    fix u c'
    assume termi_c': "Γc'  Normal u"
    assume c': "c' = merge_guards (While b c)"
    have "ΓWhile b c  Normal u"
      using termi_c' c'
    proof (induct)
      case (WhileTrue s b' c')
      have s_in_b: "s  b" using WhileTrue by simp
      have "Γmerge_guards c  Normal s"
        using WhileTrue by (auto elim: terminates_Normal_elim_cases)
      with While.hyps have "Γc  Normal s"
        by auto
      moreover
      have hyp_w: "w. Γmerge_guards c,Normal s   w  ΓWhile b c  w"
        using WhileTrue by simp
      hence "w. Γc,Normal s   w  ΓWhile b c  w"
        by (simp add: exec_iff_exec_merge_guards [symmetric])
      ultimately show ?case
        using s_in_b
        by (auto intro: terminates.intros)
    next
      case WhileFalse thus ?case by (auto intro: terminates.intros)
    qed auto
  }
  with While show ?case by simp
next
  case Call thus ?case
    by (fastforce intro: terminates.intros )
next
  case DynCom thus ?case
    by (fastforce intro: terminates.intros elim: terminates_Normal_elim_cases)
next
  case (Guard f g c)
  have termi_merge: "Γmerge_guards (Guard f g c)  Normal s" by fact
  show ?case
  proof (cases "f' g' c'. merge_guards c = Guard f' g' c'")
    case False
    hence m: "merge_guards (Guard f g c) = Guard f g (merge_guards c)"
      by (cases "merge_guards c") (auto simp add: Let_def)
    from termi_merge Guard.hyps show ?thesis
      by (simp only: m)
         (fastforce intro: terminates.intros elim: terminates_Normal_elim_cases)
  next
    case True
    then obtain f' g' c' where
      mc: "merge_guards c = Guard f' g' c'"
      by blast
    show ?thesis
    proof (cases "f=f'")
      case False
      with mc have m: "merge_guards (Guard f g c) = Guard f g (merge_guards c)"
        by (simp add: Let_def)
      from termi_merge Guard.hyps show ?thesis
      by (simp only: m)
         (fastforce intro: terminates.intros elim: terminates_Normal_elim_cases)
    next
      case True
      with mc have m: "merge_guards (Guard f g c) = Guard f (g  g') c'"
        by simp
      from termi_merge Guard.hyps
      show ?thesis
        by (simp only: m mc)
           (auto intro: terminates.intros elim: terminates_Normal_elim_cases)
    qed
  qed
next
  case Throw thus ?case
    by (fastforce intro: terminates.intros )
next
  case (Catch c1 c2)
  have "Γmerge_guards (Catch c1 c2)  Normal s" by fact
  then obtain
    termi_merge_c1: "Γmerge_guards c1  Normal s" and
    termi_merge_c2: "s'. Γmerge_guards c1,Normal s   Abrupt s' 
                           Γmerge_guards c2  Normal s'"
    by (auto elim: terminates_Normal_elim_cases)
  from termi_merge_c1 Catch.hyps
  have "Γc1  Normal s" by iprover
  moreover
  {
    fix s'
    assume exec_c1: "Γc1,Normal s   Abrupt s'"
    have "Γ c2  Normal s'"
    proof -
      from exec_to_exec_merge_guards [OF exec_c1]
      have "Γmerge_guards c1,Normal s   Abrupt s'" .
      from termi_merge_c2 [rule_format, OF this] Catch.hyps
      show ?thesis
        by iprover
    qed
  }
  ultimately show ?case by (auto intro: terminates.intros)
qed

lemma terminates_merge_guards_to_terminates:
   "Γmerge_guards c s  Γc s"
by (cases s) (auto intro: terminates_merge_guards_to_terminates_Normal)

theorem terminates_iff_terminates_merge_guards:
  "Γc s = Γmerge_guards c s"
  by (iprover intro: terminates_to_terminates_merge_guards
    terminates_merge_guards_to_terminates)

(* ************************************************************************* *)
subsection ‹Lemmas about @{term "c1 g c2"}
(* ************************************************************************ *)

lemma terminates_fewer_guards_Normal:
  shows "c s. Γc'Normal s; c g c'; Γc',Normal s  ⇒∉Fault ` UNIV
               ΓcNormal s"
proof (induct c')
  case Skip thus ?case by (auto intro: terminates.intros dest: subseteq_guardsD)
next
  case Basic thus ?case by (auto intro: terminates.intros dest: subseteq_guardsD)
next
  case Spec thus ?case by (auto intro: terminates.intros dest: subseteq_guardsD)
next
  case (Seq c1' c2')
  have termi: "ΓSeq c1' c2'  Normal s" by fact
  then obtain
    termi_c1': "Γc1' Normal s" and
    termi_c2': "s'. Γc1',Normal s   s'  Γc2' s'"
    by (auto elim: terminates_Normal_elim_cases)
  have noFault: "ΓSeq c1' c2',Normal s  ⇒∉Fault ` UNIV" by fact
  hence noFault_c1': "Γc1',Normal s  ⇒∉Fault ` UNIV"
    by (auto intro: exec.intros simp add: final_notin_def)
  have "c g Seq c1' c2'" by fact
  from subseteq_guards_Seq [OF this] obtain c1 c2 where
    c: "c = Seq c1 c2" and
    c1_c1': "c1 g c1'" and
    c2_c2': "c2 g c2'"
    by blast
  from termi_c1' c1_c1' noFault_c1'
  have "Γc1 Normal s"
    by (rule Seq.hyps)
  moreover
  {
    fix t
    assume exec_c1: "Γc1,Normal s   t"
    have "Γc2 t"
    proof -
      from exec_to_exec_subseteq_guards [OF c1_c1' exec_c1] obtain t' where
        exec_c1': "Γc1',Normal s   t'" and
        t_Fault: "isFault t  isFault t'" and
        t'_noFault: "¬ isFault t'  t' = t"
        by blast
      show ?thesis
      proof (cases "isFault t'")
        case True
        with exec_c1' noFault_c1'
        have False
          by (fastforce elim: isFaultE dest: Fault_end simp add: final_notin_def)
        thus ?thesis ..
      next
        case False
        with t'_noFault have t': "t'=t" by simp
        with termi_c2' exec_c1'
        have termi_c2': "Γc2' t"
          by auto
        show ?thesis
        proof (cases t)
          case Fault thus ?thesis by auto
        next
          case Abrupt thus ?thesis by auto
        next
          case Stuck thus ?thesis by auto
        next
          case (Normal u)
          with noFault exec_c1' t'
          have "Γc2',Normal u  ⇒∉Fault ` UNIV"
            by (auto intro: exec.intros simp add: final_notin_def)
          from termi_c2' [simplified Normal] c2_c2' this
          have "Γc2  Normal u"
            by (rule Seq.hyps)
          with Normal exec_c1
          show ?thesis by simp
        qed
      qed
    qed
  }
  ultimately show ?case using c by (auto intro: terminates.intros)
next
  case (Cond b c1' c2')
  have noFault: "ΓCond b c1' c2',Normal s  ⇒∉Fault ` UNIV" by fact
  have termi: "ΓCond b c1' c2'  Normal s" by fact
  have "c g Cond b c1' c2'" by fact
  from subseteq_guards_Cond [OF this] obtain c1 c2 where
    c: "c = Cond b c1 c2" and
    c1_c1': "c1 g c1'" and
    c2_c2': "c2 g c2'"
    by blast
  thus ?case
  proof (cases "s  b")
    case True
    with termi have termi_c1': "Γc1'  Normal s"
      by (auto elim: terminates_Normal_elim_cases)
    from True noFault have "Γc1',Normal s  ⇒∉Fault ` UNIV"
      by (auto intro: exec.intros simp add: final_notin_def)
    from termi_c1' c1_c1' this
    have "Γc1  Normal s"
      by (rule Cond.hyps)
    with True c show ?thesis
      by (auto intro: terminates.intros)
  next
    case False
    with termi have termi_c2': "Γc2'  Normal s"
      by (auto elim: terminates_Normal_elim_cases)
    from False noFault have "Γc2',Normal s  ⇒∉Fault ` UNIV"
      by (auto intro: exec.intros simp add: final_notin_def)
    from termi_c2' c2_c2' this
    have "Γc2  Normal s"
      by (rule Cond.hyps)
    with False c show ?thesis
      by (auto intro: terminates.intros)
  qed
next
  case (While b c')
  have noFault: "ΓWhile b c',Normal s  ⇒∉Fault ` UNIV" by fact
  have termi: "ΓWhile b c'  Normal s" by fact
  have "c g While b c'" by fact
  from subseteq_guards_While [OF this]
  obtain c'' where
    c: "c = While b c''" and
    c''_c': "c'' g c'"
    by blast
  {
    fix d u
    assume termi: "Γd  u"
    assume d: "d = While b c'"
    assume noFault: "ΓWhile b c',u  ⇒∉Fault ` UNIV"
    have "ΓWhile b c''  u"
    using termi d noFault
    proof (induct)
      case (WhileTrue u b' c''')
      have u_in_b: "u  b" using WhileTrue by simp
      have termi_c': "Γc'  Normal u" using WhileTrue by simp
      have noFault: "ΓWhile b c',Normal u  ⇒∉Fault ` UNIV" using WhileTrue by simp
      hence noFault_c': "Γc',Normal u  ⇒∉Fault ` UNIV" using u_in_b
        by (auto intro: exec.intros simp add: final_notin_def)
      from While.hyps [OF termi_c' c''_c' this]
      have "Γc''  Normal u".
      moreover
      from WhileTrue
      have hyp_w: "s'. Γc',Normal u   s'   ΓWhile b c',s'  ⇒∉Fault ` UNIV
                         ΓWhile b c''  s'"
        by simp
      {
        fix v
        assume exec_c'': "Γc'',Normal u   v"
        have "ΓWhile b c''  v"
        proof -
          from exec_to_exec_subseteq_guards [OF c''_c' exec_c''] obtain v' where
            exec_c': "Γc',Normal u   v'" and
            v_Fault: "isFault v  isFault v'" and
            v'_noFault: "¬ isFault v'  v' = v"
            by auto
          show ?thesis
          proof (cases "isFault v'")
            case True
            with exec_c' noFault u_in_b
            have False
              by (fastforce
                   simp add: final_notin_def intro: exec.intros elim: isFaultE)
            thus ?thesis ..
          next
            case False
            with v'_noFault have v': "v'=v"
              by simp
            with noFault exec_c' u_in_b
            have "ΓWhile b c',v  ⇒∉Fault ` UNIV"
              by (fastforce simp add: final_notin_def intro: exec.intros)
            from hyp_w [rule_format, OF exec_c' [simplified v'] this]
            show "ΓWhile b c''  v" .
          qed
        qed
      }
      ultimately
      show ?case using u_in_b
        by (auto intro: terminates.intros)
    next
      case WhileFalse thus ?case by (auto intro: terminates.intros)
    qed auto
  }
  with c noFault termi show ?case
    by auto
next
  case Call thus ?case by (auto intro: terminates.intros dest: subseteq_guardsD)
next
  case (DynCom C')
  have termi: "ΓDynCom C'  Normal s" by fact
  hence termi_C': "ΓC' s  Normal s"
    by cases
  have noFault: "ΓDynCom C',Normal s  ⇒∉Fault ` UNIV" by fact
  hence noFault_C': "ΓC' s,Normal s  ⇒∉Fault ` UNIV"
    by (auto intro: exec.intros simp add: final_notin_def)
  have "c g DynCom C'" by fact
  from subseteq_guards_DynCom [OF this] obtain C where
    c: "c = DynCom C" and
    C_C': "s. C s g C' s"
    by blast
  from DynCom.hyps termi_C' C_C' [rule_format] noFault_C'
  have "ΓC s  Normal s"
    by fast
  with c show ?case
    by (auto intro: terminates.intros)
next
  case (Guard f' g' c')
  have noFault: "ΓGuard f' g' c',Normal s  ⇒∉Fault ` UNIV" by fact
  have termi: "ΓGuard f' g' c'  Normal s" by fact
  have "c g Guard f' g' c'" by fact
  hence c_cases: "(c g c')  (c''. c = Guard f' g' c''  (c'' g c'))"
    by (rule subseteq_guards_Guard)
  thus ?case
  proof (cases "s  g'")
    case True
    note s_in_g' = this
    with noFault have noFault_c': "Γc',Normal s  ⇒∉Fault ` UNIV"
      by (auto simp add: final_notin_def intro: exec.intros)
    from termi s_in_g' have termi_c': "Γc'  Normal s"
      by cases auto
    from c_cases show ?thesis
    proof
      assume "c g c'"
      from termi_c' this noFault_c'
      show "Γc  Normal s"
        by (rule Guard.hyps)
    next
      assume "c''. c = Guard f' g' c''  (c'' g c')"
      then obtain c'' where
        c: "c = Guard f' g' c''" and c''_c': "c'' g c'"
        by blast
      from termi_c' c''_c' noFault_c'
      have "Γc''  Normal s"
        by (rule Guard.hyps)
      with s_in_g' c
      show ?thesis
        by (auto intro: terminates.intros)
    qed
  next
    case False
    with noFault have False
      by (auto intro: exec.intros simp add: final_notin_def)
    thus ?thesis ..
  qed
next
  case Throw thus ?case by (auto intro: terminates.intros dest: subseteq_guardsD)
next
  case (Catch c1' c2')
  have termi: "ΓCatch c1' c2'  Normal s" by fact
  then obtain
    termi_c1': "Γc1' Normal s" and
    termi_c2': "s'. Γc1',Normal s   Abrupt s'  Γc2' Normal s'"
    by (auto elim: terminates_Normal_elim_cases)
  have noFault: "ΓCatch c1' c2',Normal s  ⇒∉Fault ` UNIV" by fact
  hence noFault_c1': "Γc1',Normal s  ⇒∉Fault ` UNIV"
    by (fastforce intro: exec.intros simp add: final_notin_def)
  have "c g Catch c1' c2'"  by fact
  from subseteq_guards_Catch [OF this] obtain c1 c2 where
    c: "c = Catch c1 c2" and
    c1_c1': "c1 g c1'" and
    c2_c2': "c2 g c2'"
    by blast
  from termi_c1' c1_c1' noFault_c1'
  have "Γc1 Normal s"
    by (rule Catch.hyps)
  moreover
  {
    fix t
    assume exec_c1: "Γc1,Normal s   Abrupt t"
    have "Γc2 Normal t"
    proof -
      from exec_to_exec_subseteq_guards [OF c1_c1' exec_c1] obtain t' where
        exec_c1': "Γc1',Normal s   t'" and
        t'_noFault: "¬ isFault t'  t' = Abrupt t"
        by blast
      show ?thesis
      proof (cases "isFault t'")
        case True
        with exec_c1' noFault_c1'
        have False
          by (fastforce elim: isFaultE dest: Fault_end simp add: final_notin_def)
        thus ?thesis ..
      next
        case False
        with t'_noFault have t': "t'=Abrupt t" by simp
        with termi_c2' exec_c1'
        have termi_c2': "Γc2' Normal t"
          by auto
        with noFault exec_c1' t'
        have "Γc2',Normal t  ⇒∉Fault ` UNIV"
          by (auto intro: exec.intros simp add: final_notin_def)
        from termi_c2' c2_c2' this
        show "Γc2  Normal t"
          by (rule Catch.hyps)
      qed
    qed
  }
  ultimately show ?case using c by (auto intro: terminates.intros)
qed

theorem terminates_fewer_guards:
  shows "Γc's; c g c'; Γc',s  ⇒∉Fault ` UNIV
          Γcs"
  by (cases s) (auto intro: terminates_fewer_guards_Normal)

lemma terminates_noFault_strip_guards:
  assumes termi: "ΓcNormal s"
  shows "Γc,Normal s  ⇒∉Fault ` F  Γstrip_guards F cNormal s"
using termi
proof (induct)
  case Skip thus ?case by (auto intro: terminates.intros)
next
  case Basic thus ?case by (auto intro: terminates.intros)
next
  case Spec thus ?case by (auto intro: terminates.intros)
next
  case (Guard s g c f)
  have s_in_g: "s  g" by fact
  have "Γc  Normal s" by fact
  have "ΓGuard f g c,Normal s  ⇒∉Fault ` F" by fact
  with s_in_g have "Γc,Normal s  ⇒∉Fault ` F"
    by (fastforce simp add: final_notin_def intro: exec.intros)
  with Guard.hyps have "Γstrip_guards F c  Normal s" by simp
  with s_in_g show ?case
    by (auto intro: terminates.intros)
next
  case GuardFault thus ?case
    by (auto intro: terminates.intros exec.intros simp add: final_notin_def )
next
  case Fault thus ?case by (auto intro: terminates.intros)
next
  case (Seq c1 s c2)
  have noFault_Seq: "ΓSeq c1 c2,Normal s  ⇒∉Fault ` F" by fact
  hence noFault_c1: "Γc1,Normal s  ⇒∉Fault ` F"
    by (auto simp add: final_notin_def intro: exec.intros)
  with Seq.hyps have "Γstrip_guards F c1  Normal s" by simp
  moreover
  {
    fix s'
    assume exec_strip_guards_c1: "Γstrip_guards F c1,Normal s   s'"
    have "Γstrip_guards F c2  s'"
    proof (cases "isFault s'")
      case True
      thus ?thesis by (auto elim: isFaultE intro: terminates.intros)
    next
      case False
      with exec_strip_guards_to_exec [OF exec_strip_guards_c1] noFault_c1
      have *: "Γc1,Normal s   s'"
        by (auto simp add: final_notin_def elim!: isFaultE)
      with noFault_Seq have "Γc2,s'  ⇒∉Fault ` F"
        by (auto simp add: final_notin_def intro: exec.intros)
      with * show ?thesis
        using Seq.hyps by simp
    qed
  }
  ultimately show ?case
    by (auto intro: terminates.intros)
next
  case CondTrue thus ?case
    by (fastforce intro: terminates.intros exec.intros simp add: final_notin_def )
next
  case CondFalse thus ?case
    by (fastforce intro: terminates.intros exec.intros simp add: final_notin_def )
next
  case (WhileTrue s b c)
  have s_in_b: "s  b" by fact
  have noFault_while: "ΓWhile b c,Normal s  ⇒∉Fault ` F" by fact
  with s_in_b have noFault_c: "Γc,Normal s  ⇒∉Fault ` F"
    by (auto simp add: final_notin_def intro: exec.intros)
  with WhileTrue.hyps have "Γstrip_guards F c  Normal s" by simp
  moreover
  {
    fix s'
    assume exec_strip_guards_c: "Γstrip_guards F c,Normal s   s'"
    have "Γstrip_guards F (While b c)  s'"
    proof (cases "isFault s'")
      case True
      thus ?thesis by (auto elim: isFaultE intro: terminates.intros)
    next
      case False
      with exec_strip_guards_to_exec [OF exec_strip_guards_c] noFault_c
      have *: "Γc,Normal s   s'"
        by (auto simp add: final_notin_def elim!: isFaultE)
      with s_in_b noFault_while have "ΓWhile b c,s'  ⇒∉Fault ` F"
        by (auto simp add: final_notin_def intro: exec.intros)
      with * show ?thesis
        using WhileTrue.hyps by simp
    qed
  }
  ultimately show ?case
    using WhileTrue.hyps by (auto intro: terminates.intros)
next
  case WhileFalse thus ?case by (auto intro: terminates.intros)
next
  case Call thus ?case by (auto intro: terminates.intros)
next
  case CallUndefined thus ?case by (auto intro: terminates.intros)
next
  case Stuck thus ?case by (auto intro: terminates.intros)
next
  case DynCom thus ?case
    by (auto intro: terminates.intros exec.intros simp add: final_notin_def )
next
  case Throw thus ?case by (auto intro: terminates.intros)
next
  case Abrupt thus ?case by (auto intro: terminates.intros)
next
  case (Catch c1 s c2)
  have noFault_Catch: "ΓCatch c1 c2,Normal s  ⇒∉Fault ` F" by fact
  hence noFault_c1: "Γc1,Normal s  ⇒∉Fault ` F"
    by (fastforce simp add: final_notin_def intro: exec.intros)
  with Catch.hyps have "Γstrip_guards F c1  Normal s" by simp
  moreover
  {
    fix s'
    assume exec_strip_guards_c1: "Γstrip_guards F c1,Normal s   Abrupt s'"
    have "Γstrip_guards F c2  Normal s'"
    proof -
      from exec_strip_guards_to_exec [OF exec_strip_guards_c1] noFault_c1
      have *: "Γc1,Normal s   Abrupt s'"
        by (auto simp add: final_notin_def elim!: isFaultE)
      with noFault_Catch have "Γc2,Normal s'  ⇒∉Fault ` F"
        by (auto simp add: final_notin_def intro: exec.intros)
      with * show ?thesis
        using Catch.hyps by simp
    qed
  }
  ultimately show ?case
    using Catch.hyps by (auto intro: terminates.intros)
qed

(* ************************************************************************* *)
subsection ‹Lemmas about @{const "strip_guards"}
(* ************************************************************************* *)

lemma terminates_noFault_strip:
  assumes termi: "ΓcNormal s"
  shows "Γc,Normal s  ⇒∉Fault ` F  strip F ΓcNormal s"
using termi
proof (induct)
  case Skip thus ?case by (auto intro: terminates.intros)
next
  case Basic thus ?case by (auto intro: terminates.intros)
next
  case Spec thus ?case by (auto intro: terminates.intros)
next
  case (Guard s g c f)
  have s_in_g: "s  g" by fact
  have "ΓGuard f g c,Normal s  ⇒∉Fault ` F" by fact
  with s_in_g have "Γc,Normal s  ⇒∉Fault ` F"
    by (fastforce simp add: final_notin_def intro: exec.intros)
  then have "strip F Γc  Normal s" by (simp add: Guard.hyps)
  with s_in_g show ?case
    by (auto intro: terminates.intros simp del: strip_simp)
next
  case GuardFault thus ?case
    by (auto intro: terminates.intros exec.intros simp add: final_notin_def )
next
  case Fault thus ?case by (auto intro: terminates.intros)
next
  case (Seq c1 s c2)
  have noFault_Seq: "ΓSeq c1 c2,Normal s  ⇒∉Fault ` F" by fact
  hence noFault_c1: "Γc1,Normal s  ⇒∉Fault ` F"
    by (auto simp add: final_notin_def intro: exec.intros)
  then have "strip F Γc1  Normal s" by (simp add: Seq.hyps)
  moreover
  {
    fix s'
    assume exec_strip_c1: "strip F Γc1,Normal s   s'"
    have "strip F Γc2  s'"
    proof (cases "isFault s'")
      case True
      thus ?thesis by (auto elim: isFaultE intro: terminates.intros)
    next
      case False
      with exec_strip_to_exec [OF exec_strip_c1] noFault_c1
      have *: "Γc1,Normal s   s'"
        by (auto simp add: final_notin_def elim!: isFaultE)
      with noFault_Seq have "Γc2,s'  ⇒∉Fault ` F"
        by (auto simp add: final_notin_def intro: exec.intros)
      with * show ?thesis
        using Seq.hyps by (simp del: strip_simp)
    qed
  }
  ultimately show ?case
    by (fastforce intro: terminates.intros)
next
  case CondTrue thus ?case
    by (fastforce intro: terminates.intros exec.intros simp add: final_notin_def )
next
  case CondFalse thus ?case
    by (fastforce intro: terminates.intros exec.intros simp add: final_notin_def )
next
  case (WhileTrue s b c)
  have s_in_b: "s  b" by fact
  have noFault_while: "ΓWhile b c,Normal s  ⇒∉Fault ` F" by fact
  with s_in_b have noFault_c: "Γc,Normal s  ⇒∉Fault ` F"
    by (auto simp add: final_notin_def intro: exec.intros)
  then have "strip F Γc  Normal s" by (simp add: WhileTrue.hyps)
  moreover
  {
    fix s'
    assume exec_strip_c: "strip F Γc,Normal s   s'"
    have "strip F ΓWhile b c  s'"
    proof (cases "isFault s'")
      case True
      thus ?thesis by (auto elim: isFaultE intro: terminates.intros)
    next
      case False
      with exec_strip_to_exec [OF exec_strip_c] noFault_c
      have *: "Γc,Normal s   s'"
        by (auto simp add: final_notin_def elim!: isFaultE)
      with s_in_b noFault_while have "ΓWhile b c,s'  ⇒∉Fault ` F"
        by (auto simp add: final_notin_def intro: exec.intros)
      with * show ?thesis
        using WhileTrue.hyps by (simp del: strip_simp)
    qed
  }
  ultimately show ?case
    using WhileTrue.hyps by (auto intro: terminates.intros simp del: strip_simp)
next
  case WhileFalse thus ?case by (auto intro: terminates.intros)
next
  case (Call p bdy s)
  have bdy: "Γ p = Some bdy" by fact
  have "ΓCall p,Normal s  ⇒∉Fault ` F" by fact
  with bdy have bdy_noFault: "Γbdy,Normal s  ⇒∉Fault ` F"
    by (auto intro: exec.intros simp add: final_notin_def)
  then have strip_bdy_noFault: "strip F Γbdy,Normal s  ⇒∉Fault ` F"
    by (auto simp add: final_notin_def dest!: exec_strip_to_exec elim!: isFaultE)

  from bdy_noFault have "strip F Γbdy  Normal s" by (simp add: Call.hyps)
  from terminates_noFault_strip_guards [OF this strip_bdy_noFault]
  have "strip F Γstrip_guards F bdy  Normal s".
  with bdy show ?case
    by (fastforce intro: terminates.Call)
next
  case CallUndefined thus ?case by (auto intro: terminates.intros)
next
  case Stuck thus ?case by (auto intro: terminates.intros)
next
  case DynCom thus ?case
    by (auto intro: terminates.intros exec.intros simp add: final_notin_def )
next
  case Throw thus ?case by (auto intro: terminates.intros)
next
  case Abrupt thus ?case by (auto intro: terminates.intros)
next
  case (Catch c1 s c2)
  have noFault_Catch: "ΓCatch c1 c2,Normal s  ⇒∉Fault ` F" by fact
  hence noFault_c1: "Γc1,Normal s  ⇒∉Fault ` F"
    by (fastforce simp add: final_notin_def intro: exec.intros)
  then have "strip F Γc1  Normal s" by (simp add: Catch.hyps)
  moreover
  {
    fix s'
    assume exec_strip_c1: "strip F Γc1,Normal s   Abrupt s'"
    have "strip F Γc2  Normal s'"
    proof -
      from exec_strip_to_exec [OF exec_strip_c1] noFault_c1
      have *: "Γc1,Normal s   Abrupt s'"
        by (auto simp add: final_notin_def elim!: isFaultE)
      with * noFault_Catch have "Γc2,Normal s'  ⇒∉Fault ` F"
        by (auto simp add: final_notin_def intro: exec.intros)
      with * show ?thesis
        using Catch.hyps by (simp del: strip_simp)
    qed
  }
  ultimately show ?case
    using Catch.hyps by (auto intro: terminates.intros simp del: strip_simp)
qed


(* ************************************************************************* *)
subsection ‹Miscellaneous›
(* ************************************************************************* *)

lemma terminates_while_lemma:
  assumes termi: "Γwfk"
  shows "k b c. fk = Normal (f k); w=While b c;
                       i. Γc,Normal (f i)   Normal (f (Suc i))
          i. f i  b"
using termi
proof (induct)
  case WhileTrue thus ?case by blast
next
  case WhileFalse thus ?case by blast
qed simp_all

lemma terminates_while:
  "Γ(While b c)Normal (f k);
    i. Γc,Normal (f i)   Normal (f (Suc i))
          i. f i  b"
  by (blast intro: terminates_while_lemma)

lemma wf_terminates_while:
 "wf {(t,s). Γ(While b c)Normal s  sb 
             Γc,Normal s   Normal t}"
apply(subst wf_iff_no_infinite_down_chain)
apply(rule notI)
apply clarsimp
apply(insert terminates_while)
apply blast
done

lemma terminates_restrict_to_terminates:
  assumes terminates_res: "Γ|⇘M c  s"
  assumes not_Stuck: "Γ|⇘Mc,s  ⇒∉{Stuck}"
  shows "Γ c  s"
using terminates_res not_Stuck
proof (induct)
  case Skip show ?case by (rule terminates.Skip)
next
  case Basic show ?case by (rule terminates.Basic)
next
  case Spec show ?case by (rule terminates.Spec)
next
  case Guard thus ?case
    by (auto intro: terminates.Guard dest: notStuck_GuardD)
next
  case GuardFault thus ?case by (auto intro: terminates.GuardFault)
next
  case Fault show ?case by (rule terminates.Fault)
next
  case (Seq c1 s c2)
  have not_Stuck: "Γ|⇘MSeq c1 c2,Normal s  ⇒∉{Stuck}" by fact
  hence c1_notStuck: "Γ|⇘Mc1,Normal s  ⇒∉{Stuck}"
    by (rule notStuck_SeqD1)
  show "ΓSeq c1 c2  Normal s"
  proof (rule terminates.Seq,safe)
    from c1_notStuck
    show "Γc1  Normal s"
      by (rule Seq.hyps)
  next
    fix s'
    assume exec: "Γc1,Normal s   s'"
    show "Γc2  s'"
    proof -
      from exec_to_exec_restrict [OF exec] obtain t' where
        exec_res: "Γ|⇘Mc1,Normal s   t'" and
        t'_notStuck: "t'  Stuck  t' = s'"
        by blast
      show ?thesis
      proof (cases "t'=Stuck")
        case True
        with c1_notStuck exec_res have "False"
          by (auto simp add: final_notin_def)
        thus ?thesis ..
      next
        case False
        with t'_notStuck have t': "t'=s'" by simp
        with not_Stuck exec_res
        have "Γ|⇘Mc2,s'  ⇒∉{Stuck}"
          by (auto dest: notStuck_SeqD2)
        with exec_res t' Seq.hyps
        show ?thesis
          by auto
      qed
    qed
  qed
next
  case CondTrue thus ?case
    by (auto intro: terminates.CondTrue dest: notStuck_CondTrueD)
next
  case CondFalse thus ?case
    by (auto intro: terminates.CondFalse dest: notStuck_CondFalseD)
next
  case (WhileTrue s b c)
  have s: "s  b" by fact
  have not_Stuck: "Γ|⇘MWhile b c,Normal s  ⇒∉{Stuck}" by fact
  with WhileTrue have c_notStuck: "Γ|⇘Mc,Normal s  ⇒∉{Stuck}"
    by (iprover intro:  notStuck_WhileTrueD1)
  show ?case
  proof (rule terminates.WhileTrue [OF s],safe)
    from c_notStuck
    show "Γc  Normal s"
      by (rule WhileTrue.hyps)
  next
    fix s'
    assume exec: "Γc,Normal s   s'"
    show "ΓWhile b c  s'"
    proof -
      from exec_to_exec_restrict [OF exec] obtain t' where
        exec_res: "Γ|⇘Mc,Normal s   t'" and
        t'_notStuck: "t'  Stuck  t' = s'"
        by blast
      show ?thesis
      proof (cases "t'=Stuck")
        case True
        with c_notStuck exec_res have "False"
          by (auto simp add: final_notin_def)
        thus ?thesis ..
      next
        case False
        with t'_notStuck have t': "t'=s'" by simp
        with not_Stuck exec_res s
        have "Γ|⇘MWhile b c,s'  ⇒∉{Stuck}"
          by (auto dest: notStuck_WhileTrueD2)
        with exec_res t' WhileTrue.hyps
        show ?thesis
          by auto
      qed
    qed
  qed
next
  case WhileFalse then show ?case by (iprover intro: terminates.WhileFalse)
next
  case Call thus ?case
    by (auto intro: terminates.Call dest: notStuck_CallD restrict_SomeD)
next
  case CallUndefined
  thus ?case
    by (auto dest: notStuck_CallDefinedD)
next
  case Stuck show ?case by (rule terminates.Stuck)
next
  case DynCom
  thus ?case
    by (auto intro: terminates.DynCom dest: notStuck_DynComD)
next
  case Throw show ?case by (rule terminates.Throw)
next
  case Abrupt show ?case by (rule terminates.Abrupt)
next
  case (Catch c1 s c2)
  have not_Stuck: "Γ|⇘MCatch c1 c2,Normal s  ⇒∉{Stuck}" by fact
  hence c1_notStuck: "Γ|⇘Mc1,Normal s  ⇒∉{Stuck}"
    by (rule notStuck_CatchD1)
  show "ΓCatch c1 c2  Normal s"
  proof (rule terminates.Catch,safe)
    from c1_notStuck
    show "Γc1  Normal s"
      by (rule Catch.hyps)
  next
    fix s'
    assume exec: "Γc1,Normal s   Abrupt s'"
    show "Γc2  Normal s'"
    proof -
      from exec_to_exec_restrict [OF exec] obtain t' where
        exec_res: "Γ|⇘Mc1,Normal s   t'" and
        t'_notStuck: "t'  Stuck  t' = Abrupt s'"
        by blast
      show ?thesis
      proof (cases "t'=Stuck")
        case True
        with c1_notStuck exec_res have "False"
          by (auto simp add: final_notin_def)
        thus ?thesis ..
      next
        case False
        with t'_notStuck have t': "t'=Abrupt s'" by simp
        with not_Stuck exec_res
        have "Γ|⇘Mc2,Normal s'  ⇒∉{Stuck}"
          by (auto dest: notStuck_CatchD2)
        with exec_res t' Catch.hyps
        show ?thesis
          by auto
      qed
    qed
  qed
qed

end