theory Semantics_Goto
imports Main Firewall_Common "Common/List_Misc" "~~/src/HOL/Library/LaTeXsugar"
begin

section\<open>Big Step Semantics with Goto\<close>
text\<open>
  We extend the iptables semantics to support the goto action.
  A goto directly continues processing at the start of the called chain.
  It does not change the call stack.
  In contrast to calls, goto does not return.
  Consequently, everything behind a matching goto cannot be reached.
\<close>
text\<open>
  This theory is structured as follows.
  Fist, the goto semantics are introduced.
  Then, we show that those semantics are deterministic.
  Finally, we present two methods to remove gotos.
   The first unfolds goto.
   The second replaces gotos with calls.
  Finally, since the goto rules makes all proofs quite ugly, we never mention the goto semantics again.
  As we have shown, we can get rid of the gotos easily, thus, we stick to the nicer iptables semantics without goto.
\<close>

context
begin

  subsection\<open>Semantics\<close>
    private type_synonym 'a ruleset = "string \<rightharpoonup> 'a rule list"

    private type_synonym ('a, 'p) matcher = "'a \<Rightarrow> 'p \<Rightarrow> bool"

    qualified fun matches :: "('a, 'p) matcher \<Rightarrow> 'a match_expr \<Rightarrow> 'p \<Rightarrow> bool" where
      "matches \<gamma> (MatchAnd e1 e2) p \<longleftrightarrow> matches \<gamma> e1 p \<and> matches \<gamma> e2 p" |
      "matches \<gamma> (MatchNot me) p \<longleftrightarrow> \<not> matches \<gamma> me p" |
      "matches \<gamma> (Match e) p \<longleftrightarrow> \<gamma> e p" |
      "matches _ MatchAny _ \<longleftrightarrow> True"

    (*
    main:
      call foo
      deny-all
    foo:
      goto bar
    bar:
      [nothing]

    The call returns, even if a goto is executed in the called chains. The deny-all will be executed!

    Chain OUTPUT (policy ACCEPT 98 packets, 34936 bytes)
     pkts bytes target     prot opt in     out     source               destination
        1    84            all  --  *      *       0.0.0.0/0            127.42.0.1
        1    84 foo        all  --  *      *       0.0.0.0/0            127.42.0.1
        1    84            all  --  *      *       0.0.0.0/0            127.42.0.1

    Chain bar (1 references)
     pkts bytes target     prot opt in     out     source               destination

    Chain foo (1 references)
     pkts bytes target     prot opt in     out     source               destination
        1    84 bar        all  --  *      *       0.0.0.0/0            0.0.0.0/0           [goto]

    *)
    qualified fun no_matching_Goto :: "('a, 'p) matcher \<Rightarrow> 'p \<Rightarrow> 'a rule list \<Rightarrow> bool" where
      "no_matching_Goto _ _ [] \<longleftrightarrow> True" |
      "no_matching_Goto \<gamma> p ((Rule m (Goto _))#rs) \<longleftrightarrow> \<not> matches \<gamma> m p \<and> no_matching_Goto \<gamma> p rs" |
      "no_matching_Goto \<gamma> p (_#rs) \<longleftrightarrow> no_matching_Goto \<gamma> p rs"

    inductive iptables_goto_bigstep :: "'a ruleset \<Rightarrow> ('a, 'p) matcher \<Rightarrow> 'p \<Rightarrow> 'a rule list \<Rightarrow> state \<Rightarrow> state \<Rightarrow> bool"
      ("_,_,_\<turnstile>\<^sub>g \<langle>_, _\<rangle> \<Rightarrow> _"  [60,60,60,20,98,98] 89)
      for \<Gamma> and \<gamma> and p where
    skip:    "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[], t\<rangle> \<Rightarrow> t" |
    accept:  "matches \<gamma> m p \<Longrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m Accept], Undecided\<rangle> \<Rightarrow> Decision FinalAllow" |
    drop:    "matches \<gamma> m p \<Longrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m Drop], Undecided\<rangle> \<Rightarrow> Decision FinalDeny" |
    reject:  "matches \<gamma> m p \<Longrightarrow>  \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m Reject], Undecided\<rangle> \<Rightarrow> Decision FinalDeny" |
    log:     "matches \<gamma> m p \<Longrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m Log], Undecided\<rangle> \<Rightarrow> Undecided" |
    empty:   "matches \<gamma> m p \<Longrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m Empty], Undecided\<rangle> \<Rightarrow> Undecided" |
    nomatch: "\<not> matches \<gamma> m p \<Longrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m a], Undecided\<rangle> \<Rightarrow> Undecided" |
    decision: "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs, Decision X\<rangle> \<Rightarrow> Decision X" |
    seq:      "\<lbrakk>\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs\<^sub>1, Undecided\<rangle> \<Rightarrow> t; \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs\<^sub>2, t\<rangle> \<Rightarrow> t'; no_matching_Goto \<gamma> p rs\<^sub>1\<rbrakk> \<Longrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs\<^sub>1@rs\<^sub>2, Undecided\<rangle> \<Rightarrow> t'" |
    call_return:  "\<lbrakk> matches \<gamma> m p; \<Gamma> chain = Some (rs\<^sub>1@[Rule m' Return]@rs\<^sub>2);
                     matches \<gamma> m' p; \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs\<^sub>1, Undecided\<rangle> \<Rightarrow> Undecided;
                     no_matching_Goto \<gamma> p rs\<^sub>1\<rbrakk> \<Longrightarrow>
                     (*we do not support a goto in the first part if you want to return
                     probably unhandled case:
                     main:
                       call foo
                     foo:
                       goto bar
                     bar:
                       Return //returns to `call foo'
                     But this would be a really awkward ruleset!
                     *)
                   \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m (Call chain)], Undecided\<rangle> \<Rightarrow> Undecided" |
    call_result:  "\<lbrakk> matches \<gamma> m p; \<Gamma> chain = Some rs; \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs, Undecided\<rangle> \<Rightarrow> t \<rbrakk> \<Longrightarrow>
                   \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m (Call chain)], Undecided\<rangle> \<Rightarrow> t" | (*goto handling here seems okay*)
    goto_decision:  "\<lbrakk> matches \<gamma> m p; \<Gamma> chain = Some rs; \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs, Undecided\<rangle> \<Rightarrow> Decision X \<rbrakk> \<Longrightarrow>
                   \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>(Rule m (Goto chain))#rest, Undecided\<rangle> \<Rightarrow> Decision X" |
    goto_no_decision:  "\<lbrakk> matches \<gamma> m p; \<Gamma> chain = Some rs; \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs, Undecided\<rangle> \<Rightarrow> Undecided \<rbrakk> \<Longrightarrow>
                   \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>(Rule m (Goto chain))#rest, Undecided\<rangle> \<Rightarrow> Undecided"

    text\<open>
    The semantic rules again in pretty format:
    \begin{center}
    @{thm[mode=Axiom] skip [no_vars]}\\[1ex]
    @{thm[mode=Rule] accept [no_vars]}\\[1ex]
    @{thm[mode=Rule] drop [no_vars]}\\[1ex]
    @{thm[mode=Rule] reject [no_vars]}\\[1ex]
    @{thm[mode=Rule] log [no_vars]}\\[1ex]
    @{thm[mode=Rule] empty [no_vars]}\\[1ex]
    @{thm[mode=Rule] nomatch [no_vars]}\\[1ex]
    @{thm[mode=Rule] decision [no_vars]}\\[1ex]
    @{thm[mode=Rule] seq [no_vars]} \\[1ex]
    @{thm[mode=Rule] call_return [no_vars]}\\[1ex]
    @{thm[mode=Rule] call_result [no_vars]}\\[1ex]
    @{thm[mode=Rule] goto_decision [no_vars]}\\[1ex]
    @{thm[mode=Rule] goto_no_decision [no_vars]}
    \end{center}
\<close>

    private lemma deny:
      "matches \<gamma> m p \<Longrightarrow> a = Drop \<or> a = Reject \<Longrightarrow> iptables_goto_bigstep \<Gamma> \<gamma> p [Rule m a] Undecided (Decision FinalDeny)"
    by (auto intro: drop reject)

    private lemma iptables_goto_bigstep_induct
      [case_names
        Skip Allow Deny Log Nomatch Decision Seq Call_return Call_result Goto_Decision Goto_no_Decision,
       induct pred: iptables_goto_bigstep]:
    "\<lbrakk> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs,s\<rangle> \<Rightarrow> t;
       \<And>t. P [] t t;
       \<And>m a. matches \<gamma> m p \<Longrightarrow> a = Accept \<Longrightarrow> P [Rule m a] Undecided (Decision FinalAllow);
       \<And>m a. matches \<gamma> m p \<Longrightarrow> a = Drop \<or> a = Reject \<Longrightarrow> P [Rule m a] Undecided (Decision FinalDeny);
       \<And>m a. matches \<gamma> m p \<Longrightarrow> a = Log \<or> a = Empty \<Longrightarrow> P [Rule m a] Undecided Undecided;
       \<And>m a. \<not> matches \<gamma> m p \<Longrightarrow> P [Rule m a] Undecided Undecided;
       \<And>rs X. P rs (Decision X) (Decision X);
       \<And>rs rs\<^sub>1 rs\<^sub>2 t t'. rs = rs\<^sub>1 @ rs\<^sub>2 \<Longrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs\<^sub>1,Undecided\<rangle> \<Rightarrow> t \<Longrightarrow> P rs\<^sub>1 Undecided t \<Longrightarrow>
                          \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs\<^sub>2,t\<rangle> \<Rightarrow> t' \<Longrightarrow> P rs\<^sub>2 t t' \<Longrightarrow> no_matching_Goto \<gamma> p rs\<^sub>1 \<Longrightarrow>
                          P rs Undecided t';
       \<And>m a chain rs\<^sub>1 m' rs\<^sub>2. matches \<gamma> m p \<Longrightarrow> a = Call chain \<Longrightarrow>
                              \<Gamma> chain = Some (rs\<^sub>1 @ [Rule m' Return] @ rs\<^sub>2) \<Longrightarrow>
                              matches \<gamma> m' p \<Longrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs\<^sub>1,Undecided\<rangle> \<Rightarrow> Undecided \<Longrightarrow>
                              no_matching_Goto \<gamma> p rs\<^sub>1 \<Longrightarrow>  P rs\<^sub>1 Undecided Undecided \<Longrightarrow>
                              P [Rule m a] Undecided Undecided;
       \<And>m a chain rs t. matches \<gamma> m p \<Longrightarrow> a = Call chain \<Longrightarrow> \<Gamma> chain = Some rs \<Longrightarrow>
                         \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs,Undecided\<rangle> \<Rightarrow> t \<Longrightarrow> P rs Undecided t \<Longrightarrow> P [Rule m a] Undecided t;
       \<And>m a chain rs rest X. matches \<gamma> m p \<Longrightarrow> a = Goto chain \<Longrightarrow> \<Gamma> chain = Some rs \<Longrightarrow>
                              \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs,Undecided\<rangle> \<Rightarrow> (Decision X) \<Longrightarrow> P rs Undecided (Decision X) \<Longrightarrow>
                              P (Rule m a#rest) Undecided (Decision X);
       \<And>m a chain rs rest. matches \<gamma> m p \<Longrightarrow> a = Goto chain \<Longrightarrow> \<Gamma> chain = Some rs \<Longrightarrow>
                           \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs,Undecided\<rangle> \<Rightarrow> Undecided \<Longrightarrow> P rs Undecided Undecided \<Longrightarrow>
                           P (Rule m a#rest) Undecided Undecided\<rbrakk> \<Longrightarrow>
     P rs s t"
    by (induction rule: iptables_goto_bigstep.induct) auto

  subsubsection\<open>Forward reasoning\<close>

    private lemma decisionD: "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>r, s\<rangle> \<Rightarrow> t \<Longrightarrow> s = Decision X \<Longrightarrow> t = Decision X"
      by (induction rule: iptables_goto_bigstep_induct) auto

    private lemma iptables_goto_bigstep_to_undecided: "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs, s\<rangle> \<Rightarrow> Undecided \<Longrightarrow> s = Undecided"
      by (metis decisionD state.exhaust)

    private lemma iptables_goto_bigstep_to_decision: "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs, Decision Y\<rangle> \<Rightarrow> Decision X \<Longrightarrow> Y = X"
      by (metis decisionD state.inject)

    private lemma skipD: "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>r, s\<rangle> \<Rightarrow> t \<Longrightarrow> r = [] \<Longrightarrow> s = t"
      by (induction rule: iptables_goto_bigstep.induct) auto

    private lemma gotoD: "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>r, s\<rangle> \<Rightarrow> t \<Longrightarrow> r = [Rule m (Goto chain)] \<Longrightarrow> s = Undecided \<Longrightarrow> matches \<gamma> m p \<Longrightarrow>
                    \<exists> rs. \<Gamma> chain = Some rs \<and> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs,s\<rangle> \<Rightarrow> t"
      by (induction rule: iptables_goto_bigstep.induct) (auto dest: skipD elim: list_app_singletonE)

    private lemma not_no_matching_Goto_singleton_cases: "\<not> no_matching_Goto \<gamma> p [Rule m a] \<longleftrightarrow> (\<exists> chain. a = (Goto chain)) \<and> matches \<gamma> m p"
      by(case_tac a) (simp_all)

    private lemma no_matching_Goto_Cons: "no_matching_Goto \<gamma> p [r] \<Longrightarrow> no_matching_Goto \<gamma> p rs \<Longrightarrow> no_matching_Goto \<gamma> p (r#rs)"
      by(cases r)(rename_tac m a, case_tac a, simp_all)

    private lemma no_matching_Goto_head: "no_matching_Goto \<gamma> p (r#rs) \<Longrightarrow> no_matching_Goto \<gamma> p [r]"
      by(cases r)(rename_tac m a, case_tac a, simp_all)
    private lemma no_matching_Goto_tail: "no_matching_Goto \<gamma> p (r#rs) \<Longrightarrow> no_matching_Goto \<gamma> p rs"
      by(cases r)(rename_tac m a, case_tac a, simp_all)

    private lemma not_no_matching_Goto_cases:
      assumes "\<not> no_matching_Goto \<gamma> p rs" "rs \<noteq> []"
      shows "\<exists>rs1 m chain rs2. rs = rs1@(Rule m (Goto chain))#rs2 \<and> no_matching_Goto \<gamma> p rs1 \<and> matches \<gamma> m p"
        using assms
        proof(induction rs)
        case Nil thus ?case by simp
        next
        case (Cons r rs)
          note Cons_outer=this
          from Cons have "\<not> no_matching_Goto \<gamma> p (r # rs)" by simp
          show ?case
          proof(cases rs)
          case Nil
            obtain m a where "r = Rule m a" by (cases r) simp
            with \<open>\<not> no_matching_Goto \<gamma> p (r # rs)\<close> Nil not_no_matching_Goto_singleton_cases have "(\<exists> chain. a = (Goto chain)) \<and> matches \<gamma> m p" by metis
            from this obtain chain where "a = (Goto chain)" and "matches \<gamma> m p" by blast
            have "r # rs = [] @ Rule m (Goto chain) # []" "no_matching_Goto \<gamma> p []" "matches \<gamma> m p"
              by (simp_all add: \<open>a = Goto chain\<close> \<open>r = Rule m a\<close> Nil \<open>matches \<gamma> m p\<close>)
            thus ?thesis by blast
          next
          case(Cons r' rs')
            with Cons_outer have "r # rs =  r # r' # rs'" by simp
            show ?thesis
            proof(cases"no_matching_Goto \<gamma> p [r]")
            case True
              with \<open>\<not> no_matching_Goto \<gamma> p (r # rs)\<close> have "\<not> no_matching_Goto \<gamma> p rs" by (meson no_matching_Goto_Cons)
              have "rs \<noteq> []" using Cons by simp
              from Cons_outer(1)[OF \<open>\<not> no_matching_Goto \<gamma> p rs\<close> \<open>rs \<noteq> []\<close>]
                obtain rs1 m chain rs2 where "rs = rs1 @ Rule m (Goto chain) # rs2" "no_matching_Goto \<gamma> p rs1" "matches \<gamma> m p" by blast
              with \<open>r # rs =  r # r' # rs'\<close> \<open>no_matching_Goto \<gamma> p [r]\<close> no_matching_Goto_Cons
                  have "r # rs = r # rs1 @ Rule m (Goto chain) # rs2 \<and> no_matching_Goto \<gamma> p (r#rs1) \<and> matches \<gamma> m p" by fast
              thus ?thesis
                apply(rule_tac x="r#rs1" in exI)
                by auto
            next
            case False
              obtain m a where "r = Rule m a" by (cases r) simp
              with False not_no_matching_Goto_singleton_cases have "(\<exists> chain. a = (Goto chain)) \<and> matches \<gamma> m p" by metis
              from this obtain chain where "a = (Goto chain)" and "matches \<gamma> m p" by blast
              have "r # rs = [] @ Rule m (Goto chain) # rs" "no_matching_Goto \<gamma> p []" "matches \<gamma> m p"
                by (simp_all add: \<open>a = Goto chain\<close> \<open>r = Rule m a\<close> \<open>matches \<gamma> m p\<close>)
              thus ?thesis by blast
            qed
          qed
        qed

    private lemma seq_cons_Goto_Undecided:
      assumes "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m (Goto chain)], Undecided\<rangle> \<Rightarrow> Undecided"
      and "\<not> matches \<gamma> m p \<Longrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs, Undecided\<rangle> \<Rightarrow> Undecided"
      shows "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>Rule m (Goto chain) # rs, Undecided\<rangle> \<Rightarrow> Undecided"
      proof(cases "matches \<gamma> m p")
        case True
          from True assms have "\<exists>rs. \<Gamma> chain = Some rs \<and> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs, Undecided\<rangle> \<Rightarrow> Undecided" by(auto dest: gotoD)
          with True show ?thesis using goto_no_decision by fast
      next
        case False
        with assms have " \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m (Goto chain)] @ rs, Undecided\<rangle> \<Rightarrow> Undecided" by(auto dest: seq)
        with False show ?thesis by simp
      qed

    private lemma seq_cons_Goto_t:
      "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m (Goto chain)], Undecided\<rangle> \<Rightarrow> t \<Longrightarrow> matches \<gamma> m p \<Longrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>Rule m (Goto chain) # rs, Undecided\<rangle> \<Rightarrow> t"
       apply(frule gotoD)
          apply(simp_all)
       apply(clarify)
       apply(cases t)
        apply(auto intro: iptables_goto_bigstep.intros)
    done

    private lemma no_matching_Goto_append: "no_matching_Goto \<gamma> p (rs1@rs2) \<longleftrightarrow> no_matching_Goto \<gamma> p rs1 \<and>  no_matching_Goto \<gamma> p rs2"
      by(induction \<gamma> p rs1 rule: no_matching_Goto.induct) (simp_all)

    private lemma no_matching_Goto_append1: "no_matching_Goto \<gamma> p (rs1@rs2) \<Longrightarrow> no_matching_Goto \<gamma> p rs1"
      using no_matching_Goto_append by fast
    private lemma no_matching_Goto_append2: "no_matching_Goto \<gamma> p (rs1@rs2) \<Longrightarrow> no_matching_Goto \<gamma> p rs2"
      using no_matching_Goto_append by fast

    private lemma seq_cons:
      assumes "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[r],Undecided\<rangle> \<Rightarrow> t" and "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs,t\<rangle> \<Rightarrow> t'" and "no_matching_Goto \<gamma> p [r]"
      shows "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>r#rs, Undecided\<rangle> \<Rightarrow> t'"
      proof -
        from assms have "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[r] @ rs, Undecided\<rangle> \<Rightarrow> t'" by (rule seq)
        thus ?thesis by simp
      qed

    context
      notes skipD[dest] list_app_singletonE[elim]
    begin
      lemma acceptD: "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>r, s\<rangle> \<Rightarrow> t \<Longrightarrow> r = [Rule m Accept] \<Longrightarrow> matches \<gamma> m p \<Longrightarrow> s = Undecided \<Longrightarrow> t = Decision FinalAllow"
      by (induction rule: iptables_goto_bigstep.induct) auto

  qualified fun rewrite_Goto_chain_safe :: "(string \<rightharpoonup> 'a rule list) \<Rightarrow> 'a rule list \<Rightarrow> ('a rule list) option" where
    "rewrite_Goto_chain_safe _ [] = Some []" |
    "rewrite_Goto_chain_safe \<Gamma> ((Rule m (Goto chain))#rs) =
      (case (\<Gamma> chain) of None     \<Rightarrow> None
                      |  Some rs' \<Rightarrow> (if
                                         \<not> terminal_chain rs'
                                      then
                                         None
                                      else
                                         map_option (\<lambda>rs. Rule m (Call chain) # rs) (rewrite_Goto_chain_safe \<Gamma> rs)
                                     )
      )" |
    "rewrite_Goto_chain_safe \<Gamma> (r#rs) = map_option (\<lambda>rs. r # rs) (rewrite_Goto_chain_safe \<Gamma> rs)"

  private fun rewrite_Goto_safe_internal
    :: "(string \<times> 'a rule list) list \<Rightarrow> (string \<times> 'a rule list) list \<Rightarrow> (string \<times> 'a rule list) list option" where
    "rewrite_Goto_safe_internal _ [] = Some []" |
    "rewrite_Goto_safe_internal \<Gamma> ((chain_name, rs)#cs) =
                (case rewrite_Goto_chain_safe (map_of \<Gamma>) rs of
                         None \<Rightarrow> None
                       | Some rs' \<Rightarrow> map_option (\<lambda>rst. (chain_name, rs')#rst) (rewrite_Goto_safe_internal \<Gamma> cs)
                )"

  qualified fun rewrite_Goto_safe :: "(string \<times> 'a rule list) list \<Rightarrow> (string \<times> 'a rule list) list option" where
    "rewrite_Goto_safe cs = rewrite_Goto_safe_internal cs cs"

  (*use rewrite_Goto_chain_safe whenever possible!*)
  qualified definition rewrite_Goto :: "(string \<times> 'a rule list) list \<Rightarrow> (string \<times> 'a rule list) list" where
    "rewrite_Goto cs = the (rewrite_Goto_safe cs)"

  private lemma step_IH_cong: "(\<And>s. \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs1, s\<rangle> \<Rightarrow> t = \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs2, s\<rangle> \<Rightarrow> t) \<Longrightarrow>
         \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>r#rs1, s\<rangle> \<Rightarrow> t = \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>r#rs2, s\<rangle> \<Rightarrow> t"
  apply(rule iffI)
   apply(erule seqE_cons)
    apply(rule seq'_cons)
      apply simp_all
   apply(drule not_no_matching_Goto_cases)
    apply(simp; fail)
   apply(elim exE conjE, rename_tac rs1a m chain rs2a)
   apply(subgoal_tac "r = Rule m (Goto chain)")
    prefer 2
    subgoal by (simp add: Cons_eq_append_conv)
   apply(thin_tac "[r] = _ @ Rule m (Goto chain) # _")
   apply simp
   apply (metis decision decisionD seq_cons_Goto_t state.exhaust)
  apply(erule seqE_cons)
   apply(rule seq'_cons)
     apply simp_all
  apply(drule not_no_matching_Goto_cases)
   apply(simp; fail)
  apply(elim exE conjE, rename_tac rs1a m chain rs2a)
  apply(subgoal_tac "r = Rule m (Goto chain)")
   prefer 2
   subgoal by (simp add: Cons_eq_append_conv)
  apply(thin_tac "[r] = _ @ Rule m (Goto chain) # _")
  apply simp
  apply (metis decision decisionD seq_cons_Goto_t state.exhaust)
  done

  private lemma terminal_chain_decision:
    "terminal_chain rs \<Longrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs, Undecided\<rangle> \<Rightarrow> t \<Longrightarrow> \<exists>X. t = Decision X"
    apply(induction rs arbitrary: t rule: terminal_chain.induct)
                                         apply simp_all
                                    apply(auto dest: iptables_goto_bigstepD)[3]
                                 apply(erule seqE_cons, simp_all, blast dest: iptables_goto_bigstepD)+ (*6s*)
    done

  private lemma terminal_chain_Goto_decision: "\<Gamma> chain = Some rs \<Longrightarrow> terminal_chain rs \<Longrightarrow> matches \<gamma> m p \<Longrightarrow>
       \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m (Goto chain)], s\<rangle> \<Rightarrow> t \<Longrightarrow> \<exists>X. t = Decision X"
    apply(cases s)
     apply(drule gotoD, simp_all)
     apply(elim exE conjE, simp_all)
     using terminal_chain_decision apply fast
    by (meson decisionD)

  qualified theorem rewrite_Goto_chain_safe:
    "rewrite_Goto_chain_safe \<Gamma> rs = Some rs' \<Longrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs', s\<rangle> \<Rightarrow> t \<longleftrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs, s\<rangle> \<Rightarrow> t"
  proof(induction \<Gamma> rs arbitrary: rs' s rule: rewrite_Goto_chain_safe.induct)
  case 1 thus ?case by (simp split: option.split_asm if_split_asm)
  next
  case (2 \<Gamma> m chain rs)
    from 2(2) obtain z x2 where "\<Gamma> chain = Some x2" and "terminal_chain x2"
            and "rs' = Rule m (Call chain) # z"
            and "Some z = rewrite_Goto_chain_safe \<Gamma> rs"
    by(auto split: option.split_asm if_split_asm)
    from 2(1) \<open>\<Gamma> chain = Some x2\<close> \<open>terminal_chain x2\<close> \<open>Some z = rewrite_Goto_chain_safe \<Gamma> rs\<close>
      have IH: "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>z, s\<rangle> \<Rightarrow> t = \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs, s\<rangle> \<Rightarrow> t" for s by simp

    have "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>Rule m (Call chain) # z, Undecided\<rangle> \<Rightarrow> t \<longleftrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>Rule m (Goto chain) # rs, Undecided\<rangle> \<Rightarrow> t"
          (is "?lhs \<longleftrightarrow> ?rhs")
    proof(intro iffI)
      assume ?lhs
      with IH obtain ti where ti1: "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m (Call chain)], Undecided\<rangle> \<Rightarrow> ti" and ti2: "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>rs, ti\<rangle> \<Rightarrow> t"
        by(auto elim: seqE_cons)
      show ?rhs
      proof(cases "matches \<gamma> m p")
      case False
        from replace_Goto_with_Call_in_terminal_chain \<open>\<Gamma> chain = Some x2\<close> \<open>terminal_chain x2\<close>
        have " \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m (Call chain)], Undecided\<rangle> \<Rightarrow> ti \<longleftrightarrow> \<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m (Goto chain)], Undecided\<rangle> \<Rightarrow> ti"
          by fast
        with False ti1 ti2 show ?thesis by(rule_tac t=ti in seq'_cons) simp+
      next
      case True
        from ti1 \<open>\<Gamma> chain = Some x2\<close> \<open>terminal_chain x2\<close>
        have g: "\<Gamma>,\<gamma>,p\<turnstile>\<^sub>g \<langle>[Rule m (Goto chain)], Undecided\<rangle> \<Rightarrow> ti"
          by(subst(asm) replace_Goto_with_Call_in_terminal_chain[symmetric]) simp+
        with True \<open>\<Gamma> chain = Some x2\<close> \<open>terminal_chain x2\<close> obtain X where X: "ti = Decision X"
          by(blast dest: terminal_chain_Goto_decision)
        with this ti2 have "t = Decision X"
          by(simp add: decisionD)
        with g X True ti2 \<open>\<Gamma> chain = Some x2\<close> \<open>terminal_chain x2\<close> show ?thesis
          apply(simp)
          apply(rule seq_cons_Goto_t, simp_all)
          done
      qed
    next
      assume ?rhs
      with IH \<open>\<Gamma> chain = Some x2\<close> \<open>terminal_chain x2\<close> \<open>Some z = rewrite_Goto_chain_safe \<Gamma> rs\<close> show ?lhs
        apply -
        apply(erule seqE_cons)
         subgoal for ti
         apply simp_all
         apply(rule_tac t=ti in seq'_cons)
           apply simp_all
         using replace_Goto_with_Call_in_terminal_chain by fast
        apply simp
        apply(frule(3) terminal_chain_Goto_decision)
        apply(subst(asm) replace_Goto_with_Call_in_terminal_chain, simp_all)
        apply(rule seq'_cons, simp_all)
        apply(elim exE)
        by (simp add: decision)
    qed
    with \<open>rs' = Rule m (Call chain) # z\<close> show ?case
      apply -
      apply(rule just_show_all_bigstep_semantics_equalities_with_start_Undecided)
      by simp

  qed(auto cong: step_IH_cong)

  text\<open>Example: The semantics are actually defined (for this example).\<close>
  lemma defines "\<gamma> \<equiv> (\<lambda>_ _. True)" and "m \<equiv> MatchAny"
  shows "[''FORWARD'' \<mapsto> [Rule m Log, Rule m (Call ''foo''), Rule m Drop],
          ''foo'' \<mapsto> [Rule m Log, Rule m (Goto ''bar''), Rule m Reject],
          ''bar'' \<mapsto> [Rule m (Goto ''baz''), Rule m Reject],
          ''baz'' \<mapsto> [(Rule m Accept)]],
      \<gamma>,p\<turnstile>\<^sub>g\<langle>[Rule MatchAny (Call ''FORWARD'')], Undecided\<rangle> \<Rightarrow> (Decision FinalAllow)"
  apply(subgoal_tac "matches \<gamma> m p")
   prefer 2
   apply(simp add: \<gamma>_def m_def; fail)
  apply(rule call_result)
    apply(auto)
  apply(rule_tac t=Undecided in seq_cons)
    apply(auto intro: log)
  apply(rule_tac t="Decision FinalAllow" in seq_cons)
    apply(auto intro: decision)
  apply(rule call_result)
     apply(simp)+
  apply(rule_tac t=Undecided in seq_cons)
    apply(auto intro: log)
  apply(rule goto_decision)
    apply(simp)+
  apply(rule goto_decision)
    apply(simp)+
  apply(auto intro: accept)
  done

end

end


(*
 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
 *
 * SPDX-License-Identifier: BSD-2-Clause
 *)

theory ArchArraysMemInstance
imports ArraysMemInstance
begin

(* Showing arrays are in mem_type requires maximum sizes for objects,
   and maximum counts for elements *)
class array_outer_max_size = mem_type +
  assumes array_outer_max_size_ax: "size_of TYPE('a::c_type) < 2 ^ 19"

class array_max_count = finite +
  assumes array_max_count_ax: "CARD ('a) <= 2 ^ 13"

instance array :: (array_outer_max_size, array_max_count) mem_type
apply intro_classes
apply simp
apply (subgoal_tac "addr_card = 2 ^ (addr_bitsize - 19) * 2 ^ 19")
  apply (erule ssubst)
  apply (rule less_le_trans[where y = "card (UNIV::'b set) * 2 ^ 19"])
    apply (rule mult_less_mono2)
      apply (rule array_outer_max_size_ax)
    apply simp
  apply (rule mult_le_mono1)
    apply (rule le_trans[where j = "2 ^ 13"])
      apply (rule array_max_count_ax)
    apply simp
  apply simp
apply (simp add: addr_card)
done

class array_inner_max_size = array_outer_max_size +
  assumes array_inner_max_size_ax: "size_of TYPE('a::c_type) < 2 ^ 6"

instance array :: (array_inner_max_size, array_max_count) array_outer_max_size
apply intro_classes
apply simp
  apply (rule order_less_le_trans)
   apply (rule mult_le_less_imp_less)
    apply (rule array_max_count_ax)
   apply (rule array_inner_max_size_ax)
  apply simp
   apply simp
  apply simp
  done

instance word :: (len8) array_outer_max_size
apply intro_classes
apply(simp add: size_of_def)
apply(subgoal_tac "len_of TYPE('a) \<le> 128")
 apply simp
apply(rule len8_width)
done

instance word :: (len8) array_inner_max_size
apply intro_classes
apply(simp add: size_of_def)
apply(subgoal_tac "len_of TYPE('a) \<le> 128")
 apply simp
apply(rule len8_width)
done

instance ptr :: (c_type) array_outer_max_size
apply intro_classes
apply (simp add: size_of_def)
done

instance ptr :: (c_type) array_inner_max_size
apply intro_classes
apply (simp add: size_of_def)
done

class lt12 = finite +
  assumes lt12_ax: "CARD ('a) < 2 ^ 12"
class lt11 = lt12 +
  assumes lt11_ax: "CARD ('a) < 2 ^ 11"
class lt10 = lt11 +
  assumes lt10_ax: "CARD ('a) < 2 ^ 10"
class lt9 = lt10 +
  assumes lt9_ax: "CARD ('a) < 2 ^ 9"
class lt8 = lt9 +
  assumes lt8_ax: "CARD ('a) < 2 ^ 8"
class lt7 = lt8 +
  assumes lt7_ax: "CARD ('a) < 2 ^ 7"
class lt6 = lt7 +
  assumes lt6_ax: "CARD ('a) < 2 ^ 6"
class lt5 = lt6 +
  assumes lt5_ax: "CARD ('a) < 2 ^ 5"
class lt4 = lt5 +
  assumes lt4_ax: "CARD ('a) < 2 ^ 4"
class lt3 = lt4 +
  assumes lt3_ax: "CARD ('a) < 2 ^ 3"
class lt2 = lt3 +
  assumes lt2_ax: "CARD ('a) < 2 ^ 2"
class lt1 = lt2 +
  assumes lt1_ax: "CARD ('a) < 2 ^ 1"

instance bit0 :: (lt12) array_max_count
  using lt12_ax[where 'a='a] by intro_classes simp

instance bit1 :: (lt12) array_max_count
  using lt12_ax[where 'a='a] by intro_classes simp

instance bit0 :: (lt11) lt12
  using lt11_ax[where 'a='a] by intro_classes simp

instance bit1 :: (lt11) lt12
  using lt11_ax[where 'a='a] by intro_classes simp

instance bit0 :: (lt10) lt11
  using lt10_ax[where 'a='a] by intro_classes simp

instance bit1 :: (lt10) lt11
  using lt10_ax[where 'a='a] by intro_classes simp

instance bit0 :: (lt9) lt10
  using lt9_ax[where 'a='a] by intro_classes simp

instance bit1 :: (lt9) lt10
  using lt9_ax[where 'a='a] by intro_classes simp

instance bit0 :: (lt8) lt9
  using lt8_ax[where 'a='a] by intro_classes simp

instance bit1 :: (lt8) lt9
  using lt8_ax[where 'a='a] by intro_classes simp

instance bit0 :: (lt7) lt8
  using lt7_ax[where 'a='a] by intro_classes simp

instance bit1 :: (lt7) lt8
  using lt7_ax[where 'a='a] by intro_classes simp

instance bit0 :: (lt6) lt7
  using lt6_ax[where 'a='a] by intro_classes simp

instance bit1 :: (lt6) lt7
  using lt6_ax[where 'a='a] by intro_classes simp

instance bit0 :: (lt5) lt6
  using lt5_ax[where 'a='a] by intro_classes simp

instance bit1 :: (lt5) lt6
  using lt5_ax[where 'a='a] by intro_classes simp

instance bit0 :: (lt4) lt5
  using lt4_ax[where 'a='a] by intro_classes simp

instance bit1 :: (lt4) lt5
  using lt4_ax[where 'a='a] by intro_classes simp

instance bit0 :: (lt3) lt4
  using lt3_ax[where 'a='a] by intro_classes simp

instance bit1 :: (lt3) lt4
  using lt3_ax[where 'a='a] by intro_classes simp

instance bit0 :: (lt2) lt3
  using lt2_ax[where 'a='a] by intro_classes simp

instance bit1 :: (lt2) lt3
  using lt2_ax[where 'a='a] by intro_classes simp

instance bit0 :: (lt1) lt2
  using lt1_ax[where 'a='a] by intro_classes simp

instance bit1 :: (lt1) lt2
  using lt1_ax[where 'a='a] by intro_classes simp

instance num1 :: lt1
  by (intro_classes, simp_all)

(* don't understand why this also seems to be necessary *)
instance num1 :: array_max_count
  by (intro_classes, simp)

(* introduce hackish handling of 8192 type by making a copy of the type
   under a constructor, and then manually showing that it is an instance of
   array_max_count *)
datatype array_max_count_ty = array_max_count_ty "8192"

(* ML c-parser code also needs to know at which array size to use this type *)
ML \<open>
  structure ArchArrayMaxCount = struct
    val array_max_count = 8192
  end
\<close>

lemma univ_array_max_count_ty:
  "(UNIV::array_max_count_ty set) = image array_max_count_ty (UNIV::8192 set)"
  apply (simp add: set_eq_iff image_iff)
  apply (rule_tac allI)
  apply (rule_tac array_max_count_ty.induct)
  apply simp
  done

instance "array_max_count_ty" :: finite
  apply intro_classes
  apply (simp add: univ_array_max_count_ty)
  done

lemma card_array_max_count_ty[simp]: "CARD(array_max_count_ty) = CARD(8192)"
  apply (simp add: univ_array_max_count_ty card_image inj_on_def)
  done

instance "array_max_count_ty" :: array_max_count
  by intro_classes simp

end


theory Extra4
  imports ExtraInv VCTheoryLemmas
begin

theorem extra4: "VC4 extraInv s0 requestButton_value"
  apply(simp only: VC4_def extraInv_def)
proof
  assume " (toEnvP s0 \<and>
     (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = minimalRed \<longrightarrow>
           0 < ltimeEnv s1 Ctrl \<and> ltimeEnv s1 Ctrl \<le> MINIMAL_RED_TIME_LIMIT) \<and>
     (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = minimalRed \<longrightarrow>
           (\<exists>s2. toEnvP s2 \<and>
                 substate s2 s1 \<and>
                 toEnvNum s2 s1 = ltimeEnv s1 Ctrl \<and> getPstate s2 Ctrl = green \<and> ltimeEnv s2 Ctrl = GREEN_TIME_LIMIT) \<or>
           (\<forall>s2. toEnvP s2 \<and> substate s2 s1 \<longrightarrow> getPstate s2 Ctrl = minimalRed)) \<and>
     (\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and> substate s2 s0 \<and> getPstate s2 Ctrl = minimalRed \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl \<longrightarrow>
         getPstate s1 Ctrl = minimalRed) \<and>
     (\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and>
         substate s2 s0 \<and> (\<forall>s3. toEnvP s3 \<and> substate s1 s3 \<and> substate s3 s2 \<longrightarrow> getPstate s3 Ctrl = minimalRed) \<longrightarrow>
         toEnvNum s1 s2 = ltimeEnv s2 Ctrl - ltimeEnv s1 Ctrl) \<and>
     (\<forall>s1. toEnvP s1 \<and>
           substate s1 s0 \<and> getPstate s1 Ctrl = redAfterMinimalRed \<and> getVarBool s1 redAfterMinimalRed = NOT_PRESSED \<longrightarrow>
           (\<exists>s2. toEnvP s2 \<and>
                 substate s2 s1 \<and>
                 getPstate s2 Ctrl = minimalRed \<and>
                 ltimeEnv s2 Ctrl = MINIMAL_RED_TIME_LIMIT \<and>
                 getVarBool s2 redAfterMinimalRed = NOT_PRESSED \<and>
                 (\<forall>s3. toEnvP s3 \<and> substate s2 s3 \<and> substate s3 s1 \<and> s2 \<noteq> s3 \<longrightarrow>
                       getPstate s3 Ctrl = redAfterMinimalRed \<and>
                       getVarBool s3 redAfterMinimalRed = NOT_PRESSED \<and> getVarBool s3 Ctrl = NOT_PRESSED))) \<and>
     (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = redToGreen \<longrightarrow>
           0 < ltimeEnv s1 Ctrl \<and> ltimeEnv s1 Ctrl \<le> RED_TO_GREEN_TIME_LIMIT) \<and>
     (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = redToGreen \<longrightarrow>
           (\<exists>s2. toEnvP s2 \<and>
                 substate s2 s1 \<and>
                 toEnvNum s2 s1 = ltimeEnv s1 Ctrl \<and>
                 getPstate s2 Ctrl = redAfterMinimalRed \<and>
                 (getVarBool s2 redAfterMinimalRed = PRESSED \<or> getVarBool s2 Ctrl = PRESSED))) \<and>
     (\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and> substate s2 s0 \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl \<and> getPstate s2 Ctrl = redToGreen \<longrightarrow>
         getPstate s1 Ctrl = redToGreen) \<and>
     (\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and>
         substate s2 s0 \<and> (\<forall>s3. toEnvP s3 \<and> substate s1 s3 \<and> substate s3 s2 \<longrightarrow> getPstate s3 Ctrl = redToGreen) \<longrightarrow>
         toEnvNum s1 s2 = ltimeEnv s2 Ctrl - ltimeEnv s1 Ctrl) \<and>
     (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = green \<longrightarrow>
           0 < ltimeEnv s1 Ctrl \<and> ltimeEnv s1 Ctrl \<le> GREEN_TIME_LIMIT) \<and>
     (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = green \<longrightarrow>
           (\<exists>s2. toEnvP s2 \<and>
                 substate s2 s1 \<and>
                 toEnvNum s2 s1 = ltimeEnv s2 Ctrl \<and>
                 getPstate s2 Ctrl = redToGreen \<and> ltimeEnv s2 Ctrl = RED_TO_GREEN_TIME_LIMIT)) \<and>
     (\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and> substate s2 s0 \<and> getPstate s2 Ctrl = green \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl \<longrightarrow>
         getPstate s1 Ctrl = green) \<and>
     (\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and>
         substate s2 s0 \<and> (\<forall>s3. toEnvP s3 \<and> substate s1 s3 \<and> substate s3 s2 \<longrightarrow> getPstate s3 Ctrl = green) \<longrightarrow>
         toEnvNum s1 s2 = ltimeEnv s2 Ctrl - ltimeEnv s1 Ctrl) \<and>
     (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = green \<longrightarrow> getVarBool s1 minimalRed = PRESSED) \<and>
     (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl \<noteq> green \<longrightarrow> getVarBool s1 minimalRed = NOT_PRESSED) \<and>
     (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<longrightarrow>
           getPstate s1 Ctrl = minimalRed \<or>
           getPstate s1 Ctrl = redAfterMinimalRed \<or> getPstate s1 Ctrl = redToGreen \<or> getPstate s1 Ctrl = green) \<and>
     (\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and>
         substate s2 s0 \<and>
         toEnvNum s1 s2 < ltimeEnv s2 Ctrl - Ctrl \<and>
         getPstate s2 Ctrl = minimalRed \<and> getVarBool s2 redAfterMinimalRed = NOT_PRESSED \<longrightarrow>
         getVarBool s1 Ctrl = NOT_PRESSED) \<and>
     (\<forall>s2. toEnvP s2 \<and> substate s2 s0 \<and> getPstate s2 Ctrl = minimalRed \<and> getVarBool s2 redAfterMinimalRed = PRESSED \<longrightarrow>
           (\<exists>s1. toEnvP s1 \<and>
                 substate s1 s2 \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl - Ctrl \<and> getVarBool s1 Ctrl = PRESSED)) \<and>
     (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = redAfterMinimalRed \<and> getVarBool s1 redAfterMinimalRed \<longrightarrow>
           (\<exists>s2. toEnvP s2 \<and>
                 substate s2 s1 \<and>
                 toEnvNum s2 s1 = Ctrl \<and>
                 getPstate s2 Ctrl = minimalRed \<and>
                 ltimeEnv s2 Ctrl = MINIMAL_RED_TIME_LIMIT \<and>
                 (getVarBool s2 redAfterMinimalRed \<or> getVarBool s1 Ctrl = PRESSED))) \<and>
     (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = green \<longrightarrow>
           getVarBool s1 redAfterMinimalRed = NOT_PRESSED)) \<and>
    env (setVarAny s0 requestButton_value) requestButton_value \<and>
    getPstate (setVarAny s0 requestButton_value) Ctrl = minimalRed \<and>
    \<not> getVarBool (setVarAny s0 requestButton_value) Ctrl \<and>
    MINIMAL_RED_TIME_LIMIT \<le> ltimeEnv (setVarAny s0 requestButton_value) Ctrl"
then obtain ei0: "toEnvP s0"
and ei1: " (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = minimalRed \<longrightarrow>
           0 < ltimeEnv s1 Ctrl \<and> ltimeEnv s1 Ctrl \<le> MINIMAL_RED_TIME_LIMIT)"
and ei2: " (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = minimalRed \<longrightarrow>
           (\<exists>s2. toEnvP s2 \<and>
                 substate s2 s1 \<and>
                 toEnvNum s2 s1 = ltimeEnv s1 Ctrl \<and> getPstate s2 Ctrl = green \<and> ltimeEnv s2 Ctrl = GREEN_TIME_LIMIT) \<or>
           (\<forall>s2. toEnvP s2 \<and> substate s2 s1 \<longrightarrow> getPstate s2 Ctrl = minimalRed))"
and ei3: " (\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and> substate s2 s0 \<and> getPstate s2 Ctrl = minimalRed \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl \<longrightarrow>
         getPstate s1 Ctrl = minimalRed)"
and ei4: " (\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and>
         substate s2 s0 \<and> (\<forall>s3. toEnvP s3 \<and> substate s1 s3 \<and> substate s3 s2 \<longrightarrow> getPstate s3 Ctrl = minimalRed) \<longrightarrow>
         toEnvNum s1 s2 = ltimeEnv s2 Ctrl - ltimeEnv s1 Ctrl)"
and ei5: " (\<forall>s1. toEnvP s1 \<and>
           substate s1 s0 \<and> getPstate s1 Ctrl = redAfterMinimalRed \<and> getVarBool s1 redAfterMinimalRed = NOT_PRESSED \<longrightarrow>
           (\<exists>s2. toEnvP s2 \<and>
                 substate s2 s1 \<and>
                 getPstate s2 Ctrl = minimalRed \<and>
                 ltimeEnv s2 Ctrl = MINIMAL_RED_TIME_LIMIT \<and>
                 getVarBool s2 redAfterMinimalRed = NOT_PRESSED \<and>
                 (\<forall>s3. toEnvP s3 \<and> substate s2 s3 \<and> substate s3 s1 \<and> s2 \<noteq> s3 \<longrightarrow>
                       getPstate s3 Ctrl = redAfterMinimalRed \<and>
                       getVarBool s3 redAfterMinimalRed = NOT_PRESSED \<and> getVarBool s3 Ctrl = NOT_PRESSED)))"
and ei6:"(\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = redToGreen \<longrightarrow>
           0 < ltimeEnv s1 Ctrl \<and> ltimeEnv s1 Ctrl \<le> RED_TO_GREEN_TIME_LIMIT)"
and ei7: "(\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = redToGreen \<longrightarrow>
           (\<exists>s2. toEnvP s2 \<and>
                 substate s2 s1 \<and>
                 toEnvNum s2 s1 = ltimeEnv s1 Ctrl \<and>
                 getPstate s2 Ctrl = redAfterMinimalRed \<and>
                 (getVarBool s2 redAfterMinimalRed = PRESSED \<or> getVarBool s2 Ctrl = PRESSED)))"
and ei8: " (\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and> substate s2 s0 \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl \<and> getPstate s2 Ctrl = redToGreen \<longrightarrow>
         getPstate s1 Ctrl = redToGreen)"
and ei9: "(\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and>
         substate s2 s0 \<and> (\<forall>s3. toEnvP s3 \<and> substate s1 s3 \<and> substate s3 s2 \<longrightarrow> getPstate s3 Ctrl = redToGreen) \<longrightarrow>
         toEnvNum s1 s2 = ltimeEnv s2 Ctrl - ltimeEnv s1 Ctrl)"
and ei10: "(\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = green \<longrightarrow>
           0 < ltimeEnv s1 Ctrl \<and> ltimeEnv s1 Ctrl \<le> GREEN_TIME_LIMIT)"
and ei11: "(\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = green \<longrightarrow>
           (\<exists>s2. toEnvP s2 \<and>
                 substate s2 s1 \<and>
                 toEnvNum s2 s1 = ltimeEnv s2 Ctrl \<and>
                 getPstate s2 Ctrl = redToGreen \<and> ltimeEnv s2 Ctrl = RED_TO_GREEN_TIME_LIMIT))"
and ei12: "(\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and> substate s2 s0 \<and> getPstate s2 Ctrl = green \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl \<longrightarrow>
         getPstate s1 Ctrl = green)"
and ei13: " (\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and>
         substate s2 s0 \<and> (\<forall>s3. toEnvP s3 \<and> substate s1 s3 \<and> substate s3 s2 \<longrightarrow> getPstate s3 Ctrl = green) \<longrightarrow>
         toEnvNum s1 s2 = ltimeEnv s2 Ctrl - ltimeEnv s1 Ctrl)"
and ei14: " (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = green \<longrightarrow> getVarBool s1 minimalRed = PRESSED)"
and ei15: "(\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl \<noteq> green \<longrightarrow> getVarBool s1 minimalRed = NOT_PRESSED)"
and ei16: " (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<longrightarrow>
           getPstate s1 Ctrl = minimalRed \<or>
           getPstate s1 Ctrl = redAfterMinimalRed \<or> getPstate s1 Ctrl = redToGreen \<or> getPstate s1 Ctrl = green) "
and ei17: "(\<forall>s1 s2.
         toEnvP s1 \<and>
         toEnvP s2 \<and>
         substate s1 s2 \<and>
         substate s2 s0 \<and>
         toEnvNum s1 s2 < ltimeEnv s2 Ctrl - Ctrl \<and>
         getPstate s2 Ctrl = minimalRed \<and> getVarBool s2 redAfterMinimalRed = NOT_PRESSED \<longrightarrow>
         getVarBool s1 Ctrl = NOT_PRESSED)"
and ei18: " (\<forall>s2. toEnvP s2 \<and> substate s2 s0 \<and> getPstate s2 Ctrl = minimalRed \<and> getVarBool s2 redAfterMinimalRed = PRESSED \<longrightarrow>
           (\<exists>s1. toEnvP s1 \<and>
                 substate s1 s2 \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl - Ctrl \<and> getVarBool s1 Ctrl = PRESSED))"
and ei19: "(\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = redAfterMinimalRed \<and> getVarBool s1 redAfterMinimalRed \<longrightarrow>
           (\<exists>s2. toEnvP s2 \<and>
                 substate s2 s1 \<and>
                 toEnvNum s2 s1 = Ctrl \<and>
                 getPstate s2 Ctrl = minimalRed \<and>
                 ltimeEnv s2 Ctrl = MINIMAL_RED_TIME_LIMIT \<and>
                 (getVarBool s2 redAfterMinimalRed \<or> getVarBool s1 Ctrl = PRESSED)))"
and ei20: " (\<forall>s1. toEnvP s1 \<and> substate s1 s0 \<and> getPstate s1 Ctrl = green \<longrightarrow>
           getVarBool s1 redAfterMinimalRed = NOT_PRESSED)"
and vc: "env (setVarAny s0 requestButton_value) requestButton_value \<and>
    getPstate (setVarAny s0 requestButton_value) Ctrl = minimalRed \<and>
    \<not> getVarBool (setVarAny s0 requestButton_value) Ctrl \<and>
    MINIMAL_RED_TIME_LIMIT \<le> ltimeEnv (setVarAny s0 requestButton_value) Ctrl" by fast
  have "toEnvP (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed))"
    by simp
  moreover from ei1 ei0 vc have "(\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = minimalRed \<longrightarrow>
          0 < ltimeEnv s1 Ctrl \<and> ltimeEnv s1 Ctrl \<le> MINIMAL_RED_TIME_LIMIT)"
    by auto
  moreover from ei2 ei0 vc have "(\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = minimalRed \<longrightarrow>
          (\<exists>s2. toEnvP s2 \<and>
                substate s2 s1 \<and>
                toEnvNum s2 s1 = ltimeEnv s1 Ctrl \<and> getPstate s2 Ctrl = green \<and> ltimeEnv s2 Ctrl = GREEN_TIME_LIMIT) \<or>
          (\<forall>s2. toEnvP s2 \<and> substate s2 s1 \<longrightarrow> getPstate s2 Ctrl = minimalRed))"
    by auto
  moreover from ei3 ei0 vc have " (\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        getPstate s2 Ctrl = minimalRed \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl \<longrightarrow>
        getPstate s1 Ctrl = minimalRed)" by auto
  moreover from ei4 ei0 vc have " (\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        (\<forall>s3. toEnvP s3 \<and> substate s1 s3 \<and> substate s3 s2 \<longrightarrow> getPstate s3 Ctrl = minimalRed) \<longrightarrow>
        toEnvNum s1 s2 = ltimeEnv s2 Ctrl - ltimeEnv s1 Ctrl)" by auto
  moreover  have " (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = redAfterMinimalRed \<and> getVarBool s1 redAfterMinimalRed = NOT_PRESSED \<longrightarrow>
          (\<exists>s2. toEnvP s2 \<and>
                substate s2 s1 \<and>
                getPstate s2 Ctrl = minimalRed \<and>
                ltimeEnv s2 Ctrl = MINIMAL_RED_TIME_LIMIT \<and>
                getVarBool s2 redAfterMinimalRed = NOT_PRESSED \<and>
                (\<forall>s3. toEnvP s3 \<and> substate s2 s3 \<and> substate s3 s1 \<and> s2 \<noteq> s3 \<longrightarrow>
                      getPstate s3 Ctrl = redAfterMinimalRed \<and>
                      getVarBool s3 redAfterMinimalRed = NOT_PRESSED \<and> getVarBool s3 Ctrl = NOT_PRESSED)))"
  proof
    fix s1
    show "toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = redAfterMinimalRed \<and> getVarBool s1 redAfterMinimalRed = NOT_PRESSED \<longrightarrow>
          (\<exists>s2. toEnvP s2 \<and>
                substate s2 s1 \<and>
                getPstate s2 Ctrl = minimalRed \<and>
                ltimeEnv s2 Ctrl = MINIMAL_RED_TIME_LIMIT \<and>
                getVarBool s2 redAfterMinimalRed = NOT_PRESSED \<and>
                (\<forall>s3. toEnvP s3 \<and> substate s2 s3 \<and> substate s3 s1 \<and> s2 \<noteq> s3 \<longrightarrow>
                      getPstate s3 Ctrl = redAfterMinimalRed \<and>
                      getVarBool s3 redAfterMinimalRed = NOT_PRESSED \<and> getVarBool s3 Ctrl = NOT_PRESSED))"
    proof cases
      assume 1: "s1 = (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed))"
      show ?thesis
      proof
        assume 2: "toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = redAfterMinimalRed \<and> getVarBool s1 redAfterMinimalRed = NOT_PRESSED"
         have "(toEnvP s0 \<and>
                substate s0 s1 \<and>
                getPstate s0 Ctrl = minimalRed \<and>
                ltimeEnv s0 Ctrl = MINIMAL_RED_TIME_LIMIT \<and>
                getVarBool s0 redAfterMinimalRed = NOT_PRESSED) \<and>
                (\<forall>s3. toEnvP s3 \<and> substate s0 s3 \<and> substate s3 s1 \<and> s0 \<noteq> s3 \<longrightarrow>
                      getPstate s3 Ctrl = redAfterMinimalRed \<and>
                      getVarBool s3 redAfterMinimalRed = NOT_PRESSED \<and> getVarBool s3 Ctrl = NOT_PRESSED)"
         proof
           from 1 2 ei0 ei1 vc substate_refl show " toEnvP s0 \<and>
    substate s0 s1 \<and>
    getPstate s0 Ctrl = minimalRed \<and>
    ltimeEnv s0 Ctrl = MINIMAL_RED_TIME_LIMIT \<and> getVarBool s0 redAfterMinimalRed = NOT_PRESSED"
             by auto
         next
           show " \<forall>s3. toEnvP s3 \<and> substate s0 s3 \<and> substate s3 s1 \<and> s0 \<noteq> s3 \<longrightarrow>
         getPstate s3 Ctrl = redAfterMinimalRed \<and>
         getVarBool s3 redAfterMinimalRed = NOT_PRESSED \<and> getVarBool s3 Ctrl = NOT_PRESSED"
           proof
             fix s3
             show "toEnvP s3 \<and> substate s0 s3 \<and> substate s3 s1 \<and> s0 \<noteq> s3 \<longrightarrow>
          getPstate s3 Ctrl = redAfterMinimalRed \<and>
          getVarBool s3 redAfterMinimalRed = NOT_PRESSED \<and> getVarBool s3 Ctrl = NOT_PRESSED"
               using 1 2 vc substate_asym[of s0 s3] by auto
           qed
         qed
         thus "\<exists>s2. toEnvP s2 \<and>
       substate s2 s1 \<and>
       getPstate s2 Ctrl = minimalRed \<and>
       ltimeEnv s2 Ctrl = MINIMAL_RED_TIME_LIMIT \<and>
       getVarBool s2 redAfterMinimalRed = NOT_PRESSED \<and>
       (\<forall>s3. toEnvP s3 \<and> substate s2 s3 \<and> substate s3 s1 \<and> s2 \<noteq> s3 \<longrightarrow>
             getPstate s3 Ctrl = redAfterMinimalRed \<and>
             getVarBool s3 redAfterMinimalRed = NOT_PRESSED \<and> getVarBool s3 Ctrl = NOT_PRESSED)"
           by auto
       qed
     next
       assume  "s1 \<noteq> (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed))"
       with ei5 show ?thesis by auto
     qed
   qed
   moreover from ei6 ei0 vc have " (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = redToGreen \<longrightarrow>
          0 < ltimeEnv s1 Ctrl \<and> ltimeEnv s1 Ctrl \<le> RED_TO_GREEN_TIME_LIMIT)"
     by auto
   moreover from ei7 ei0 vc have " (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = redToGreen \<longrightarrow>
          (\<exists>s2. toEnvP s2 \<and>
                substate s2 s1 \<and>
                toEnvNum s2 s1 = ltimeEnv s1 Ctrl \<and>
                getPstate s2 Ctrl = redAfterMinimalRed \<and>
                (getVarBool s2 redAfterMinimalRed = PRESSED \<or> getVarBool s2 Ctrl = PRESSED)))"
     by auto
   moreover from ei8 ei0 vc have "(\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        toEnvNum s1 s2 < ltimeEnv s2 Ctrl \<and> getPstate s2 Ctrl = redToGreen \<longrightarrow>
        getPstate s1 Ctrl = redToGreen)"
     by auto
   moreover from ei9 ei0 vc have " (\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        (\<forall>s3. toEnvP s3 \<and> substate s1 s3 \<and> substate s3 s2 \<longrightarrow> getPstate s3 Ctrl = redToGreen) \<longrightarrow>
        toEnvNum s1 s2 = ltimeEnv s2 Ctrl - ltimeEnv s1 Ctrl)"
     by auto
   moreover from ei10 ei0 vc have "(\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = green \<longrightarrow>
          0 < ltimeEnv s1 Ctrl \<and> ltimeEnv s1 Ctrl \<le> GREEN_TIME_LIMIT)"
     by auto
   moreover from ei11 ei0 vc have "  (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = green \<longrightarrow>
          (\<exists>s2. toEnvP s2 \<and>
                substate s2 s1 \<and>
                toEnvNum s2 s1 = ltimeEnv s2 Ctrl \<and>
                getPstate s2 Ctrl = redToGreen \<and> ltimeEnv s2 Ctrl = RED_TO_GREEN_TIME_LIMIT))"
     by auto
   moreover from ei12 ei0 vc have "(\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        getPstate s2 Ctrl = green \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl \<longrightarrow>
        getPstate s1 Ctrl = green)"
     by auto
   moreover from ei13 ei0 vc have " (\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        (\<forall>s3. toEnvP s3 \<and> substate s1 s3 \<and> substate s3 s2 \<longrightarrow> getPstate s3 Ctrl = green) \<longrightarrow>
        toEnvNum s1 s2 = ltimeEnv s2 Ctrl - ltimeEnv s1 Ctrl)"
     by auto
   moreover from ei14 ei0 vc have " (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = green \<longrightarrow>
          getVarBool s1 minimalRed = PRESSED)"
     by auto
   moreover from ei15 ei0 vc substate_refl have " (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl \<noteq> green \<longrightarrow>
          getVarBool s1 minimalRed = NOT_PRESSED)"
     by auto
   moreover from ei16 ei0 vc substate_refl have "(\<forall>s1. toEnvP s1 \<and> substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<longrightarrow>
          getPstate s1 Ctrl = minimalRed \<or>
          getPstate s1 Ctrl = redAfterMinimalRed \<or> getPstate s1 Ctrl = redToGreen \<or> getPstate s1 Ctrl = green)"
     by auto
   moreover from ei17 ei0 vc substate_refl have " (\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        toEnvNum s1 s2 < ltimeEnv s2 Ctrl - Ctrl \<and>
        getPstate s2 Ctrl = minimalRed \<and> getVarBool s2 redAfterMinimalRed = NOT_PRESSED \<longrightarrow>
        getVarBool s1 Ctrl = NOT_PRESSED)"
     by auto
   moreover from ei18 ei0 vc substate_refl have "(\<forall>s2. toEnvP s2 \<and>
          substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s2 Ctrl = minimalRed \<and> getVarBool s2 redAfterMinimalRed = PRESSED \<longrightarrow>
          (\<exists>s1. toEnvP s1 \<and>
                substate s1 s2 \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl - Ctrl \<and> getVarBool s1 Ctrl = PRESSED))"
     by auto
   moreover have " (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = redAfterMinimalRed \<and> getVarBool s1 redAfterMinimalRed \<longrightarrow>
          (\<exists>s2. toEnvP s2 \<and>
                substate s2 s1 \<and>
                toEnvNum s2 s1 = Ctrl \<and>
                getPstate s2 Ctrl = minimalRed \<and>
                ltimeEnv s2 Ctrl = MINIMAL_RED_TIME_LIMIT \<and>
                (getVarBool s2 redAfterMinimalRed \<or> getVarBool s1 Ctrl = PRESSED)))"
   proof
     fix s1
     show "toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = redAfterMinimalRed \<and> getVarBool s1 redAfterMinimalRed \<longrightarrow>
          (\<exists>s2. toEnvP s2 \<and>
                substate s2 s1 \<and>
                toEnvNum s2 s1 = Ctrl \<and>
                getPstate s2 Ctrl = minimalRed \<and>
                ltimeEnv s2 Ctrl = MINIMAL_RED_TIME_LIMIT \<and>
                (getVarBool s2 redAfterMinimalRed \<or> getVarBool s1 Ctrl = PRESSED))"
     proof cases
       assume 1: "s1 = (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed))"
       show ?thesis
       proof
         assume 2: "toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = redAfterMinimalRed \<and> getVarBool s1 redAfterMinimalRed"
        from 1 2 ei0 ei1 vc substate_refl toEnvNum_id  have "toEnvP s0 \<and>
                substate s0 s1 \<and>
                toEnvNum s0 s1 = Ctrl \<and>
                getPstate s0 Ctrl = minimalRed \<and>
                ltimeEnv s0 Ctrl = MINIMAL_RED_TIME_LIMIT \<and>
                (getVarBool s0 redAfterMinimalRed \<or> getVarBool s1 Ctrl = PRESSED)"
          by auto
        thus " \<exists>s2. toEnvP s2 \<and>
         substate s2 s1 \<and>
         toEnvNum s2 s1 = Ctrl \<and>
         getPstate s2 Ctrl = minimalRed \<and>
         ltimeEnv s2 Ctrl = MINIMAL_RED_TIME_LIMIT \<and> (getVarBool s2 redAfterMinimalRed \<or> getVarBool s1 Ctrl = PRESSED)"
          by auto
      qed
    next
      assume "s1 \<noteq> (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed))"
      with ei19 show ?thesis by auto
    qed
  qed
  moreover from ei20 ei0 vc substate_refl have "(\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = green \<longrightarrow>
          getVarBool s1 redAfterMinimalRed = NOT_PRESSED)"
    by auto
  ultimately show "toEnvP (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
    (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = minimalRed \<longrightarrow>
          0 < ltimeEnv s1 Ctrl \<and> ltimeEnv s1 Ctrl \<le> MINIMAL_RED_TIME_LIMIT) \<and>
    (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = minimalRed \<longrightarrow>
          (\<exists>s2. toEnvP s2 \<and>
                substate s2 s1 \<and>
                toEnvNum s2 s1 = ltimeEnv s1 Ctrl \<and> getPstate s2 Ctrl = green \<and> ltimeEnv s2 Ctrl = GREEN_TIME_LIMIT) \<or>
          (\<forall>s2. toEnvP s2 \<and> substate s2 s1 \<longrightarrow> getPstate s2 Ctrl = minimalRed)) \<and>
    (\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        getPstate s2 Ctrl = minimalRed \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl \<longrightarrow>
        getPstate s1 Ctrl = minimalRed) \<and>
    (\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        (\<forall>s3. toEnvP s3 \<and> substate s1 s3 \<and> substate s3 s2 \<longrightarrow> getPstate s3 Ctrl = minimalRed) \<longrightarrow>
        toEnvNum s1 s2 = ltimeEnv s2 Ctrl - ltimeEnv s1 Ctrl) \<and>
    (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = redAfterMinimalRed \<and> getVarBool s1 redAfterMinimalRed = NOT_PRESSED \<longrightarrow>
          (\<exists>s2. toEnvP s2 \<and>
                substate s2 s1 \<and>
                getPstate s2 Ctrl = minimalRed \<and>
                ltimeEnv s2 Ctrl = MINIMAL_RED_TIME_LIMIT \<and>
                getVarBool s2 redAfterMinimalRed = NOT_PRESSED \<and>
                (\<forall>s3. toEnvP s3 \<and> substate s2 s3 \<and> substate s3 s1 \<and> s2 \<noteq> s3 \<longrightarrow>
                      getPstate s3 Ctrl = redAfterMinimalRed \<and>
                      getVarBool s3 redAfterMinimalRed = NOT_PRESSED \<and> getVarBool s3 Ctrl = NOT_PRESSED))) \<and>
    (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = redToGreen \<longrightarrow>
          0 < ltimeEnv s1 Ctrl \<and> ltimeEnv s1 Ctrl \<le> RED_TO_GREEN_TIME_LIMIT) \<and>
    (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = redToGreen \<longrightarrow>
          (\<exists>s2. toEnvP s2 \<and>
                substate s2 s1 \<and>
                toEnvNum s2 s1 = ltimeEnv s1 Ctrl \<and>
                getPstate s2 Ctrl = redAfterMinimalRed \<and>
                (getVarBool s2 redAfterMinimalRed = PRESSED \<or> getVarBool s2 Ctrl = PRESSED))) \<and>
    (\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        toEnvNum s1 s2 < ltimeEnv s2 Ctrl \<and> getPstate s2 Ctrl = redToGreen \<longrightarrow>
        getPstate s1 Ctrl = redToGreen) \<and>
    (\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        (\<forall>s3. toEnvP s3 \<and> substate s1 s3 \<and> substate s3 s2 \<longrightarrow> getPstate s3 Ctrl = redToGreen) \<longrightarrow>
        toEnvNum s1 s2 = ltimeEnv s2 Ctrl - ltimeEnv s1 Ctrl) \<and>
    (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = green \<longrightarrow>
          0 < ltimeEnv s1 Ctrl \<and> ltimeEnv s1 Ctrl \<le> GREEN_TIME_LIMIT) \<and>
    (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = green \<longrightarrow>
          (\<exists>s2. toEnvP s2 \<and>
                substate s2 s1 \<and>
                toEnvNum s2 s1 = ltimeEnv s2 Ctrl \<and>
                getPstate s2 Ctrl = redToGreen \<and> ltimeEnv s2 Ctrl = RED_TO_GREEN_TIME_LIMIT)) \<and>
    (\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        getPstate s2 Ctrl = green \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl \<longrightarrow>
        getPstate s1 Ctrl = green) \<and>
    (\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        (\<forall>s3. toEnvP s3 \<and> substate s1 s3 \<and> substate s3 s2 \<longrightarrow> getPstate s3 Ctrl = green) \<longrightarrow>
        toEnvNum s1 s2 = ltimeEnv s2 Ctrl - ltimeEnv s1 Ctrl) \<and>
    (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = green \<longrightarrow>
          getVarBool s1 minimalRed = PRESSED) \<and>
    (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl \<noteq> green \<longrightarrow>
          getVarBool s1 minimalRed = NOT_PRESSED) \<and>
    (\<forall>s1. toEnvP s1 \<and> substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<longrightarrow>
          getPstate s1 Ctrl = minimalRed \<or>
          getPstate s1 Ctrl = redAfterMinimalRed \<or> getPstate s1 Ctrl = redToGreen \<or> getPstate s1 Ctrl = green) \<and>
    (\<forall>s1 s2.
        toEnvP s1 \<and>
        toEnvP s2 \<and>
        substate s1 s2 \<and>
        substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
        toEnvNum s1 s2 < ltimeEnv s2 Ctrl - Ctrl \<and>
        getPstate s2 Ctrl = minimalRed \<and> getVarBool s2 redAfterMinimalRed = NOT_PRESSED \<longrightarrow>
        getVarBool s1 Ctrl = NOT_PRESSED) \<and>
    (\<forall>s2. toEnvP s2 \<and>
          substate s2 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s2 Ctrl = minimalRed \<and> getVarBool s2 redAfterMinimalRed = PRESSED \<longrightarrow>
          (\<exists>s1. toEnvP s1 \<and>
                substate s1 s2 \<and> toEnvNum s1 s2 < ltimeEnv s2 Ctrl - Ctrl \<and> getVarBool s1 Ctrl = PRESSED)) \<and>
    (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = redAfterMinimalRed \<and> getVarBool s1 redAfterMinimalRed \<longrightarrow>
          (\<exists>s2. toEnvP s2 \<and>
                substate s2 s1 \<and>
                toEnvNum s2 s1 = Ctrl \<and>
                getPstate s2 Ctrl = minimalRed \<and>
                ltimeEnv s2 Ctrl = MINIMAL_RED_TIME_LIMIT \<and>
                (getVarBool s2 redAfterMinimalRed \<or> getVarBool s1 Ctrl = PRESSED))) \<and>
    (\<forall>s1. toEnvP s1 \<and>
          substate s1 (toEnv (setPstate (setVarAny s0 requestButton_value) Ctrl redAfterMinimalRed)) \<and>
          getPstate s1 Ctrl = green \<longrightarrow>
          getVarBool s1 redAfterMinimalRed = NOT_PRESSED)"
    by fast
qed