Theory FLPTheorem
section ‹FLPTheorem›
text ‹
  \file{FLPTheorem} combines the results of \file{FLPSystem} with the concept
  of fair infinite executions and culminates in showing the impossibility
  of a consensus algorithm in the proposed setting.
›
theory FLPTheorem
imports Execution FLPSystem
begin
locale flpPseudoConsensus =
  flpSystem trans sends start
for
  trans :: "'p ⇒ 's ⇒ 'v messageValue ⇒'s" and
  sends :: "'p ⇒ 's ⇒ 'v messageValue ⇒ ('p, 'v) message multiset" and
  start :: "'p ⇒ 's" +
assumes
  Agreement: "⋀ i c . agreementInit i c" and
  PseudoTermination: "⋀cc Q . terminationPseudo 1 cc Q"
begin
subsection ‹Obtaining non-uniform executions›
text ‹
  Executions which end with a \isb{nonUniform} configuration can be expanded
  to a strictly longer execution consuming a particular message.
  This lemma connects the previous results to the world of executions,
  thereby paving the way to the final contradiction. It covers a big part of
  the original proof of the theorem, i.e.\ finding the expansion to a longer
  execution where the decision for both values is still possible.
  \voelzer{constructing executions using Lemma 2}
›
lemma NonUniformExecutionsConstructable:
fixes
  exec :: "('p, 'v, 's ) configuration list " and
  trace :: "('p, 'v) message list" and 
  msg :: "('p, 'v) message" and
  p :: 'p  
assumes
  MsgEnabled: "enabled (last exec) msg" and
  PisReceiverOf: "isReceiverOf p msg" and
  ExecIsExecution: "execution trans sends start exec trace" and
  NonUniformLexec: "nonUniform (last exec)" and
  Agree: "⋀ cfg . reachable (last exec) cfg ⟶ agreement cfg"
shows
  "∃ exec' trace' . (execution trans sends start exec' trace') 
    ∧ nonUniform (last exec')
    ∧ prefixList exec exec' ∧ prefixList trace trace' 
    ∧ (∀ cfg . reachable (last exec') cfg ⟶ agreement cfg)
    ∧ stepReachable (last exec) msg (last exec') 
    ∧ (msg ∈ set (drop (length trace) trace'))"
proof -
  from NonUniformCanReachSilentBivalence[OF NonUniformLexec PseudoTermination Agree]
    obtain c' where C':
      "reachable (last exec) c'" 
      "val[p,c'] = {True, False}"
    by blast
  show ?thesis 
  proof (cases "stepReachable (last exec) msg c'")
    case True
    hence IsStepReachable: "stepReachable (last exec) msg c'" by simp
    hence "∃ exec' trace'. (execution trans sends start exec' trace') 
      ∧ prefixList exec exec' 
      ∧ prefixList trace trace' ∧ (last exec') = c' 
      ∧ msg ∈ set (drop (length trace) trace')" 
      using ExecIsExecution expandExecution
      by auto
    then obtain exec' trace' where NewExec: 
      "(execution trans sends start exec' trace')" 
      "prefixList exec exec'" "(last exec') = c'" "prefixList trace trace'" 
      "msg ∈ set (drop (length trace) trace')" by blast
    hence lastExecExec'Reachable: "reachable (last exec) (last exec')" 
      using C'(1) by simp
    hence InitReachLastExec':  "initReachable (last exec')" 
      using NonUniformLexec 
      by (metis ReachableTrans initReachable_def)
    hence nonUniformC': "nonUniform (last exec')" using C'(2) NewExec(3) 
      by (auto simp add: vUniform_def)
    hence isAgreementPreventing: 
      "(∀ cfg . reachable (last exec') cfg ⟶ agreement cfg)"
      using lastExecExec'Reachable Agree by (metis ReachableTrans)
    with NewExec nonUniformC' IsStepReachable show ?thesis by auto
  next
    case False
    hence NotStepReachable: "¬ (stepReachable (last exec) msg c')" by simp
    from C'(1) obtain exec' trace' where NewExec: 
      "execution trans sends start exec' trace'"
      "(prefixList exec exec' ∧ prefixList trace trace') 
      ∨ (exec = exec' ∧ trace = trace')"
      "last exec' = c'"
      using ExecIsExecution expandExecutionReachable by blast
    have lastExecExec'Reachable: "reachable (last exec) (last exec')" 
      using C'(1) NewExec(3) by simp
    with NonUniformLexec have InitReachLastExec': 
      "initReachable (last exec')" 
      by (metis ReachableTrans initReachable_def)
    with C'(2) NewExec(3) have nonUniformC': "nonUniform (last exec')" 
      by (auto simp add: vUniform_def)
    show "∃ exec1 trace1 . (execution trans sends start exec1 trace1) 
      ∧ nonUniform (last exec1)
      ∧ prefixList exec exec1 ∧ prefixList trace trace1 
      ∧ (∀ cfg . reachable (last exec1) cfg ⟶ agreement cfg)
      ∧ stepReachable (last exec) msg (last exec1) 
      ∧ (msg ∈ set (drop (length trace) trace1))"
    proof (cases "enabled (last exec') msg") 
      case True
      hence EnabledMsg: "enabled (last exec') msg" by auto
      hence "∃ cMsg . ((last exec') ⊢ msg ↦ cMsg )"  
      proof (cases msg)
        case (InMsg p' b)
        with PisReceiverOf have MsgIsInMsg: "(msg = <p, inM b>)" by auto
        define cfgInM where "cfgInM = ⦇states = λproc. (
        if proc = p then
          trans p (states (last exec') p) (Bool b)
        else states (last exec') proc),
        msgs = (((sends p (states (last exec') p) (Bool b))
              ∪# (msgs (last exec')-# msg)))⦈ "
          with UniqueReceiverOf MsgIsInMsg EnabledMsg have 
          "((last exec') ⊢ msg ↦ cfgInM)" by auto
        thus "∃ cMsg . ((last exec') ⊢ msg ↦ cMsg )" by blast
      next 
        case (OutMsg b)
        thus "∃ cMsg . ((last exec') ⊢ msg ↦ cMsg )" using PisReceiverOf 
          by auto
      next 
        case (Msg p' v')
        with PisReceiverOf have MsgIsVMsg: "(msg = <p, v'>)" by auto
        define cfgVMsg where "cfgVMsg =
          ⦇states = λproc. (
              if proc = p then
               trans p (states (last exec') p) (Value v')
               else states (last exec') proc),
            msgs = (((sends p (states (last exec') p) (Value v'))
                ∪# (msgs (last exec') -# msg )))⦈ "
        with UniqueReceiverOf MsgIsVMsg EnabledMsg noInSends have 
          "((last exec') ⊢ msg ↦ cfgVMsg)" by auto 
        thus "∃ cMsg . ((last exec') ⊢ msg ↦ cMsg )" by blast
      qed  
      then obtain cMsg where  CMsg:"((last exec') ⊢ msg ↦ cMsg )" by auto
      define execMsg where "execMsg = exec' @ [cMsg]"
      define traceMsg where "traceMsg = trace' @ [msg]"
      from NewExec(1) CMsg obtain execMsg traceMsg where isExecution: 
        "execution trans sends start execMsg traceMsg"
        and ExecMsg: "prefixList exec' execMsg" "prefixList trace' traceMsg"
        "last execMsg = cMsg" "last traceMsg = msg" 
        using expandExecutionStep by blast
      have isPrefixListExec: "prefixList exec execMsg" 
        using PrefixListTransitive NewExec(2) ExecMsg(1) by auto 
      have isPrefixListTrace: "prefixList trace traceMsg" 
        using PrefixListTransitive NewExec(2) ExecMsg(2) by auto
      have cMsgLastReachable: "reachable cMsg (last execMsg)" 
        by (auto simp add: ExecMsg reachable.init) 
      hence isStepReachable: "stepReachable (last exec) msg (last execMsg)" 
        using CMsg lastExecExec'Reachable   
        by (auto simp add: stepReachable_def) 
      have InitReachLastExecMsg: "initReachable (last execMsg)" 
        using CMsg InitReachLastExec' cMsgLastReachable 
        by (metis ReachableTrans initReachable_def step) 
      have "val[p, (last exec')] ⊆ val[p, cMsg]" 
        using CMsg PisReceiverOf InitReachLastExec'
          ActiveProcessSilentDecisionValuesIncrease[of p p "last exec'" msg cMsg]
        by auto
      with ExecMsg C'(2) NewExec(3) have 
        "val[p, (last execMsg)] = {True, False}" by auto
      with InitReachLastExecMsg have isNonUniform: 
        "nonUniform (last execMsg)" by (auto simp add: vUniform_def)
      have "reachable (last exec) (last execMsg)" 
        using lastExecExec'Reachable cMsgLastReachable CMsg 
        by (metis ReachableTrans step)
      hence isAgreementPreventing: 
        "(∀ cfg . reachable (last execMsg) cfg ⟶ agreement cfg)" 
        using Agree by (metis ReachableTrans)
      have "msg ∈ set (drop (length trace) traceMsg)" using ExecMsg(4) 
        isPrefixListTrace 
        by (metis (full_types) PrefixListMonotonicity last_drop last_in_set
          length_0_conv length_drop less_zeroE zero_less_diff)
      thus ?thesis using isExecution isNonUniform isPrefixListExec 
        isPrefixListTrace isAgreementPreventing isStepReachable by blast
    next
      case False
      hence notEnabled: "¬ (enabled (last exec') msg)" by auto
      have isStepReachable: "stepReachable (last exec) msg (last exec')" 
        using MsgEnabled notEnabled lastExecExec'Reachable StepReachable 
          by auto
        with NotStepReachable NewExec(3) show ?thesis by simp
    qed 
  qed 
qed
lemma NonUniformExecutionBase:
fixes
  cfg
assumes
  Cfg: "initial cfg" "nonUniform cfg"
shows 
  "execution trans sends start [cfg] [] 
  ∧ nonUniform (last [cfg]) 
  ∧ (∃ cfgList' msgList'.  nonUniform (last cfgList') 
    ∧ prefixList [cfg] cfgList' 
    ∧ prefixList [] msgList'
    ∧ (execution trans sends start cfgList' msgList')
     ∧ (∃ msg'. execution.minimalEnabled [cfg] [] msg' 
         ∧ msg' ∈ set msgList'))"
proof -
  have NonUniListCfg: "nonUniform (last [cfg])" using Cfg(2) by auto
  have AgreeCfg': "∀ cfg' . 
    reachable (last [cfg]) cfg' ⟶ agreement cfg'" 
    using Agreement Cfg(1) 
    by (auto simp add: agreementInit_def reachable.init agreement_def)
  have StartExec: "execution trans sends start [cfg] []" 
    using Cfg(1) by (unfold_locales, auto)
  hence "∃ msg . execution.minimalEnabled [cfg] [] msg" 
    using Cfg execution.ExistImpliesMinEnabled
    by (metis enabled_def initial_def isReceiverOf.simps(1) 
       last.simps zero_less_one)
  then obtain msg where MinEnabledMsg: 
    "execution.minimalEnabled [cfg] [] msg" by blast
  hence "∃ pMin . isReceiverOf pMin msg" using StartExec 
    by (auto simp add: execution.minimalEnabled_def)
  then obtain pMin where PMin: "isReceiverOf pMin msg" by blast
  hence "enabled (last [cfg]) msg ∧ isReceiverOf pMin msg" 
    using MinEnabledMsg StartExec 
    by (auto simp add: execution.minimalEnabled_def)
  hence Enabled: "enabled (last [cfg]) msg" "isReceiverOf pMin msg" 
    by auto
  from Enabled StartExec NonUniListCfg PseudoTermination AgreeCfg' 
  have "∃ exec' trace' . (execution trans sends start exec' trace') 
    ∧ nonUniform (last exec')
    ∧ prefixList [cfg] exec' ∧ prefixList [] trace' 
    ∧ (∀ cfg' . reachable (last exec') cfg' ⟶ agreement cfg')
    ∧ stepReachable (last [cfg]) msg (last exec') 
    ∧ (msg ∈ set (drop (length []) trace'))" 
  using NonUniformExecutionsConstructable[of "[cfg]" "msg" "pMin"
          "[]::('p,'v) message list"] 
    by simp
  with StartExec NonUniListCfg MinEnabledMsg show ?thesis by auto
qed
lemma NonUniformExecutionStep:
fixes
 cfgList msgList
assumes
  Init: "initial (hd cfgList)" and
  NonUni: "nonUniform (last cfgList)" and
  Execution: "execution trans sends start cfgList msgList"
shows
  "(∃ cfgList' msgList' .
      nonUniform (last cfgList') 
      ∧ prefixList cfgList cfgList' 
      ∧ prefixList msgList msgList'
      ∧ (execution trans sends start cfgList' msgList') 
      ∧ (initial (hd cfgList'))
      ∧ (∃ msg'. execution.minimalEnabled cfgList msgList msg' 
        ∧ msg' ∈ (set (drop (length msgList ) msgList')) ))"
proof -
  have ReachImplAgree: "∀ cfg . reachable (last cfgList) cfg 
    ⟶ agreement cfg"
    using Agreement Init NonUni ReachableTrans
    unfolding agreementInit_def agreement_def initReachable_def
    by (metis (full_types))
  have "∃ msg p. enabled (last cfgList) msg ∧ isReceiverOf p msg" 
  proof -
    from PseudoTermination NonUni have 
      "∃c'. qReachable (last cfgList) Proc c' ∧ decided c'" 
      using terminationPseudo_def by auto
      then obtain c' where C': "reachable (last cfgList) c'" 
        "decided c'" 
        using QReachImplReach by blast 
    have NoOut: 
      "0 = msgs (last cfgList) <⊥, outM False>"  
      "0 = msgs (last cfgList) <⊥, outM True>" 
      using NonUni ReachImplAgree PseudoTermination 
      by (metis NonUniformImpliesNotDecided neq0_conv)+
    with C'(2) have "(last cfgList) ≠ c'" 
      by (metis (full_types) less_zeroE)
    thus ?thesis using C'(1) ReachableStepFirst by blast
  qed
  then obtain msg p where Enabled: 
    "enabled (last cfgList) msg" "isReceiverOf p msg" by blast
  hence "∃ msg . execution.minimalEnabled cfgList msgList msg" 
    using Init execution.ExistImpliesMinEnabled[OF Execution] by auto        
  then obtain msg' where MinEnabledMsg: 
    "execution.minimalEnabled cfgList msgList msg'" by blast
  hence "∃ p' . isReceiverOf p' msg'"
    using Execution
    by (auto simp add: execution.minimalEnabled_def)
  then obtain p' where
    P': "isReceiverOf p' msg'" by blast
  hence Enabled':
    "enabled (last cfgList) msg'" "isReceiverOf p' msg'" 
    using MinEnabledMsg Execution
    by (auto simp add: execution.minimalEnabled_def)     
  have "∃ exec' trace' . (execution trans sends start exec' trace') 
    ∧ nonUniform (last exec')
    ∧ prefixList cfgList exec' ∧ prefixList msgList trace' 
    ∧ (∀ cfg . reachable (last exec') cfg ⟶ agreement cfg)
    ∧ stepReachable (last cfgList) msg' (last exec') 
    ∧ (msg' ∈ set (drop (length msgList) trace')) "
    using NonUniformExecutionsConstructable[OF Enabled' Execution
          NonUni] ReachImplAgree by auto
  thus ?thesis
    using MinEnabledMsg by (metis execution.base)
qed
subsection ‹Non-uniformity even when demanding fairness›
text ‹
  Using \isb{NonUniformExecutionBase} and \isb{NonUniformExecutionStep} one can obtain
  non-uniform executions which are fair.
  Proving the fairness turned out quite cumbersome.
›
text ‹
  These two functions construct infinite series of configurations lists
  and message lists from two extension functions. 
›
fun infiniteExecutionCfg ::
  "('p, 'v, 's) configuration ⇒
   (('p, 'v, 's) configuration list ⇒ ('p, 'v) message list 
    ⇒ ('p, 'v, 's) configuration list) ⇒
   (('p, 'v, 's) configuration list ⇒ ('p, 'v) message list 
    ⇒('p, 'v) message list) 
  ⇒ nat
  ⇒ (('p, 'v, 's) configuration list)"
and  infiniteExecutionMsg ::
  "('p, 'v, 's) configuration ⇒
   (('p, 'v, 's) configuration list ⇒ ('p, 'v) message list 
    ⇒ ('p, 'v, 's) configuration list) ⇒
   (('p, 'v, 's) configuration list ⇒ ('p, 'v) message list 
    ⇒('p, 'v) message list) 
  ⇒ nat
  ⇒ ('p, 'v) message list"
where
  "infiniteExecutionCfg cfg fStepCfg fStepMsg 0 = [cfg]"
| "infiniteExecutionCfg cfg fStepCfg fStepMsg (Suc n) =
    fStepCfg (infiniteExecutionCfg cfg fStepCfg fStepMsg n) 
             (infiniteExecutionMsg cfg fStepCfg fStepMsg n)"
| "infiniteExecutionMsg cfg fStepCfg fStepMsg 0 = []"
| "infiniteExecutionMsg cfg fStepCfg fStepMsg (Suc n) =
    fStepMsg (infiniteExecutionCfg cfg fStepCfg fStepMsg n) 
             (infiniteExecutionMsg cfg fStepCfg fStepMsg n)"
lemma FairNonUniformExecution:
fixes
  cfg
assumes
  Cfg: "initial cfg" "nonUniform cfg"
shows "∃ fe ft.
  (fe 0) = [cfg]
  ∧ fairInfiniteExecution fe ft
  ∧ (∀ n . nonUniform (last (fe n))
       ∧ prefixList (fe n) (fe (n+1)) 
       ∧ prefixList (ft n) (ft (n+1))
       ∧ (execution trans sends start (fe n) (ft n)))"
proof -
  have BC: 
    "execution trans sends start [cfg] [] 
    ∧ nonUniform (last [cfg]) 
    ∧ (∃ cfgList' msgList'.  nonUniform (last cfgList') 
    ∧ prefixList [cfg] cfgList' 
    ∧ prefixList [] msgList'
    ∧ (execution trans sends start cfgList' msgList')
    ∧ (∃ msg'. execution.minimalEnabled [cfg] [] msg' 
       ∧ msg' ∈ set msgList'))"
    using NonUniformExecutionBase[OF assms] .
   
  obtain fStepCfg fStepMsg where FStep: "∀ cfgList msgList . ∃cfgList' msgList' .
          fStepCfg cfgList msgList = cfgList' ∧
          fStepMsg cfgList msgList = msgList' ∧
          (initial (hd cfgList) ∧
          nonUniform (last cfgList) ∧
          execution trans sends start cfgList msgList ⟶ 
          (nonUniform (last (fStepCfg cfgList msgList)) 
          ∧ prefixList cfgList (fStepCfg cfgList msgList) 
          ∧ prefixList msgList (fStepMsg cfgList msgList) 
          ∧ execution trans sends start (fStepCfg cfgList msgList) 
              (fStepMsg cfgList msgList) 
          ∧ (initial (hd (fStepCfg cfgList msgList)))
          ∧ (∃ msg'. execution.minimalEnabled cfgList msgList msg' 
            ∧ msg' ∈ (set (drop (length msgList) 
                                (fStepMsg cfgList msgList))))))"
   using NonUniformExecutionStep
      PredicatePairFunctions2[of 
        "λ cfgList msgList cfgList' msgList'. 
          (initial (hd cfgList) 
          ∧ nonUniform (last cfgList) 
          ∧ execution trans sends start cfgList msgList 
            ⟶ (nonUniform (last cfgList') 
            ∧ prefixList cfgList cfgList' 
            ∧ prefixList msgList msgList' 
            ∧ execution trans sends start cfgList' msgList'
            ∧ (initial (hd cfgList'))
            ∧ (∃ msg'. execution.minimalEnabled cfgList msgList msg' 
              ∧ msg' ∈ (set (drop (length msgList ) msgList')))))" "False"] by auto
  define fe ft
    where "fe = infiniteExecutionCfg cfg fStepCfg fStepMsg"
      and "ft = infiniteExecutionMsg cfg fStepCfg fStepMsg"
  
  have BasicProperties: "(∀n. nonUniform (last (fe n)) 
    ∧ prefixList (fe n) (fe (n + 1)) ∧ prefixList (ft n) (ft (n + 1)) 
    ∧ execution trans sends start (fe n) (ft n) 
    ∧ initial (hd (fe (n + 1))))"
  proof (clarify)
    fix n
    show "nonUniform (last (fe n)) ∧
          prefixList (fe n) (fe (n + (1::nat))) 
          ∧ prefixList (ft n) (ft (n + (1::nat))) 
          ∧ execution trans sends start (fe n) (ft n) 
          ∧ initial (hd (fe (n + 1)))"
    proof(induct n)
      case 0
      hence "fe 0 = [cfg]" "ft 0 = []" "fe 1 = fStepCfg (fe 0) (ft 0)" 
        "ft 1 = fStepMsg (fe 0) (ft 0)"
        using fe_def ft_def
        by simp_all
      thus ?case
        using BC FStep
        by (simp, metis execution.base)
    next
      case (Suc n)
        thus ?case
        using fe_def ft_def
        by (auto, (metis FStep execution.base)+)
    qed
  qed
  have Fair: "fairInfiniteExecution fe ft" 
    using BasicProperties
    unfolding fairInfiniteExecution_def infiniteExecution_def 
      execution_def flpSystem_def
  proof(auto simp add: finiteProcs minimalProcs finiteSends noInSends) 
    fix n n0 p msg
    assume AssumptionFair: "∀n. initReachable (last (fe n)) ∧
       ¬ vUniform False (last (fe n)) ∧
       ¬ vUniform True (last (fe n)) ∧
       prefixList (fe n) (fe (Suc n)) ∧
       prefixList (ft n) (ft (Suc n)) ∧
       Suc 0 ≤ length (fe n) ∧
       length (fe n) - Suc 0 = length (ft n) ∧
       initial (hd (fe n)) ∧ 
       (∀i<length (fe n) - Suc 0. ((fe n ! i) ⊢ (ft n ! i) 
       ↦ (fe n ! Suc i))) ∧ initial (hd (fe (Suc n)))"
      "n0 < length (fe n)"
      "enabled (fe n ! n0) msg" 
      "isReceiverOf p msg" 
      "correctInfinite fe ft p"
    have MessageStaysOrConsumed: "⋀ n n1 n2 msg. 
      (n1 ≤ n2 ∧ n2 < length (fe n) ∧ (enabled (fe n ! n1) msg)) 
      ⟶ (enabled (fe n ! n2) msg) 
          ∨ (∃ n0' ≥ n1. n0' < length (ft n) ∧ ft n ! n0' = msg)"
    proof(auto)
      fix n n1 n2 msg
      assume Ass: "n1 ≤ n2" "n2 < length (fe n)" "enabled (fe n ! n1) msg"
        "∀index<length (ft n). n1 ≤ index ⟶ ft n ! index ≠ msg"
      have "∀ k ≤ n2 - n1 . 
        msgs (fe n ! n1) msg ≤ msgs (fe n ! (n1 + k)) msg" 
      proof(auto)
        fix k
        show "k ≤ n2 - n1 ⟹ 
          msgs (fe n ! n1) msg ≤ msgs (fe n ! (n1 + k)) msg"
        proof(induct k, auto)
          fix k
          assume IV: "msgs (fe n ! n1) msg ≤ msgs (fe n ! (n1 + k)) msg" 
            "Suc k ≤ n2 - n1"
          from BasicProperties have Exec: 
            "execution trans sends start (fe n) (ft n)" by blast
          have "n2 ≤ length (ft n)"
            using Exec Ass(2)
            execution.length[of trans sends start "fe n" "ft n"]
            by simp
          hence RightIndex: "n1 + k ≥ n1 ∧ n1 + k < length (ft n)"
            using IV(2) by simp
          have  Step: "(fe n ! (n1 + k)) ⊢ (ft n ! (n1 + k)) 
                      ↦ (fe n ! Suc (n1 + k))" 
            using Exec execution.step[of trans sends start "fe n" "ft n" 
              "n1 + k" "fe n ! (n1 + k)" "fe n ! (n1 + k + 1)"] IV(2) 
              Ass(2) 
            by simp
          hence "msg ≠ (ft n ! (n1 + k))" 
            using Ass(4) Ass(2) IV(2) RightIndex Exec 
            execution.length[of trans sends start "fe n" "ft n"]
            by blast
          thus "msgs (fe n ! n1) msg ≤ msgs (fe n ! Suc (n1 + k)) msg" 
            using Step OtherMessagesOnlyGrowing[of "(fe n ! (n1 + k))" 
              "(ft n ! (n1 + k))" "(fe n ! Suc (n1 + k))" "msg"] IV(1)
            by simp
        qed
      qed
      hence "msgs (fe n ! n1) msg ≤ msgs (fe n ! n2) msg" 
        by (metis Ass(1) le_add_diff_inverse order_refl)
      thus "enabled (fe n ! n2) msg" using Ass(3) enabled_def 
        by (metis gr0I leD)
    qed
    have EnabledOrConsumed: "enabled (fe n ! (length (fe n) - 1)) msg 
      ∨ (∃n0'≥n0. n0' < length (ft n) ∧ ft n ! n0' = msg)" 
      using AssumptionFair(3) AssumptionFair(2) 
        MessageStaysOrConsumed[of "n0" "length (fe n) - 1" "n" "msg"] 
      by auto
    have EnabledOrConsumedAtLast: "enabled (last (fe n)) msg ∨ 
      (∃ n0' . n0' ≥ n0 ∧ n0' < length (ft n) ∧ (ft n) ! n0' = msg )"
      using EnabledOrConsumed last_conv_nth AssumptionFair(2) 
      by (metis length_0_conv less_nat_zero_code)
    have Case2ImplThesis: "(∃ n0' . n0' ≥ n0 ∧ n0' < length (ft n) 
      ∧ ft n ! n0' = msg) 
      ⟹ (∃n'≥n. ∃n0'≥n0. n0' < length (ft n') ∧ msg = ft n' ! n0')"
      by auto
    have Case1ImplThesis': "enabled (last (fe n)) msg 
      ⟶ (∃n'≥n. ∃n0'≥ (length (ft n)). n0' < length (ft n') 
          ∧ msg = ft n' ! n0')" 
    proof(clarify)
      assume AssumptionCase1ImplThesis': "enabled (last (fe n)) msg"
      show "∃n'≥n. ∃n0'≥length (ft n). n0' < length (ft n') 
        ∧ msg = ft n' ! n0'" 
      proof(rule ccontr,simp)
        assume AssumptionFairContr: "∀n'≥n. ∀n0'<length (ft n'). 
          length (ft n) ≤ n0' ⟶ msg ≠ ft n' ! n0'"
        define firstOccSet where "firstOccSet n = { msg1 . ∃ nMsg . 
          ∃ n1 ≤ nMsg . 
          execution.firstOccurrence (fe n) (ft n) msg1 n1 
          ∧ execution.firstOccurrence (fe n) (ft n) msg nMsg }" for n
        have NotEmpty: "fe n ≠ []" using  AssumptionFair(2) 
          by (metis less_nat_zero_code list.size(3))
        have FirstToLast': 
          "∀ n . reachable ((fe n) ! 0) ((fe n) ! (length (fe n) - 1))"
          using execution.ReachableInExecution BasicProperties execution.notEmpty
          by (metis diff_less less_or_eq_imp_le not_gr0 not_one_le_zero)
        hence FirstToLast: "∀ n . reachable (hd (fe n)) (last (fe n))" 
          using NotEmpty hd_conv_nth last_conv_nth AssumptionFair(1) 
          by (metis (full_types) One_nat_def length_0_conv 
            not_one_le_zero)
        hence InitToLast: "∀ n . initReachable (last (fe n))" 
          using BasicProperties by auto
        have "⋀ msg n0 . ∀ n . 
          (execution.firstOccurrence (fe n) (ft n) msg n0) 
          ⟶  0 < msgs (last (fe n)) msg"
          using BasicProperties execution.firstOccurrence_def 
            enabled_def
          by metis
        hence "∀ n . ∀ msg' ∈ (firstOccSet n) . 
          0 < msgs (last (fe n)) msg'" using firstOccSet_def by blast
        hence "∀ n . firstOccSet n ⊆ {msg. 0 < msgs (last (fe n)) msg}"
          by (metis (lifting, full_types) mem_Collect_eq subsetI)
        hence FiniteMsgs: "∀ n . finite (firstOccSet n)" 
          using FiniteMessages[OF finiteProcs finiteSends] InitToLast
          by (metis rev_finite_subset)
        have FirstOccSetDecrOrConsumed: "∀ index . 
          (enabled (last (fe index)) msg) 
          ⟶ (firstOccSet (Suc index) ⊂ firstOccSet index 
          ∧ (enabled (last (fe (Suc index))) msg)
            ∨ msg ∈ (set (drop (length (ft index)) (ft (Suc index)))))"
        proof(clarify)
          fix index
          assume AssumptionFirstOccSetDecrOrConsumed:
            "enabled (last (fe index)) msg" 
            "msg ∉ set (drop (length (ft index)) (ft (Suc index)))"
          have NotEmpty: "fe (Suc index) ≠ []" "fe index ≠ []" 
            using BasicProperties 
            by (metis AssumptionFair(1) One_nat_def list.size(3) 
              not_one_le_zero)+
          have LengthStep: "length (ft (Suc index)) > length (ft index)"
            using AssumptionFair(1) 
            by (metis PrefixListMonotonicity)              
          have IPrefixList:
            "∀ i::nat . prefixList (ft i) (ft (Suc i))" 
            using AssumptionFair(1) by auto
          have IPrefixListEx:
            "∀ i::nat . prefixList (fe i) (fe (Suc i))" 
            using AssumptionFair(1) by auto
          have LastOfIndex:
            "(fe (Suc index) ! (length (fe index) - Suc 0)) 
            = (last (fe index))"
            using PrefixSameOnLow[of "fe index" "fe (Suc index)"]
              IPrefixListEx[rule_format, of index]
              NotEmpty LengthStep 
            by (auto simp add: last_conv_nth)
          have NotConsumedIntermediate: 
            "∀ i::nat < length (ft (Suc index)) . 
              (i ≥ length (ft index)
              ⟶ ft (Suc index) ! i ≠ msg)" 
            using AssumptionFirstOccSetDecrOrConsumed(2) ListLenDrop 
            by auto
          hence 
            "¬(∃i. i < length (ft (Suc index)) ∧ i ≥ length (ft index)
            ∧ msg = (ft (Suc index)) ! i)" 
            using execution.length BasicProperties
            by auto
          hence "¬(∃i. i < length (fe (Suc index)) - 1 
            ∧ i ≥ length (fe index) - 1 
            ∧ msg = (ft (Suc index)) ! i)"
            using BasicProperties[rule_format, of "Suc index"]
              BasicProperties[rule_format, of "index"]
              execution.length[of trans sends start]
            by auto
          hence EnabledIntermediate: 
            "∀ i < length (fe (Suc index)) . (i ≥ length (fe index) - 1
              ⟶ enabled (fe (Suc index) ! i) msg)" 
            using BasicProperties[rule_format, of "Suc index"]
              BasicProperties[rule_format, of "index"]
              execution.StaysEnabled[of trans sends start
              "fe (Suc index)" "ft (Suc index)" "last (fe index)" msg 
              "length (fe index) - 1 "]
              AssumptionFirstOccSetDecrOrConsumed(1)
            by (auto, metis AssumptionFair(1) LastOfIndex 
              MessageStaysOrConsumed)
          have "length (fe (Suc index)) - 1 ≥ length (fe index) - 1"
            using PrefixListMonotonicity NotEmpty BasicProperties 
            by (metis AssumptionFair(1) diff_le_mono less_imp_le)
          hence "enabled (fe (Suc index) 
            ! (length (fe (Suc index)) - 1)) msg"
            using EnabledIntermediate NotEmpty(1) 
            by (metis diff_less length_greater_0_conv zero_less_one)
          hence EnabledInSuc: "enabled (last (fe (Suc index))) msg" 
            using NotEmpty last_conv_nth[of "fe (Suc index)"] by simp
          have IndexIsExec: 
            "execution trans sends start (fe index) (ft index)" 
            using BasicProperties by blast
          have SucIndexIsExec: 
            "execution trans sends start (fe (Suc index)) 
              (ft (Suc index))" 
            using BasicProperties by blast
          have SameCfgOnLow: "∀ i < length (fe index) . (fe index) ! i
            = (fe (Suc index)) ! i"
            using BasicProperties PrefixSameOnLow by auto
          have SameMsgOnLow: "∀ i < length (ft index) . (ft index) ! i
            = (ft (Suc index)) ! i"
            using BasicProperties PrefixSameOnLow by auto
          have SmallIndex: "⋀ nMsg . execution.firstOccurrence
            (fe (Suc index)) (ft (Suc index)) msg nMsg 
            ⟹ nMsg < length (fe index)" 
          proof(-)
            fix nMsg
            assume "execution.firstOccurrence (fe (Suc index)) 
              (ft (Suc index)) msg nMsg"
            hence AssumptionSubset3: 
              "∃p. isReceiverOf p msg"
                "enabled (last (fe (Suc index))) msg"
                "nMsg < length (fe (Suc index))"
                "enabled (fe (Suc index) ! nMsg) msg"
                "∀n'≥nMsg. n' < length (ft (Suc index)) 
                ⟶ msg ≠ ft (Suc index) ! n'"
                "nMsg ≠ 0 ⟶ ¬ enabled (fe (Suc index) ! (nMsg - 1)) 
                msg ∨ msg = ft (Suc index) ! (nMsg - 1)"
              using execution.firstOccurrence_def[of "trans" "sends" 
                "start" "fe (Suc index)" "ft (Suc index)" "msg" "nMsg"]
                SucIndexIsExec by auto
            show "nMsg < length (fe index)"
            proof(rule ccontr)
              assume AssumpSmallIndex: "¬ nMsg < length (fe index)"
              have "fe index ≠ []" using BasicProperties 
                AssumptionFair(1)
                by (metis One_nat_def list.size(3) not_one_le_zero)
              hence "length (fe index) > 0" 
                by (metis length_greater_0_conv)
              hence nMsgNotZero: "nMsg ≠ 0" 
                using AssumpSmallIndex by metis
              hence SucCases: "¬ enabled ((fe (Suc index)) ! (nMsg - 1))
                msg ∨ msg = (ft (Suc index)) ! (nMsg - 1)"
                using AssumptionSubset3(6) by blast
              have Cond1: "nMsg - 1 ≥ length (fe index) - 1"
                using AssumpSmallIndex by (metis diff_le_mono leI)
              hence Enabled: "enabled (fe (Suc index) ! (nMsg - 1)) msg"
                using EnabledIntermediate AssumptionSubset3(3) 
                by (metis less_imp_diff_less)
              have Cond2: "nMsg - 1 ≥ length (ft index) ∧ nMsg - 1
                < length (ft (Suc index))"
                using Cond1 execution.length[of "trans" "sends" "start"
                  "fe index" "ft index"]
                  IndexIsExec AssumptionSubset3(3) 
                  by (simp, metis AssumptionFair(1) One_nat_def Suc_diff_1 
                    Suc_eq_plus1 less_diff_conv nMsgNotZero neq0_conv)
              hence NotConsumed: "ft (Suc index) ! (nMsg - 1) ≠ msg" 
                using NotConsumedIntermediate by simp
              show False using SucCases Enabled NotConsumed
              by blast
            qed
          qed
          have Subset: "⋀ msgInSet . msgInSet ∈ firstOccSet (Suc index)
            ⟹ msgInSet ∈ firstOccSet index" 
          unfolding firstOccSet_def
          proof(auto)
            fix msgInSet nMsg n1
            assume AssumptionSubset: "n1 ≤ nMsg"
              "execution.firstOccurrence (fe (Suc index)) 
                (ft (Suc index)) msgInSet n1"
              "execution.firstOccurrence (fe (Suc index)) 
                (ft (Suc index)) msg nMsg"
            have AssumptionSubset2: 
              "∃p. isReceiverOf p msgInSet"
                "enabled (last (fe (Suc index))) msgInSet"
                "n1 < length (fe (Suc index))"
                "enabled (fe (Suc index) ! n1) msgInSet"
                "∀n'≥n1. n' < length (ft (Suc index)) 
                  ⟶ msgInSet ≠ ft (Suc index) ! n'"
                "n1 ≠ 0 ⟶ ¬ enabled (fe (Suc index) ! (n1 - 1)) 
                  msgInSet ∨ msgInSet = ft (Suc index) ! (n1 - 1)"
              using execution.firstOccurrence_def[of "trans" "sends" 
                "start" "fe (Suc index)" "ft (Suc index)" "msgInSet" 
                "n1"] AssumptionSubset(2) SucIndexIsExec by auto 
            have AssumptionSubset3: 
              "∃p. isReceiverOf p msg"
                "enabled (last (fe (Suc index))) msg"
                "nMsg < length (fe (Suc index))"
                "enabled (fe (Suc index) ! nMsg) msg"
                "∀n'≥nMsg. n' < length (ft (Suc index)) 
                  ⟶ msg ≠ ft (Suc index) ! n'"
                "nMsg ≠ 0 ⟶ ¬ enabled (fe (Suc index) ! (nMsg - 1)) 
                  msg ∨ msg = ft (Suc index) ! (nMsg - 1)"
              using execution.firstOccurrence_def[of "trans" "sends" 
                "start" "fe (Suc index)" "ft (Suc index)" "msg" "nMsg"]
                AssumptionSubset(3) SucIndexIsExec by auto
            have ShorterTrace: "length (ft index) 
                                < length (ft (Suc index))" 
              using PrefixListMonotonicity BasicProperties by auto
            have FirstOccurrenceMsg: "execution.firstOccurrence 
              (fe index) (ft index) msg nMsg"
            proof-
              have Occ1: "∃ p . isReceiverOf p msg" 
                using AssumptionSubset3(1) by blast
              have Occ2: "enabled (last (fe index)) msg" 
                using AssumptionFirstOccSetDecrOrConsumed by blast
              have "(fe index) ! nMsg = (fe (Suc index)) ! nMsg"
                using SmallIndex AssumptionSubset(3) 
                  PrefixSameOnLow[of "fe index" "fe (Suc index)"] 
                  BasicProperties 
                by simp
              hence Occ4: "enabled ((fe index) ! nMsg) msg" 
                using AssumptionSubset3(4) by simp
              have OccSameMsg: "∀ n' ≥ nMsg . n' < length (ft index) 
                ⟶ (ft index) ! n' = (ft (Suc index)) ! n'" 
                using PrefixSameOnLow BasicProperties by auto
              hence Occ5: "∀ n' ≥ nMsg . n' < length (ft index) 
                ⟶ msg ≠ ((ft index) ! n')" 
                using AssumptionSubset3(5) ShorterTrace by simp
              have Occ6: "nMsg ≠ 0 ⟶ (¬ enabled ((fe index) ! 
                (nMsg - 1)) msg ∨ msg = (ft index ) ! (nMsg - 1))" 
              proof(clarify)
                assume AssumpOcc6: "0 < nMsg" "msg ≠ ft index ! 
                  (nMsg - 1)" "enabled (fe index ! (nMsg - 1)) msg"
                have "nMsg - (Suc 0) < length (fe index) - (Suc 0)" 
                  using SmallIndex AssumptionSubset(3) AssumpOcc6(1) 
                  by (metis Suc_le_eq diff_less_mono)
                hence SmallIndexTrace: "nMsg - 1 < length (ft index)" 
                  using IndexIsExec execution.length 
                  by (metis One_nat_def)
                have "¬ enabled (fe (Suc index) ! (nMsg - 1)) msg 
                  ∨ msg = ft (Suc index) ! (nMsg - 1)"
                  using AssumptionSubset3(6) AssumpOcc6(1) by blast
                moreover have "fe (Suc index) ! (nMsg - 1) 
                  = fe index ! (nMsg - 1)"
                  using SameCfgOnLow SmallIndex AssumptionSubset(3) 
                  by (metis less_imp_diff_less)
                moreover have "ft (Suc index) ! (nMsg - 1) 
                  = ft index ! (nMsg - 1)"
                  using SameMsgOnLow SmallIndexTrace by metis 
                ultimately have "¬ enabled (fe index ! (nMsg - 1)) msg 
                  ∨ msg = ft index ! (nMsg - 1)"
                  by simp
                thus False using AssumpOcc6 by blast
              qed
              show ?thesis using IndexIsExec Occ1 Occ2 SmallIndex 
                AssumptionSubset(3) Occ4 Occ5 Occ6
                execution.firstOccurrence_def[of "trans" "sends" "start"
                  "fe index" "ft index"]
                by simp 
            qed
            have "execution.firstOccurrence (fe index) (ft index) 
              msgInSet n1" 
              using AssumptionSubset2 AssumptionSubset(1)
            proof-
              have Occ1': "∃p. isReceiverOf p msgInSet" 
                using AssumptionSubset2(1) by blast                 
              have Occ3': "n1 < length (fe index)" 
                using SmallIndex AssumptionSubset(3) AssumptionSubset(1)
                by (metis le_less_trans)
              have "(fe index) ! n1 = (fe (Suc index)) ! n1"
                using Occ3' PrefixSameOnLow[of "fe index" 
                  "fe (Suc index)"] BasicProperties by simp
              hence Occ4': "enabled (fe index ! n1) msgInSet" 
                using AssumptionSubset2(4) by simp
              have OccSameMsg': "∀ n' ≥ n1 . n' < length (ft index) 
                ⟶ (ft index) ! n' = (ft (Suc index)) ! n'" 
                using PrefixSameOnLow BasicProperties by auto
              hence Occ5': "∀n' ≥ n1. n' < length (ft index) 
                ⟶ msgInSet ≠ ft index ! n'" 
                using AssumptionSubset2(5) ShorterTrace by simp
              have "length (fe index) > 0" using NotEmpty(2) 
                by (metis length_greater_0_conv)
              hence "length (fe index) - 1 < length (fe index)" 
                by (metis One_nat_def diff_Suc_less)                  
              hence 
                "enabled (fe index ! (length (fe index) - 1)) msgInSet
                ∨ (∃n0'≥n1. n0' < length (ft index) ∧ ft index ! n0'
                  = msgInSet)"
                using Occ4' Occ3' MessageStaysOrConsumed[of "n1" 
                  "length (fe index) - 1" "index" "msgInSet"]
                by (metis Suc_pred' ‹0 < length (fe index)› 
                  not_le not_less_eq_eq)
              hence "enabled ((fe index) ! (length (fe index) - 1)) 
                msgInSet" 
                using Occ5' by auto
              hence Occ2': "enabled (last (fe index)) msgInSet" 
                using last_conv_nth[of "fe index"] NotEmpty(2) by simp
              have Occ6': "n1 ≠ 0 ⟶ ¬ enabled (fe index ! (n1 - 1)) 
                msgInSet ∨ msgInSet = ft index ! (n1 - 1)"
              proof(clarify)
                assume AssumpOcc6': "0 < n1" "msgInSet ≠ ft index ! 
                  (n1 - 1)" "enabled (fe index ! (n1 - 1)) msgInSet"
                have "n1 - (Suc 0) < length (fe index) - (Suc 0)" 
                  using Occ3' AssumpOcc6'(1) 
                  by (metis Suc_le_eq diff_less_mono)
                hence SmallIndexTrace': "n1 - 1 < length (ft index)" 
                  using IndexIsExec execution.length 
                  by (metis One_nat_def)
                have "¬ enabled (fe (Suc index) ! (n1 - 1)) msgInSet 
                  ∨ msgInSet = ft (Suc index) ! (n1 - 1)"
                  using AssumptionSubset2(6) AssumpOcc6'(1) by blast
                moreover have "fe (Suc index) ! (n1 - 1) 
                  = fe index ! (n1 - 1)"
                  using SameCfgOnLow Occ3' by (metis less_imp_diff_less)
                moreover have "ft (Suc index) ! (n1 - 1) 
                  = ft index ! (n1 - 1)"
                  using SameMsgOnLow SmallIndexTrace' by metis 
                ultimately have "¬ enabled (fe index ! 
                  (n1 - 1)) msgInSet ∨ msgInSet = ft index ! (n1 - 1)"
                  by simp
                thus False using AssumpOcc6' by blast
              qed
              show ?thesis using IndexIsExec Occ1' Occ2' Occ3' Occ4' 
                Occ5' Occ6'
                execution.firstOccurrence_def[of "trans" "sends" 
                  "start" "fe index" "ft index"]
                by simp  
            qed
            
            thus "∃nMsg' n1'. n1' ≤ nMsg' 
              ∧ execution.firstOccurrence (fe index) (ft index) 
                msgInSet n1' 
              ∧ execution.firstOccurrence (fe index) (ft index) 
                msg nMsg'" 
              using FirstOccurrenceMsg AssumptionSubset(1) by blast
          qed
          have ProperSubset: "∃ msg' .msg' ∈ firstOccSet index 
            ∧ msg' ∉ firstOccSet (Suc index)"
          proof-               
            have "initial (hd (fe index))" using AssumptionFair(1) 
              by blast
            hence "∃msg'. execution.minimalEnabled (fe index) (ft index)
              msg' ∧  msg' ∈ set (drop (length (ft index)) 
                (fStepMsg (fe index) (ft index)))" 
              using FStep fe_def ft_def
                BasicProperties by simp
            then obtain consumedMsg where ConsumedMsg: 
              "execution.minimalEnabled (fe index) (ft index) 
                consumedMsg"
              "consumedMsg ∈ set (drop (length (ft index)) 
                (fStepMsg (fe index) (ft index)))" by blast
            hence ConsumedIsInDrop:
              "consumedMsg ∈ set (drop (length (ft index)) (ft (Suc index)))"
              using fe_def ft_def FStep
                BasicProperties[rule_format, of index]
              by auto
            
            have MinImplAllBigger: "⋀ msg' . execution.minimalEnabled
            (fe index) (ft index) msg' 
             ⟶ (∃ OccM' . (execution.firstOccurrence (fe index) 
              (ft index) msg' OccM' )
                ∧ (∀ msg . ∀ OccM . execution.firstOccurrence (fe index)
                  (ft index) msg OccM 
                ⟶ OccM' ≤ OccM))" 
            proof(auto)
              fix msg'
              assume AssumpMinImplAllBigger: "execution.minimalEnabled 
                (fe index) (ft index) msg'"
              have IsExecIndex: "execution trans sends start 
                (fe index) (ft index)" 
                using  BasicProperties[rule_format, of index] by simp
              have "(∃ p . isReceiverOf p msg') ∧ 
                (enabled (last (fe index)) msg')
                ∧ (∃ n .  n < length (fe index) 
                  ∧ enabled ( (fe index) ! n) msg' 
                  ∧ (∀ n' ≥ n . n' < length (ft index) 
                  ⟶ msg' ≠ ((ft index)! n'))
                  ∧ (∀ n' msg' . ((∃ p . isReceiverOf p msg') 
                    ∧ (enabled (last (fe index)) msg') 
                    ∧ n' < length (ft index) 
                    ∧ enabled ((fe index)! n') msg' 
                    ∧ (∀ n'' ≥ n' . n'' < length (ft index) 
                    ⟶ msg' ≠ ((ft index) ! n''))) ⟶ n' ≥ n))" 
              using execution.minimalEnabled_def[of trans sends start 
                "(fe index)" "(ft index)" msg'] 
                AssumpMinImplAllBigger IsExecIndex by auto
              then obtain OccM' where OccM': 
                "(∃ p . isReceiverOf p msg')" 
                "(enabled (last (fe index)) msg')"
                "OccM' < length (fe index)" 
                "enabled ( (fe index) ! OccM') msg'"  
                "(∀ n' ≥ OccM' . n' < length (ft index) 
                ⟶ msg' ≠ ((ft index)! n'))"
                "(∀ n' msg' . ((∃ p . isReceiverOf p msg') 
                  ∧ (enabled (last (fe index)) msg') 
                  ∧ n' < length (ft index) 
                  ∧ enabled ((fe index)! n') msg' 
                  ∧ (∀ n'' ≥ n' . n'' < length (ft index) 
                  ⟶ msg' ≠ ((ft index) ! n''))) ⟶ n' ≥ OccM')" 
                by blast                  
              have "0 < OccM' ⟹ enabled (fe index ! (OccM' - Suc 0)) msg' 
                      ⟹ msg' ≠ ft index ! (OccM' - Suc 0) ⟹ False"
              proof(-)
                fix p
                assume AssumpContr: 
                  "0 < OccM'"
                  "enabled (fe index ! (OccM' - Suc 0)) msg'"
                  "msg' ≠ ft index ! (OccM' - Suc 0)"
                have LengthOccM': "(OccM' - 1) < length (ft index)" 
                using OccM'(3) IndexIsExec AssumpContr(1)   
                  AssumptionFair(1)
                  by (metis  One_nat_def Suc_diff_1 Suc_eq_plus1_left 
                    Suc_less_eq le_add_diff_inverse)
                have BiggerIndices: "(∀n''≥(OccM' - 1). 
                  n'' < length (ft index) ⟶ msg' ≠ ft index ! n'')"
                  using OccM'(5) by (metis AssumpContr(3) One_nat_def 
                      Suc_eq_plus1 diff_Suc_1 le_SucE le_diff_conv)
                have "(∃p. isReceiverOf p msg') ∧ enabled (last 
                  (fe index)) msg' ∧ (OccM' - 1) < length (ft index)
                    ∧ enabled (fe index ! (OccM' - 1)) msg' 
                    ∧ (∀n''≥(OccM' - 1). n'' < length (ft index) 
                      ⟶ msg' ≠ ft index ! n'')" 
                  using OccM' LengthOccM' AssumpContr BiggerIndices 
                  by simp
                hence "OccM' ≤ OccM' - 1" using OccM'(6) by blast 
                thus False using AssumpContr(1) diff_less leD zero_less_one by blast
              qed
              hence FirstOccMsg': "execution.firstOccurrence (fe index)
                  (ft index) msg' OccM'"   
                unfolding execution_def
                  execution.firstOccurrence_def[OF IsExecIndex, of msg' OccM']
                by (auto simp add: OccM'(1,2,3,4,5))
              have "∀msg OccM. execution.firstOccurrence (fe index) 
                (ft index) msg OccM ⟶ OccM' ≤ OccM" 
              proof clarify
                fix msg OccM
                assume  "execution.firstOccurrence (fe index) 
                  (ft index) msg OccM"
                hence AssumpOccMFirstOccurrence: 
                  "∃ p . isReceiverOf p msg" 
                  "enabled (last (fe index)) msg" 
                  "OccM < (length (fe index))"
                  "enabled ((fe index) ! OccM) msg" 
                  "(∀ n' ≥ OccM . n' < length (ft index) 
                  ⟶ msg ≠ ((ft index) ! n'))"
                  "(OccM ≠ 0 ⟶ (¬ enabled ((fe index) ! (OccM - 1)) 
                  msg ∨ msg = (ft index)!(OccM - 1)))"
                  by (auto simp add: execution.firstOccurrence_def[of 
                      trans sends start "(fe index)" "(ft index)" 
                      msg OccM] IsExecIndex)
                hence "(∃p. isReceiverOf p msg) ∧
                  enabled (last (fe index)) msg ∧
                  enabled (fe index ! OccM) msg ∧ 
                  (∀n''≥ OccM. n'' < length (ft index) 
                    ⟶ msg ≠ ft index ! n'')" 
                 by simp
                thus "OccM' ≤ OccM" using OccM' 
                proof(cases "OccM < length (ft index)",auto)
                  assume "¬ OccM < length (ft index)"
                  hence "OccM ≥ length (fe index) - 1" 
                    using AssumptionFair(1) by (metis One_nat_def leI)
                  hence "OccM = length (fe index) - 1"
                    using AssumpOccMFirstOccurrence(3) by simp
                  thus "OccM' ≤ OccM" using OccM'(3) by simp
                qed
              qed
              with FirstOccMsg' show "∃OccM'. 
                execution.firstOccurrence (fe index) (ft index) 
                  msg' OccM' 
                ∧ (∀msg OccM. execution.firstOccurrence (fe index) 
                  (ft index) msg OccM ⟶ OccM' ≤ OccM)" by blast
            qed
            have MinImplFirstOcc: "⋀ msg' . execution.minimalEnabled 
              (fe index) (ft index) msg' 
              ⟹ msg' ∈ firstOccSet index"
            proof -
              fix msg'
              assume AssumpMinImplFirstOcc: 
                "execution.minimalEnabled (fe index) (ft index) msg'"
              then obtain OccM' where OccM': 
                "execution.firstOccurrence (fe index) (ft index) 
                  msg' OccM'"
                "∀ msg . ∀ OccM . execution.firstOccurrence 
                (fe index) (ft index) msg OccM 
              ⟶ OccM' ≤ OccM" using MinImplAllBigger by blast
              thus "msg' ∈ firstOccSet index" using OccM' 
              proof (auto simp add: firstOccSet_def)
                have "enabled (last (fe index)) msg" 
                  using AssumptionFirstOccSetDecrOrConsumed(1) by blast
                hence "∃nMsg .  execution.firstOccurrence (fe index) 
                  (ft index) msg nMsg"
                  using execution.FirstOccurrenceExists IndexIsExec 
                  AssumptionFair(4) by blast
                then obtain nMsg where NMsg: "execution.firstOccurrence
                  (fe index) (ft index) msg nMsg" by blast
                hence "OccM' ≤ nMsg" using OccM' by simp
                hence "∃nMsg . OccM' ≤ nMsg ∧
                  execution.firstOccurrence (fe index) (ft index) msg'
                    OccM' ∧
                  execution.firstOccurrence (fe index) (ft index) msg 
                    nMsg" 
                  using OccM'(1) NMsg by blast 
                thus "∃nMsg n1 . n1 ≤ nMsg ∧
                  execution.firstOccurrence (fe index) (ft index) 
                    msg' n1 ∧
                  execution.firstOccurrence (fe index) (ft index) 
                    msg nMsg" by blast
              qed
            qed
            hence ConsumedInSet: "consumedMsg ∈ firstOccSet index" 
              using ConsumedMsg by simp
            have GreaterOccurrence: "⋀ nMsg n1 . 
                execution.firstOccurrence (fe (Suc index)) 
                  (ft (Suc index)) consumedMsg n1 ∧ 
                execution.firstOccurrence (fe (Suc index)) 
                  (ft (Suc index)) msg nMsg 
                ⟹ nMsg < n1" 
            proof(rule ccontr,auto)
              fix nMsg n1
              assume AssumpGreaterOccurrence: "¬ nMsg < n1"
                "execution.firstOccurrence (fe (Suc index)) 
                  (ft (Suc index)) consumedMsg n1"
                "execution.firstOccurrence (fe (Suc index)) 
                  (ft (Suc index)) msg nMsg" 
              have "nMsg < length (fe index)" 
                using SmallIndex AssumpGreaterOccurrence(3) by simp
              hence "n1 < length (fe index)" 
                using AssumpGreaterOccurrence(1) 
                by (metis less_trans nat_neq_iff)
              hence N1Small: "n1 ≤ length (ft index)" 
                using IndexIsExec AssumptionFair(1) 
                by (metis  One_nat_def Suc_eq_plus1 le_diff_conv2 
                  not_le not_less_eq_eq)
              have NotConsumed: "∀ i ≥ n1 . i < length (ft (Suc index))
                ⟶ consumedMsg ≠ (ft (Suc index)) ! i" 
                using execution.firstOccurrence_def[of "trans" "sends"
                  "start" "fe (Suc index)" "ft (Suc index)" 
                  "consumedMsg" "n1"]
                  AssumpGreaterOccurrence(2) SucIndexIsExec by auto
              have "∃ i ≥ length (ft index) . 
                i < length (ft (Suc index)) 
                ∧ consumedMsg = (ft (Suc index)) ! i"
                using DropToIndex[of "consumedMsg" "length (ft index)"]
                ConsumedIsInDrop by simp
              then obtain i where IDef: "i ≥ length (ft index)"
                "i < length (ft (Suc index))" 
                "consumedMsg = (ft (Suc index)) ! i" by blast
              thus False using NotConsumed N1Small by simp
            qed
            have "consumedMsg ∉ firstOccSet (Suc index)" 
            proof(clarify)
              assume AssumpConsumedInSucSet: 
                "consumedMsg ∈ firstOccSet (Suc index)"
              hence "∃nMsg n1. n1 ≤ nMsg ∧
                  execution.firstOccurrence (fe (Suc index)) 
                    (ft (Suc index)) consumedMsg n1 ∧ 
                  execution.firstOccurrence (fe (Suc index)) 
                    (ft (Suc index)) msg nMsg" 
                using firstOccSet_def by blast
              thus False using GreaterOccurrence 
                by (metis less_le_trans less_not_refl3)
            qed
            thus ?thesis using ConsumedInSet by blast
          qed
          hence "firstOccSet (Suc index) ⊂ firstOccSet index" 
            using Subset by blast
          thus "firstOccSet (Suc index) ⊂ firstOccSet index 
            ∧ enabled (last (fe (Suc index))) msg"
            using EnabledInSuc by blast
        qed
        have NotConsumed: "∀ index ≥ n . ¬ msg ∈ 
          (set (drop (length (ft index)) (ft (Suc index))))"
        proof(clarify)
          fix index
          assume AssumpMsgNotConsumed: "n ≤ index" 
            "msg ∈ set (drop (length (ft index)) (ft (Suc index)))"
          have "∃ n0' ≥ length (ft index) . 
            n0' < length (ft (Suc index)) 
            ∧ msg = (ft (Suc index)) ! n0'" 
            using AssumpMsgNotConsumed(2) DropToIndex[of "msg" 
              "length (ft index)" "ft (Suc index)"] by auto
          then obtain n0' where MessageIndex: "n0' ≥ length (ft index)" 
            "n0' < length (ft (Suc index))" 
            "msg = (ft (Suc index)) ! n0'" by blast
          have LengthIncreasing: "length (ft n) ≤ length (ft index)" 
            using AssumpMsgNotConsumed(1) 
          proof(induct index,auto)
            fix indexa
            assume AssumpLengthIncreasing: 
              "n ≤ indexa ⟹ length (ft n) ≤ length (ft indexa)" 
              "n ≤ Suc indexa" "n ≤ index"
            show "length (ft n) ≤ length (ft (Suc indexa))"
            proof(cases "n = Suc indexa",auto)
              assume "n ≠ Suc indexa"
              hence "n ≤ indexa" using AssumpLengthIncreasing(2) 
                by (metis le_SucE)
              hence LengthNA: "length (ft n) ≤ length (ft indexa)" 
                using AssumpLengthIncreasing(1) by blast
              have PrefixIndexA: "prefixList (ft indexa) (ft (Suc indexa))"
                using BasicProperties by simp
              show "length (ft n) ≤ length (ft (Suc indexa))"
                using LengthNA PrefixListMonotonicity[OF PrefixIndexA]
                by (metis (opaque_lifting, no_types) antisym le_cases 
                  less_imp_le less_le_trans)
            qed
          qed
          thus False using AssumptionFairContr MessageIndex 
            AssumpMsgNotConsumed(1) 
            by (metis ‹length (ft index) ≤ n0'› le_SucI le_trans)
        qed
        hence FirstOccSetDecrImpl: 
          "∀ index ≥ n . (enabled (last (fe index)) msg) 
          ⟶ firstOccSet (Suc index) ⊂ firstOccSet index 
            ∧ (enabled (last (fe (Suc index))) msg)"
          using FirstOccSetDecrOrConsumed by blast
        hence FirstOccSetDecrImpl: "∀ index ≥ n . firstOccSet 
          (Suc index) ⊂ firstOccSet index"
          using KeepProperty[of "n" "λx.(enabled (last (fe x)) msg)" 
            "λx.(firstOccSet (Suc x) ⊂ firstOccSet x)"]
            AssumptionCase1ImplThesis' by blast
        hence FirstOccSetDecr': "∀ index ≥ n . 
          card (firstOccSet (Suc index)) < card (firstOccSet index)"
          using FiniteMsgs psubset_card_mono by metis
        hence "card (firstOccSet (n + (card (firstOccSet n) + 1))) 
          ≤ card (firstOccSet n) - (card (firstOccSet n) + 1)"
          using SmallerMultipleStepsWithLimit[of "n" 
            "λx. card (firstOccSet x)" "card (firstOccSet n) + 1"]
          by blast
        hence IsNegative:"card (firstOccSet (n + (card 
          (firstOccSet n) + 1))) < 0" 
          by (metis FirstOccSetDecr' diff_add_zero leD le_add1 
            less_nat_zero_code neq0_conv)
        thus False by (metis less_nat_zero_code)
      qed
    qed
    hence Case1ImplThesis: "enabled (last (fe n)) msg 
      ⟹ (∃n'≥n. ∃n0'≥n0. n0' < length (ft n') ∧ msg = ft n' ! n0')"
      using AssumptionFair(2) execution.length[of trans sends start 
        "fe n" "ft n"] BasicProperties 
      by (metis One_nat_def Suc_eq_plus1 Suc_lessI leI le_less_trans 
        less_asym less_diff_conv)
    show "∃n'≥n. ∃n0'≥n0. n0' < length (ft n') ∧ msg = ft n' ! n0'"
    using disjE[OF EnabledOrConsumedAtLast Case1ImplThesis Case2ImplThesis] .
  qed
  show ?thesis proof (rule exI[of _ fe], rule exI[of _ ft])
    show "fe 0 = [cfg] ∧ fairInfiniteExecution fe ft 
      ∧ (∀n. nonUniform (last (fe n)) ∧ prefixList (fe n) (fe (n + 1)) 
          ∧ prefixList (ft n) (ft (n + 1))
          ∧ execution trans sends start (fe n) (ft n))"
    using Fair fe_def FStep BasicProperties by auto
  qed
qed
subsection ‹Contradiction›
text ‹
  An infinite execution is said to be a terminating FLP execution if each process
  at some point sends a decision message or if it stops, which is expressed
  by the process not processing any further messages.
›
definition (in flpSystem) terminationFLP::
  "(nat ⇒ ('p, 'v, 's) configuration list) 
  ⇒ (nat ⇒ ('p, 'v) message list) ⇒ bool"
where
  "terminationFLP fe ft ≡ infiniteExecution fe ft ⟶ 
  (∀ p . ∃ n .
     (∃ i0 < length (ft n). ∃ b . 
      (<⊥, outM b> ∈# sends p (states ((fe n) ! i0) p) (unpackMessage ((ft n) ! i0)))
      ∧ isReceiverOf p ((ft n) ! i0))
  ∨ (∀ n1 > n . ∀ m ∈ set (drop (length (ft n)) (ft n1)) . ¬ isReceiverOf p m))"
theorem ConsensusFails:
assumes 
  Termination:
    "⋀ fe ft . (fairInfiniteExecution fe ft ⟹ terminationFLP fe ft)" and
  Validity: "∀ i c . validity i c" and
  Agreement: "∀ i c . agreementInit i c"
shows
  "False"
proof -
  obtain cfg where Cfg: "initial cfg" "nonUniform cfg"
    using InitialNonUniformCfg[OF PseudoTermination Validity Agreement] 
        by blast
  obtain fe:: "nat ⇒ ('p, 'v, 's) configuration list" and
              ft:: "nat ⇒ ('p, 'v) message list"
    where FE: "(fe 0) = [cfg]" "fairInfiniteExecution fe ft"
        "(∀(n::nat) . nonUniform (last (fe n)) 
          ∧ prefixList (fe n) (fe (n+1)) 
          ∧ prefixList (ft n) (ft (n+1))
          ∧ (execution trans sends start (fe n) (ft n)))" 
    using FairNonUniformExecution[OF Cfg] 
    by blast
  have AllArePrefixesExec: "∀ m . ∀ n > m . prefixList (fe m) (fe n)"
  proof(clarify)
    fix m::nat and n::nat
    assume MLessN: "m < n"
    have "prefixList (fe m) (fe n)" using MLessN 
    proof(induct n, simp)
      fix n
      assume IA: "(m < n) ⟹ (prefixList (fe m) (fe n))" "m < (Suc n)"
      have "m = n ∨ m < n" using IA(2) by (metis less_SucE)
      thus "prefixList (fe m) (fe (Suc n))"
      proof(cases "m = n", auto)
        show "prefixList (fe n) (fe (Suc n))" using FE by simp
      next
        assume "m < n"
        hence IA2: "prefixList (fe m) (fe n)" using IA(1) by simp
        have "prefixList (fe n) (fe (n+1))" using FE by simp
        thus "prefixList (fe m) (fe (Suc n))" using PrefixListTransitive 
          IA2 by simp
      qed
    qed
    thus "prefixList (fe m) (fe n)" by simp
  qed
  have AllArePrefixesTrace: "∀ m . ∀ n > m . prefixList (ft m) (ft n)"
  proof(clarify)
    fix m::nat and n::nat
    assume MLessN: "m < n"
    have "prefixList (ft m) (ft n)" using MLessN
    proof(induct n, simp)
      fix n
      assume IA: "(m < n) ⟹ (prefixList (ft m) (ft n))" "m < (Suc n)"
      have "m = n ∨ m < n" using IA(2) by (metis less_SucE)
      thus "prefixList (ft m) (ft (Suc n))"
      proof(cases "m = n", auto)
        show "prefixList (ft n) (ft (Suc n))" using FE by simp
      next
        assume "m < n"
        hence IA2: "prefixList (ft m) (ft n)" using IA(1) by simp
        have "prefixList (ft n) (ft (n+1))" using FE by simp
        thus "prefixList (ft m) (ft (Suc n))" using PrefixListTransitive 
          IA2 by simp
      qed
    qed
    thus "prefixList (ft m) (ft n)" by simp
  qed
  have Length: "∀ n . length (fe n) ≥ n + 1" 
  proof(clarify)
    fix n
    show "length (fe n) ≥ n + 1" 
    proof(induct n, simp add: FE(1))
      fix n
      assume IH: "(n + (1::nat)) ≤ (length (fe n))"
      have "length (fe (n+1)) ≥ length (fe n) + 1" using FE(3) 
        PrefixListMonotonicity
        by (metis Suc_eq_plus1 Suc_le_eq)
      thus "(Suc n) + (1::nat) ≤ (length (fe (Suc n)))" using IH by auto
    qed
  qed
  have AllExecsFromInit: "∀ n . ∀ n0 < length (fe n) . 
    reachable cfg ((fe n) ! n0)"
  proof(clarify)
    fix n::nat and n0::nat
    assume "n0 < length (fe n)"
    thus "reachable cfg ((fe n) ! n0)"
    proof(cases "0 = n", auto)
      assume N0Less: "n0 < length (fe 0)"
      have NoStep: "reachable cfg cfg" using reachable.simps by blast 
      have "length (fe 0) = 1" using FE(1) by simp
      hence N0Zero: "n0 = 0" using N0Less FE by simp
      hence "(fe 0) ! n0 = cfg" using FE(1) by simp
      thus "reachable cfg ((fe 0) ! n0)" using FE(1) NoStep N0Zero by simp
    next
      assume NNotZero: "0 < n" "n0 < (length (fe n))"
      have ZeroCfg: "(fe 0) = [cfg]" using FE by simp
      have "prefixList (fe 0) (fe n)" using AllArePrefixesExec NNotZero 
        by simp
      hence PrList: "prefixList [cfg] (fe n)" using ZeroCfg by simp
      have CfgFirst: "cfg = (fe n) ! 0"
        using prefixList.cases[OF PrList]
        by (metis (full_types) ZeroCfg list.distinct(1) nth_Cons_0)
      have "reachable ((fe n) ! 0) ((fe n) ! n0)"
        using execution.ReachableInExecution FE NNotZero(2) by (metis le0)
      thus "(reachable cfg ((fe n) ! n0))" using assms CfgFirst by simp
    qed
  qed
  have NoDecided: "(∀ n n0 v . (n0 < length (fe n)) 
                  ⟶ ¬ vDecided v ((fe n) ! n0))" 
  proof(clarify)
    fix n n0 v
    assume AssmNoDecided: "n0 < length (fe n)" 
      "initReachable ((fe n) ! n0)"
      "0 < (msgs ((fe n) ! n0) <⊥, outM v>)"
    have LastNonUniform: "nonUniform (last (fe n))" using FE by simp
    have LastIsLastIndex: "⋀ l . l ≠ [] ⟶ last l = l ! ((length l) - 1)" 
      by (metis last_conv_nth)
    have Fou: "n0 ≤ length (fe n) - 1" using AssmNoDecided by simp
    have FeNNotEmpty:"fe n ≠ []" using FE(1) AllArePrefixesExec 
      by (metis AssmNoDecided(1) less_nat_zero_code list.size(3))
    hence Fou2: "length (fe n) - 1 < length (fe n)" by simp
    have "last (fe n) = (fe n) ! (length (fe n) - 1)" 
      using LastIsLastIndex FeNNotEmpty by auto
    have LastNonUniform: "nonUniform (last (fe n))" using FE by simp 
    have "reachable ((fe n) ! n0) ((fe n) ! (length (fe n) - 1))" 
      using FE execution.ReachableInExecution Fou Fou2 by metis
    hence N0ToLast: "reachable ((fe n) ! n0) (last (fe n))" 
      using LastIsLastIndex[of "fe n"] FeNNotEmpty by simp
    hence LastVDecided: "vDecided v (last (fe n))" 
      using NoOutMessageLoss[of "((fe n) ! n0)" "(last (fe n))"] 
        AssmNoDecided
      by (simp,
        metis LastNonUniform le_neq_implies_less less_nat_zero_code neq0_conv)
    have AllAgree: "∀ cfg' . reachable (last (fe n)) cfg' 
      ⟶ agreement cfg'" 
    proof(clarify)
      fix cfg'
      assume LastToNext: "reachable (last (fe n)) cfg'"
      hence "reachable cfg  ((fe n) ! (length (fe n) - 1))" 
        using AllExecsFromInit AssmNoDecided(1) by auto
      hence "reachable cfg (last (fe n))" using LastIsLastIndex[of "fe n"] 
        FeNNotEmpty by simp
      hence FirstToLast: "reachable cfg cfg'" using initReachable_def Cfg 
        LastToNext ReachableTrans by blast
      hence "agreementInit cfg cfg'" using Agreement by simp
      hence "∀v1. (<⊥, outM v1> ∈# msgs cfg') ⟶ (∀v2. (<⊥, outM v2> ∈# 
        msgs cfg') ⟷ v2 = v1)"
        using Cfg FirstToLast
        by (simp add: agreementInit_def)
      thus "agreement cfg'" by (simp add: agreement_def)
    qed
    thus "False" using NonUniformImpliesNotDecided LastNonUniform 
      PseudoTermination LastVDecided by simp
  qed
  have Termination: "terminationFLP fe ft" using assms(1)[OF FE(2)] .
  hence AllDecideOrCrash: 
    "∀p. ∃n . 
       (∃ i0 < length (ft n) . ∃b. 
          (<⊥, outM b> ∈# 
            sends p (states (fe n ! i0) p) (unpackMessage (ft n ! i0))) 
          ∧ isReceiverOf p (ft n ! i0)) 
      ∨ (∀ n1 > n . ∀ m ∈ (set (drop (length (ft n)) (ft n1))) .
          ¬ isReceiverOf p m)"
    using FE(2)
    unfolding terminationFLP_def fairInfiniteExecution_def 
    by blast
  have "∀ p . ∃ n . (∀ n1 > n . ∀ m ∈ (set (drop (length (ft n)) (ft n1))) .
    ¬ isReceiverOf p m)"
  proof(clarify)
    fix p
    from AllDecideOrCrash have
    "∃ n . 
       (∃ i0 < length (ft n) . ∃b. 
        (<⊥, outM b> ∈# sends p (states (fe n ! i0) p) (unpackMessage (ft n ! i0))) 
       ∧ isReceiverOf p (ft n ! i0)) 
      ∨ (∀ n1 > n . ∀ m ∈ (set (drop (length (ft n)) (ft n1))). 
        ¬ isReceiverOf p m)" by simp
    hence "(∃ n . ∃ i0 < length (ft n) . 
         (∃b. (<⊥, outM b> ∈# 
            sends p (states (fe n ! i0) p) (unpackMessage (ft n ! i0))) 
          ∧ isReceiverOf p (ft n ! i0)))
         ∨ (∃ n .∀ n1 > n . ∀ m ∈ (set (drop (length (ft n)) (ft n1))) .
           ¬ isReceiverOf p m)" by blast
    thus "∃n. (∀n1>n. (∀ m ∈ (set (drop (length (ft n)) (ft n1))).
      (¬ (isReceiverOf p m))))"
    proof(elim disjE, auto)
      fix n i0 b
      assume DecidingPoint:
        "i0 < length (ft n)"
        "isReceiverOf p (ft n ! i0)"
        "<⊥, outM b> ∈# sends p (states (fe n ! i0) p) (unpackMessage (ft n ! i0))"
      have "i0 < length (fe n) - 1"
        using DecidingPoint(1)
        by (metis (no_types) FE(3) execution.length) 
      hence StepN0: "((fe n) ! i0) ⊢ ((ft n) ! i0) ↦ ((fe n) ! (i0 + 1))" 
        using FE by (metis execution.step)
      hence "msgs ((fe n) ! (i0 + 1)) <⊥, outM b> 
        = (msgs ((fe n) ! i0) <⊥, outM b>) +
        (sends p (states ((fe n) ! i0) p) 
        (unpackMessage ((ft n) ! i0)) <⊥, outM b>)" 
        using DecidingPoint(2) OutOnlyGrowing[of "(fe n) ! i0" "(ft n) ! i0"
          "(fe n) ! (i0 + 1)" "p"] 
        by auto
      hence "(sends p (states ((fe n) ! i0) p) 
        (unpackMessage ((ft n) ! i0)) <⊥, outM b>) 
        ≤ msgs ((fe n) ! (i0 + 1)) <⊥, outM b>" 
        using asynchronousSystem.steps_def by auto
      hence OutMsgEx: "0 < msgs ((fe n) ! (i0 + 1)) <⊥, outM b>" 
        using asynchronousSystem.steps_def DecidingPoint(3) by auto
      have "(i0 + 1) < length (fe n)"
        using DecidingPoint(1) ‹i0 < length (fe n) - 1› by auto
      hence "initReachable ((fe n) ! (i0 + 1))" 
        using AllExecsFromInit Cfg(1) 
        by (metis asynchronousSystem.initReachable_def)
      hence Decided: "vDecided b ((fe n) ! (i0 + 1))" using OutMsgEx 
        by auto
      have "i0 + 1 < length (fe n)" using DecidingPoint(1) 
        by (metis ‹(((i0::nat) + (1::nat)) < (length (
          (fe::(nat ⇒ ('p, 'v, 's) configuration list)) (n::nat))))›)
      hence "¬ vDecided b ((fe n) ! (i0 + 1))" using NoDecided by auto
      hence "False" using Decided by auto
      thus "∃n. (∀n1>n. (∀ m ∈ (set (drop (length (ft n)) (ft n1))). 
        (¬ (isReceiverOf p m))))" by simp
    qed
  qed
  hence "∃ (crashPoint::'p ⇒ nat) . 
    ∀ p . ∃  n . crashPoint p = n ∧ (∀ n1 > n . ∀ m ∈ (set (drop 
    (length (ft n)) (ft n1))) . (¬ isReceiverOf p m))" by metis  
  then obtain crashPoint where CrashPoint:
    "∀ p . (∀ n1 > (crashPoint p) . ∀ m ∈ (set (drop (length 
    (ft (crashPoint p))) (ft n1))) . (¬ isReceiverOf p m))"
    by blast
  define limitSet where "limitSet = {crashPoint p | p . p ∈ Proc}"
  have "finite {p. p ∈ Proc}" using finiteProcs by simp
  hence "finite limitSet" using limitSet_def finite_image_set[] by blast
  hence "∃ limit . ∀ l ∈ limitSet . l < limit" using 
    finite_nat_set_iff_bounded by auto
  hence "∃ limit . ∀ p . (crashPoint p) < limit" using limitSet_def by auto
  then obtain limit where Limit: "∀ p . (crashPoint p) < limit" by blast
  define lengthLimit where "lengthLimit = length (ft limit) - 1"
  define lateMessage where "lateMessage = last (ft limit)"
  hence "lateMessage = (ft limit) ! (length (ft limit) - 1)" 
    by (metis AllArePrefixesTrace Limit last_conv_nth less_nat_zero_code 
      list.size(3) PrefixListMonotonicity)
  hence LateIsLast: "lateMessage = (ft limit) ! lengthLimit" 
  using lateMessage_def lengthLimit_def by auto
  have "∃ p . isReceiverOf p lateMessage" 
  proof(rule ccontr)
    assume "¬ (∃(p::'p). (isReceiverOf p lateMessage))"
    hence IsOutMsg: "∃ v . lateMessage = <⊥, outM v>"
      by (metis isReceiverOf.simps(1) isReceiverOf.simps(2) message.exhaust)
    have "execution trans sends start (fe limit) (ft limit)" using FE 
      by auto
    hence "length (fe limit) - 1 = length (ft limit)"
      using execution.length by simp
    hence "lengthLimit < length (fe limit) - 1" 
      using lengthLimit_def 
      by (metis (opaque_lifting, no_types) Length Limit One_nat_def Suc_eq_plus1
        Suc_le_eq diff_less 
        diffs0_imp_equal gr_implies_not0 less_Suc0 neq0_conv)
    hence "((fe limit) ! lengthLimit) ⊢ ((ft limit) ! lengthLimit) 
      ↦ ((fe limit) ! (lengthLimit + 1))"
      using FE by (metis execution.step)
    hence "((fe limit) ! lengthLimit) ⊢ lateMessage ↦ ((fe limit) ! 
      (lengthLimit + 1))"
      using LateIsLast by auto
    thus False using IsOutMsg steps_def by auto
  qed
  then obtain p where ReceiverOfLate: "isReceiverOf p lateMessage" by blast
  have "∀ n1 > (crashPoint p) . 
    ∀ m ∈ (set (drop (length (ft (crashPoint p))) (ft n1))) . 
      (¬ isReceiverOf p m)"
    using CrashPoint
    by simp
  hence NoMsgAfterLimit: "∀ m ∈ (set (drop (length (ft (crashPoint p))) 
    (ft limit))) . (¬ isReceiverOf p m)"
    using Limit
    by auto
  have "lateMessage ∈ set (drop (length(ft (crashPoint p))) (ft limit))" 
  proof-
    have "crashPoint p < limit" using Limit by simp
    hence "prefixList (ft (crashPoint p)) (ft limit)" 
      using AllArePrefixesTrace by auto
    hence CrashShorterLimit: "length (ft (crashPoint p)) 
      < length (ft limit)" using PrefixListMonotonicity by auto
    hence "last (drop (length (ft (crashPoint p))) (ft limit)) 
      = last (ft limit)" by (metis last_drop)
    hence "lateMessage = last (drop (length (ft (crashPoint p))) 
      (ft limit))" using lateMessage_def by auto
    thus "lateMessage ∈ set (drop (length(ft (crashPoint p))) (ft limit))" 
      by (metis CrashShorterLimit drop_eq_Nil last_in_set not_le)
  qed
  
  hence "¬ isReceiverOf p lateMessage" using NoMsgAfterLimit by auto
  thus "False" using ReceiverOfLate by simp
qed
end
end