Theory Execution

section ‹Execution›

text ‹
  \file{Execution} introduces a locale for executions within asynchronous systems.
›

theory Execution
imports AsynchronousSystem ListUtilities
begin

subsection ‹Execution locale definition›

text ‹
  A (finite) execution within a system is a list of configurations \isb{exec}
  accompanied by a list of messages \isb{trace} such that the first configuration
  is initial and every next state can be reached processing the messages
  in \isb{trace}.
›
locale execution =
  asynchronousSystem trans sends start    
for
  trans :: "'p  's  'v messageValue  's" and
  sends :: "'p  's  'v messageValue  ('p, 'v) message multiset" and
  start :: "'p  's"
+
fixes
  exec :: "('p, 'v, 's ) configuration list" and
  trace :: "('p, 'v) message list"
assumes 
  notEmpty: "length exec  1" and 
  length: "length exec - 1 = length trace" and
  base: "initial (hd exec)" and
  step: " i < length exec - 1 ; cfg1 = exec ! i ; cfg2 = exec ! (i + 1) 
       ((cfg1  trace ! i  cfg2)) "
begin

abbreviation execMsg ::
  "nat  ('p,'v) message"
where
  "execMsg n  (trace ! n)"

abbreviation execConf ::
  "nat  ('p, 'v, 's) configuration"
where
  "execConf n   (exec ! n)"

subsection ‹Enabledness and occurrence in the execution›

definition minimalEnabled ::
  "('p, 'v) message  bool"
where
  "minimalEnabled msg  ( p . isReceiverOf p msg) 
     (enabled (last exec) msg)
     ( n . n < length exec  enabled (execConf n) msg 
       ( n'  n . n' < length trace  msg  (execMsg n'))
     ( n' msg' . (( p . isReceiverOf p msg') 
       (enabled (last exec) msg') 
       n' < length trace 
       enabled (execConf n') msg' 
       ( n''  n' . n'' < length trace  msg'  
                      (execMsg n'')))  n'  n))"

definition firstOccurrence ::
  "('p, 'v) message  nat  bool"
where                    
  "firstOccurrence msg n  ( p . isReceiverOf p msg) 
     (enabled (last exec) msg)  n < (length exec)
     enabled (execConf n) msg 
     ( n'  n . n' < length trace  msg  (execMsg n'))
     ( n  0  (¬ enabled (execConf (n - 1)) msg 
       msg = execMsg (n - 1)))"

lemma FirstOccurrenceExists:
assumes
  "enabled (last exec) msg"
  "p. isReceiverOf p msg"
shows
  " n . firstOccurrence msg n"
proof-
  have "length exec - 1 < length exec 
     ( n'  (length exec - 1) . n' < length trace  trace ! n'  msg)"
    using length
    by (metis diff_diff_cancel leD notEmpty zero_less_diff 
      zero_less_one)
  hence NNotInTrace: " n < length exec . 
    ( n'n . n' < length trace  trace ! n'  msg)" by blast
  hence " n0 < length exec . 
    ( n'n0 . n' < length trace  trace ! n'  msg) 
    ((n0 = 0) 
       ¬ ( n'  (n0 - 1) . n' < length trace  trace ! n'  msg))" 
    using MinPredicate2[of "λx.(x < length exec 
       (n'x.(n'<length trace  trace ! n'  msg)))"]
    by auto
  hence " n0. n0 < length exec 
     ( n'n0 . n' < length trace  trace ! n'  msg) 
     ((n0 = 0) 
       ¬ ( n'  (n0 - 1) . n' < length trace  trace ! n'  msg))" 
    by simp
  from this obtain n0 where N0a: "n0 < length exec 
     ( n'n0 . n' < length trace  trace ! n'  msg) 
     ((n0 = 0) 
       ¬ ( n'  (n0 - 1) . n' < length trace  trace ! n'  msg))" 
    by metis
  hence N0: "n0 < length exec" 
    "( n'n0 . n' < length trace  trace ! n'  msg)"
    "((n0 = 0) 
       ¬ ( n'  (n0 - 1) . n' < length trace  trace ! n'  msg))" 
    using N0a by auto
  have N0': "n0 = 0  trace ! (n0 - 1) = msg"
  proof(cases "n0 = 0", auto)
    assume N0NotZero: "n0 > 0"
    hence "¬ ( n'  (n0 - 1) . n' < length trace  trace ! n'  msg)" 
      using N0(3) by blast
    moreover have "n0 - 1 < length trace"
      using N0(1) length N0NotZero 
      by (metis calculation le_less_trans)
    ultimately show "execMsg (n0 - Suc 0) = msg" using N0(2) 
      by (metis One_nat_def Suc_diff_Suc diff_Suc_eq_diff_pred 
         diff_diff_cancel diff_is_0_eq leI nat_le_linear)
  qed
  have " n1 < length exec . 
    ( n'n1 . n' < length trace  trace ! n'  msg) 
     enabled (exec ! n1) msg 
     (n1 = 0  ¬ enabled (exec ! (n1 - 1)) msg  trace ! (n1 - 1) = msg)"
  proof(cases "enabled (exec ! n0) msg")
    assume "enabled (execConf n0) msg"
    hence "n0 < length exec" 
      "( n'n0 . n' < length trace  trace ! n'  msg)" 
      "enabled (exec ! n0) msg 
      (n0 = 0  ¬ enabled (exec ! (n0 - 1)) msg  trace ! (n0 - 1) = msg)"
    using N0 N0' by auto
    thus "n1<length exec.
       (n'n1. n' < length trace  execMsg n'  msg) 
        enabled (execConf n1) msg 
        (n1 = 0  ¬ enabled (execConf (n1 - 1)) msg 
          execMsg (n1 - 1) = msg)"
      by metis
  next
    assume NotEnabled: "¬ enabled (execConf n0) msg"
    have "last exec = exec ! (length exec - 1)" using last_conv_nth notEmpty 
      by (metis NNotInTrace length_0_conv less_nat_zero_code)
    hence EnabledInLast: "enabled (exec ! (length exec - 1)) msg" 
      using assms(1) by simp
    hence "n0  length exec - 1" using NotEnabled by auto
    hence N0Small: "n0 < length exec - 1" using N0(1) by simp
    hence " k < length exec - 1 - n0  . ¬ enabled (execConf (n0 + k)) msg 
       enabled (execConf (n0 + k + 1)) msg"
      using NatPredicateTippingPoint[of "length exec - 1 - n0" 
        "λx.¬(enabled (exec ! (n0 + x)) msg)"]
        assms(1) NotEnabled EnabledInLast by simp
    then obtain k where K: " k < length exec - 1 - n0" 
      "¬ enabled (execConf (n0 + k)) msg" 
      "enabled (execConf (n0 + k + 1)) msg" by blast
    define n1 where "n1 = k + n0 + 1"
    hence N1: "n1  n0" "¬ enabled (execConf (n1 - 1)) msg" 
      "enabled (execConf n1) msg" "n1 < length exec"
      unfolding n1_def using K
      by (auto simp add: add.commute)
    have "n'n1. n' < length trace  execMsg n'  msg" 
      using N1(1) N0(2) by (metis order_trans)
    thus "n1<length exec.
        (n'n1. n' < length trace  execMsg n'  msg) 
         enabled (execConf n1) msg 
         (n1 = 0  ¬ enabled (execConf (n1 - 1)) msg 
           execMsg (n1 - 1) = msg)" 
    using N1 by auto
  qed
  then obtain n1 where N1: "n1 < length exec" 
    " n'n1 . n' < length trace  trace ! n'  msg"
    "enabled (exec ! n1) msg"
    "n1 = 0  ¬ enabled (exec ! (n1 - 1)) msg  trace ! (n1 - 1) = msg" 
    by metis
  hence "firstOccurrence msg n1" using assms unfolding firstOccurrence_def 
    by auto
  thus "n. firstOccurrence msg n" by blast
qed

lemma ReachableInExecution:
assumes
  "i < length exec"
  "j  i"
shows
  "reachable (execConf j) (execConf i)"
using assms proof(induct i, auto)
  show "reachable (execConf 0) (execConf 0)" 
    using reachable.simps by blast
next
  fix ia
  assume 
    IH: "(j  ia  reachable (execConf j) (execConf ia))" 
    "Suc ia < length exec" 
    "j  Suc ia"  
    "i < length exec" 
    "j  i"
  show "reachable (execConf j) (execConf (Suc ia))" 
  proof(cases "j = Suc ia", auto)
    show "reachable (execConf (Suc ia)) (execConf (Suc ia))" 
      using reachable.simps by metis
  next
    assume "j  Suc ia"
    hence "j  ia" using IH(3) by simp
    hence "reachable (execConf j) (execConf ia)" using IH(1) by simp
    moreover have "reachable (execConf ia) (execConf (Suc ia))" 
      using reachable.simps
      by (metis IH(2) Suc_eq_plus1 less_diff_conv local.step)
    ultimately show "reachable (execConf j) (execConf (Suc ia))" 
      using ReachableTrans by blast
  qed
qed

lemma LastPoint:
fixes
  msg::"('p, 'v) message"
assumes
  "enabled (last exec) msg"
obtains n where
  "n < length exec"
  "enabled (execConf n) msg"
  " n'  n .
    n' < length trace  msg  (execMsg n')"
  " n0 . 
      n0 < length exec 
     enabled (execConf n0) msg 
     ( n'  n0 .
        n' < length trace  msg  (execMsg n'))
     n0  n"
proof (cases ?thesis, simp)
  case False
  define len where "len = length exec - 1"
  have
    "len < length exec"
    "enabled (execConf len) msg" 
    " n'  len . n' < length trace  msg  (execMsg n')"
    using assms notEmpty length unfolding len_def
    by (auto, metis One_nat_def last_conv_nth list.size(3) not_one_le_zero)
  hence " n . n < length exec  enabled (execConf n) msg 
     ( n'  n . n' < length trace  msg  (execMsg n'))"
    by blast
  from MinPredicate[OF this] 
    show ?thesis using that False by blast
qed

lemma ExistImpliesMinEnabled:
fixes 
  msg :: "('p, 'v) message" and
  p :: 'p
assumes 
  "isReceiverOf p msg" 
  "enabled (last exec) msg"
shows
  " msg' . minimalEnabled msg'"
proof-
  have MsgHasMinTime:" msg . (enabled (last exec) msg 
     ( p . isReceiverOf p msg))
     ( n .  n < length exec  enabled (execConf n) msg 
         ( n'  n . n' < length trace  msg  (execMsg n'))
         ( n0 .  n0 < length exec  enabled (execConf n0) msg 
         ( n'  n0 . n' < length trace  msg  (execMsg n')) 
         n0  n))" by (clarify, rule LastPoint, auto)
  let ?enabledTimes = "{n::nat .  msg . (enabled (last exec) msg 
     ( p . isReceiverOf p msg))
      n < length exec  (enabled (execConf n) msg 
     ( n'  n . n' < length trace  msg  (execMsg n')))}"
  have NotEmpty:"?enabledTimes  {}" using assms MsgHasMinTime by blast
  hence " n0 . n0  ?enabledTimes" by blast
  hence " nMin  ?enabledTimes .  x  ?enabledTimes . x  nMin" 
    using MinPredicate[of "λn.(n  ?enabledTimes)"] by simp
  then obtain nMin where NMin: "nMin  ?enabledTimes" 
    " x  ?enabledTimes . x  nMin" by blast
  hence " msg . (enabled (last exec) msg  ( p . isReceiverOf p msg))
      nMin < length exec  (enabled (execConf nMin) msg 
     ( n'  nMin . n' < length trace  msg  (execMsg n'))
     ( n0 .  n0 < length exec  enabled (execConf n0) msg 
       ( n'  n0 . n' < length trace  msg  (execMsg n')) 
       n0  nMin))" by blast
  then obtain msg where "(enabled (last exec) msg 
     ( p . isReceiverOf p msg))
     nMin < length exec (enabled (execConf nMin) msg 
     ( n'  nMin . n' < length trace  msg  (execMsg n'))
     ( n0 .  n0 < length exec  enabled (execConf n0) msg 
       ( n'  n0 . n' < length trace  msg  (execMsg n')) 
       n0  nMin))" by blast
  moreover have "( n' msg' . (( p . isReceiverOf p msg') 
     (enabled (last exec) msg') 
     n' < length trace  enabled (execConf n') msg' 
     ( n''  n' . n'' < length trace  msg'  (execMsg n''))) 
       n'  nMin)"
  proof(clarify)
    fix n' msg' p
    assume Assms:
      "isReceiverOf p msg'" 
      "enabled (last exec) msg'" 
      "n' < length trace" 
      "enabled (execConf n') msg'" 
      "n''  n'. (n'' < length trace)  (msg'  execMsg n'')"
    from Assms(3) have "n' < length exec" using length by simp
    with Assms have "n'  ?enabledTimes" by auto
    thus "nMin  n'" using NMin(2) by simp
  qed
  ultimately have "minimalEnabled msg"
    using minimalEnabled_def by blast
  thus ?thesis by blast
qed

lemma StaysEnabledStep:
assumes
  En: "enabled cfg msg" and
  Cfg: "cfg = exec ! n" and
  N: "n < length exec" 
shows
  "enabled (exec ! (n + 1)) msg 
   n = (length exec - 1) 
   msg = trace ! n"
proof(cases "n = length exec - 1")
  case True
  thus ?thesis by simp
next
  case False
  with N have N: "n < length exec - 1" by simp
  with Cfg have Step:  "cfg  trace ! n  (exec ! (n + 1))" 
    using step by simp
  thus ?thesis proof(cases "enabled (exec ! (n + 1)) msg")
    case True
    thus ?thesis by simp
  next
    case False
    hence "¬ enabled (exec ! (n + 1)) msg" by simp
    thus ?thesis using En enabled_def Step N OnlyOccurenceDisables by blast
  qed
qed                          

lemma StaysEnabledHelp:
assumes
  "enabled cfg msg" and
  "cfg = exec ! n" and
  "n < length exec"    
shows 
  " i . i  n  i < (length exec - 1)  enabled (exec ! i) msg 
   msg = (trace ! i)  (enabled (exec ! (i+1)) msg)"
proof(clarify)
  fix i
  assume "n  i" "i < length exec - 1"
    "enabled (execConf i) msg" "¬ enabled (execConf (i + 1)) msg"
  thus "msg = (trace ! i)"
    using assms StaysEnabledStep
    by (metis add.right_neutral add_strict_mono le_add_diff_inverse2
        nat_neq_iff notEmpty  zero_less_one)
qed

lemma StaysEnabled:
assumes En: "enabled cfg msg" and
  "cfg = exec ! n" and
  "n < length exec"   
shows "enabled (last exec) msg  ( i . i  n  i < (length exec - 1) 
   msg = trace ! i )"
proof(cases "enabled (last exec) msg")
  case True
  thus ?thesis by simp
next
  case False 
  hence NotEnabled: "¬ enabled (last exec) msg" by simp
  have "last exec = exec ! (length exec - 1)" 
    by (metis last_conv_nth list.size(3) notEmpty not_one_le_zero)
  hence " l . l  n  last exec = exec ! l  l = length exec - 1" 
    using assms(3) by auto
  then obtain l where L: "l  n" "last exec = exec ! l" 
    "l = length exec - 1" by blast
  have "( i . i  n  i < (length exec - 1)  msg = trace ! i )"  
  proof (rule ccontr)
    assume Ass: " ¬ (in. i < length exec - 1  msg = execMsg i)" 
    hence Not: " i. i < n  i  length exec - 1  msg  execMsg i" 
      by (metis leI)
    have " i. i  n  i  length exec - 1  enabled (exec ! i) msg" 
    proof(clarify)
      fix i 
      assume I: "n  i" "i  length exec - 1"  
      thus "enabled (execConf i) msg"
        using StaysEnabledHelp[OF assms] assms(1,2) Ass 
        by (induct i, auto, metis Suc_le_lessD le_Suc_eq)
    qed
    with NotEnabled L show False by simp
  qed
  thus ?thesis by simp
qed

end ― ‹end of locale Execution›

subsection ‹Expanding executions to longer executions›

lemma (in asynchronousSystem) expandExecutionStep:
fixes 
  cfg :: "('p, 'v, 's ) configuration"
assumes
  CfgIsReachable: "(last exec')  msg  cMsg" and
  ExecIsExecution: "execution trans sends start exec' trace'" 
shows
  " exec'' trace''. (execution trans sends start exec'' trace'') 
   (prefixList exec' exec'') 
   (prefixList trace' trace'') 
   (last exec'') = cMsg 
   (last trace'' = msg)"
proof -
  define execMsg where "execMsg = exec' @ [cMsg]"
  define traceMsg where "traceMsg = trace' @ [msg]"
  have ExecMsgEq: " i < ((length execMsg) - 1) . execMsg ! i = exec'!i " 
    using execMsg_def by (auto simp add: nth_append)
  have TraceMsgEq: " i < ((length traceMsg) - 1) . traceMsg!i = trace'!i" 
    using traceMsg_def 
    by (auto simp add: nth_append)
  have ExecLen: "(length execMsg)  1" using execMsg_def by auto
  have lessLessExec: " i . i < (length exec')  i < (length execMsg )" 
    unfolding execMsg_def by auto
  have ExecLenTraceLen: "length exec'- 1 = length trace'" 
    using ExecIsExecution execution.length by auto
  have lessLessTrace: " i . i < (length exec' - 1)  i < (length trace')" 
    using ExecLenTraceLen by auto
  have Exec'Len: "length exec'  1" 
    using ExecIsExecution execution.notEmpty by blast
  hence "hd exec' = hd execMsg " using execMsg_def
    by (metis One_nat_def hd_append2 length_0_conv not_one_le_zero)
  moreover have "initial (hd exec')" 
    using ExecIsExecution execution.base by blast 
  ultimately have ExecInit: "initial (hd execMsg)" using execMsg_def by auto
  have ExecMsgLen: "length execMsg - 1 = length traceMsg" 
    using ExecLenTraceLen unfolding execMsg_def traceMsg_def
    by (auto,metis Exec'Len Suc_pred length_greater_0_conv list.size(3) 
       not_one_le_zero) 
  have ExecSteps:" i < length exec' - 1 .
    ((exec' ! i)   trace' ! i  (exec' ! (i + 1)))" 
    using ExecIsExecution execution.step by blast
  have " i < length execMsg - 1. 
    ((execMsg ! i)  traceMsg ! i  (execMsg ! (i + 1)))" 
    unfolding execMsg_def traceMsg_def
  proof auto
    fix i
    assume IlessLen:"i < (length exec')"
    show "((exec' @ [cMsg]) ! i)  ((trace' @ [msg]) ! i) 
       ((exec' @ [cMsg]) ! (Suc i))" 
    proof (cases "(i < (length exec') - 1)")
    case True
      hence IlessLen1: "(i < (length exec') - 1)" by auto
      hence "((exec' ! i)   trace' ! i  (exec' ! (i + 1)))" 
        using ExecSteps by auto
      with IlessLen1 ExecMsgEq lessLessExec execMsg_def 
      have "((exec' @ [cMsg]) ! i)  ((trace') ! i) 
         ((exec' @ [cMsg]) ! (Suc i))" by auto
      thus "((exec' @ [cMsg]) ! i)  ((trace' @ [msg]) ! i) 
         ((exec' @ [cMsg]) ! (Suc i))" 
        using IlessLen1 TraceMsgEq lessLessTrace traceMsg_def by auto
    next
    case False
      with IlessLen have IEqLen1: "(i = (length exec') - 1)" by auto
      thus "((exec' @ [cMsg]) ! i)  ((trace' @ [msg]) ! i) 
         ((exec' @ [cMsg]) ! (Suc i))" 
        using  execMsg_def traceMsg_def  CfgIsReachable Exec'Len 
               ExecLenTraceLen ExecMsgEq ExecMsgLen IlessLen   
        by (metis One_nat_def Suc_eq_plus1 Suc_eq_plus1_left last_conv_nth 
           le_add_diff_inverse length_append less_nat_zero_code list.size(3) 
           list.size(4) nth_append_length)
    qed
  qed
  hence isExecution: "execution trans sends start execMsg traceMsg" 
    using ExecLen ExecMsgLen ExecInit  
    by (unfold_locales ,auto) 
  moreover have "prefixList exec' execMsg" unfolding execMsg_def 
    by (metis TailIsPrefixList not_Cons_self2)
  moreover have "prefixList trace' traceMsg" unfolding traceMsg_def 
    by (metis TailIsPrefixList not_Cons_self2)
  ultimately show ?thesis using execMsg_def traceMsg_def by (metis last_snoc)
qed

lemma (in asynchronousSystem) expandExecutionReachable:
fixes 
  cfg :: "('p, 'v, 's ) configuration" and
  cfgLast :: "('p, 'v, 's ) configuration"
assumes
  CfgIsReachable: "reachable (cfgLast) cfg" and
  ExecIsExecution: "execution trans sends start exec trace"  and
  ExecLast: "cfgLast = last exec" 
shows
  " exec' trace'. (execution trans sends start exec' trace') 
   ((prefixList exec exec' 
     prefixList trace trace') 
     (exec = exec'  trace = trace')) 
   (last exec') = cfg"
using CfgIsReachable  ExecIsExecution ExecLast 
proof (induct cfgLast cfg rule: reachable.induct, auto)
  fix msg cfg3 exec' trace'
  assume "(last exec')  msg  cfg3"
         "execution trans sends start exec' trace'"
  hence " exec'' trace''. (execution trans sends start exec'' trace'') 
     (prefixList exec' exec'') 
     (prefixList trace' trace'')  (last exec'') = cfg3 
     (last trace'') = msg" by (simp add: expandExecutionStep)
  then obtain  exec'' trace'' where 
    NewExec: "execution trans sends start exec'' trace''" 
             "prefixList exec' exec''" "prefixList trace' trace''" 
             "last exec'' = cfg3" by blast
  assume prefixLists: "prefixList exec exec'" 
                      "prefixList trace trace'" 
  from prefixLists(1) NewExec(2) have "prefixList exec exec''" 
    using PrefixListTransitive by auto
  moreover from prefixLists(2) NewExec(3) have 
    "prefixList trace trace''"  using PrefixListTransitive by auto
  ultimately show " exec'' trace'' .
          execution trans sends start exec'' trace'' 
          ((prefixList exec exec''  prefixList trace trace'') 
           (exec = exec''  trace = trace'')) 
          last exec'' = cfg3" using NewExec(1) NewExec(4) by blast
next
  fix msg cfg3
  assume "(last exec)  msg  cfg3" "execution trans sends start exec trace"
  then show
    "exec' trace'. execution trans sends start exec' trace' 
       (prefixList exec exec'  prefixList trace trace' 
         exec = exec'  trace = trace')  last exec' = cfg3" 
    using expandExecutionStep by blast
qed

lemma (in asynchronousSystem) expandExecution:
fixes 
  cfg :: "('p, 'v, 's ) configuration" and
  cfgLast :: "('p, 'v, 's ) configuration"
assumes
  CfgIsReachable: "stepReachable (last exec) msg cfg" and
  ExecIsExecution: "execution trans sends start exec trace"
shows
  " exec' trace'. (execution trans sends start exec' trace') 
   (prefixList exec exec') 
   (prefixList trace trace')  (last exec') = cfg 
   (msg  set (drop (length trace) trace'))"  
proof -
  from CfgIsReachable obtain c' c'' where 
    Step: "reachable (last exec) c'" "c'  msg  c''" "reachable c'' cfg" 
    by (auto simp add: stepReachable_def)
  from Step(1) ExecIsExecution have " exec' trace' .
    execution trans sends start exec' trace' 
    ((prefixList exec exec'  prefixList trace trace') 
     (exec = exec'  trace = trace')) 
    last exec' = c'" by (auto simp add: expandExecutionReachable)
  then obtain  exec' trace' where Exec': 
    "execution trans sends start exec' trace'"
    "(prefixList exec exec'  prefixList trace trace') 
       (exec = exec'  trace = trace')"
    "last exec' = c'" by blast
  from Exec'(1) Exec'(3) Step(2) have " exec'' trace'' . 
    execution trans sends start exec'' trace'' 
    prefixList exec' exec''  prefixList trace' trace'' 
     last exec'' = c''  last trace'' = msg" 
    by (auto simp add: expandExecutionStep)
  then obtain exec'' trace'' where Exec'': 
    "execution trans sends start exec'' trace''"
    "prefixList exec' exec''" "prefixList trace' trace''" 
    "last exec'' = c''" "last trace'' = msg" by blast
  have PrefixLists: "prefixList exec exec''  prefixList trace trace''"  
  proof(cases "exec = exec'  trace = trace'")
  case True
    with Exec'' show "prefixList exec exec''  prefixList trace trace''" 
    by auto
  next
  case False
    with Exec'(2) have Prefix: "prefixList exec exec'" 
      "prefixList trace trace'" by auto
    from Prefix(1) Exec''(2) have "prefixList exec exec''" 
      using PrefixListTransitive by auto
    with Prefix(2) Exec''(3) show  "prefixList exec exec'' 
       prefixList trace trace''" 
      using PrefixListTransitive by auto
  qed
  with Exec''(5) have MsgInTrace'': "msg  set (drop (length trace) trace'')" 
    by (metis PrefixListMonotonicity drop_eq_Nil last_drop 
      last_in_set not_le)
  from Step(3) Exec''(1) Exec''(4) have " exec''' trace''' .
    execution trans sends start exec''' trace''' 
    ((prefixList exec'' exec'''  prefixList trace'' trace''') 
     (exec'' = exec'''  trace'' = trace''')) 
    last exec''' = cfg" 
    by (auto simp add: expandExecutionReachable)
  then obtain exec''' trace''' where Exec''': 
    "execution trans sends start exec''' trace'''"
    "(prefixList exec'' exec'''  prefixList trace'' trace''') 
     (exec'' = exec'''  trace'' = trace''')"
    "last exec''' = cfg" by blast
  have "prefixList exec exec'''  prefixList trace trace''' 
     msg  set (drop (length trace) trace''')"  
  proof(cases "exec'' = exec'''  trace'' = trace'''")
  case True
    with PrefixLists MsgInTrace'' 
    show "prefixList exec exec'''  prefixList trace trace''' 
     msg  set (drop (length trace) trace''')" by auto
  next
  case False
    with Exec'''(2) have Prefix: "prefixList exec'' exec'''" 
      "prefixList trace'' trace'''" by auto
    from Prefix(1) PrefixLists have "prefixList exec exec'''" 
      using PrefixListTransitive by auto
    with Prefix(2) PrefixLists have "prefixList exec exec''' 
       prefixList trace trace'''"  
      using PrefixListTransitive by auto
    moreover have "msg  set (drop (length trace) trace''')" 
      using Prefix(2) PrefixLists MsgInTrace'' 
      by (metis (opaque_lifting, no_types) PrefixListHasTail append_eq_conv_conj 
         drop_take rev_subsetD set_take_subset)
    ultimately show ?thesis by auto
  qed
  with Exec'''(1) Exec'''(3) show ?thesis by blast
qed

subsection ‹Infinite and fair executions›

text ‹
  Völzer does not give much attention to the definition of the
  infinite executions. We derive them from finite executions by considering
  infinite executions to be infinite sequence of finite executions increasing
  monotonically w.r.t. the list prefix relation.
›

definition (in asynchronousSystem) infiniteExecution ::
  "(nat  (('p, 'v, 's) configuration list)) 
   (nat  (('p, 'v) message list))  bool"
where
  "infiniteExecution fe ft 
     n . execution trans sends start (fe n) (ft n)  
      prefixList (fe n) (fe (n+1)) 
      prefixList (ft n) (ft (n+1))"

definition (in asynchronousSystem) correctInfinite ::
  "(nat  (('p, 'v, 's) configuration list)) 
   (nat  (('p, 'v) message list))  'p  bool"
where 
  "correctInfinite fe ft p  
    infiniteExecution fe ft
     ( n .  n0 < length (fe n).  msg .(enabled ((fe n) ! n0) msg) 
     isReceiverOf p msg 
     ( msg' .  n'  n .  n0'  n0 .isReceiverOf p msg' 
     n0' < length (fe n')  (msg' = ((ft n') ! n0'))))"

definition (in asynchronousSystem) fairInfiniteExecution ::
  "(nat  (('p, 'v, 's) configuration list)) 
   (nat  (('p, 'v) message list))  bool"
where
  "fairInfiniteExecution fe ft 
    infiniteExecution fe ft
     ( n .  n0 < length (fe n).  p .  msg . 
      ((enabled ((fe n) ! n0) msg) 
         isReceiverOf p msg  correctInfinite fe ft p ) 
       ( n'  n .  n0'  n0 . n0' < length (ft n') 
         (msg = ((ft n') ! n0'))))"

end