(*  Title:      HOL/Auth/n_moesi_lemma_on_inv__1.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_moesi Protocol Case Study*}

theory n_moesi_lemma_on_inv__1 imports n_moesi_base
begin
section{*All lemmas on causal relation between inv__1 and some rule r*}
lemma n_rule_t1Vsinv__1:
assumes a1: "(\<exists> i. i\<le>N\<and>r=n_rule_t1  i)" and
a2: "(\<exists> p__Inv0 p__Inv2. p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__1  p__Inv0 p__Inv2)"
shows "invHoldForRule s f r (invariants N)" (is "?P1 s \<or> ?P2 s \<or> ?P3 s")
proof -
from a1 obtain i where a1:"i\<le>N\<and>r=n_rule_t1  i" apply fastforce done
from a2 obtain p__Inv0 p__Inv2 where a2:"p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__1  p__Inv0 p__Inv2" apply fastforce done
have "(i=p__Inv2)\<or>(i=p__Inv0)\<or>(i~=p__Inv0\<and>i~=p__Inv2)" apply (cut_tac a1 a2, auto) done
moreover {
  assume b1: "(i=p__Inv2)"
  have "?P3 s"
  apply (cut_tac a1 a2 b1, simp, rule_tac x="(neg (andForm (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M)) (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E))))" in exI, auto) done
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i=p__Inv0)"
  have "?P3 s"
  apply (cut_tac a1 a2 b1, simp, rule_tac x="(neg (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M)) (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E))))" in exI, auto) done
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i~=p__Inv0\<and>i~=p__Inv2)"
  have "?P2 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
ultimately show "invHoldForRule s f r (invariants N)" by satx
qed

lemma n_rule_t2Vsinv__1:
assumes a1: "(\<exists> i. i\<le>N\<and>r=n_rule_t2 N i)" and
a2: "(\<exists> p__Inv0 p__Inv2. p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__1  p__Inv0 p__Inv2)"
shows "invHoldForRule s f r (invariants N)" (is "?P1 s \<or> ?P2 s \<or> ?P3 s")
proof -
from a1 obtain i where a1:"i\<le>N\<and>r=n_rule_t2 N i" apply fastforce done
from a2 obtain p__Inv0 p__Inv2 where a2:"p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__1  p__Inv0 p__Inv2" apply fastforce done
have "(i=p__Inv2)\<or>(i=p__Inv0)\<or>(i~=p__Inv0\<and>i~=p__Inv2)" apply (cut_tac a1 a2, auto) done
moreover {
  assume b1: "(i=p__Inv2)"
  have "((formEval (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)) s))\<or>((formEval (andForm (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M)) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))\<or>((formEval (andForm (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))" by auto
  moreover {
    assume c1: "((formEval (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  moreover {
    assume c1: "((formEval (andForm (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M)) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  moreover {
    assume c1: "((formEval (andForm (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  ultimately have "invHoldForRule s f r (invariants N)" by satx
}
moreover {
  assume b1: "(i=p__Inv0)"
  have "((formEval (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)) s))\<or>((formEval (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M)) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) s))\<or>((formEval (andForm (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) s))" by auto
  moreover {
    assume c1: "((formEval (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  moreover {
    assume c1: "((formEval (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M)) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  moreover {
    assume c1: "((formEval (andForm (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  ultimately have "invHoldForRule s f r (invariants N)" by satx
}
moreover {
  assume b1: "(i~=p__Inv0\<and>i~=p__Inv2)"
  have "((formEval (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)) (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E))) s))\<or>((formEval (andForm (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M)) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E))) s))\<or>((formEval (andForm (andForm (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E))) s))\<or>((formEval (andForm (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)) (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))\<or>((formEval (andForm (andForm (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M)) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))\<or>((formEval (andForm (andForm (andForm (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))\<or>((formEval (andForm (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M)))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))\<or>((formEval (andForm (andForm (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M)) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M)))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))\<or>((formEval (andForm (andForm (andForm (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M)))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))" by auto
  moreover {
    assume c1: "((formEval (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)) (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E))) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  moreover {
    assume c1: "((formEval (andForm (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M)) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E))) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  moreover {
    assume c1: "((formEval (andForm (andForm (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E))) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  moreover {
    assume c1: "((formEval (andForm (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)) (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  moreover {
    assume c1: "((formEval (andForm (andForm (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M)) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  moreover {
    assume c1: "((formEval (andForm (andForm (andForm (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  moreover {
    assume c1: "((formEval (andForm (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M)))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  moreover {
    assume c1: "((formEval (andForm (andForm (andForm (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M)) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M)))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))"
    have "?P1 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  moreover {
    assume c1: "((formEval (andForm (andForm (andForm (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const M))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv2)) (Const E)))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const M)))) (neg (eqn (IVar (Para (Ident ''a'') p__Inv0)) (Const E)))) s))"
    have "?P2 s"
    proof(cut_tac a1 a2 b1 c1, auto) qed
    then have "invHoldForRule s f r (invariants N)" by auto
  }
  ultimately have "invHoldForRule s f r (invariants N)" by satx
}
ultimately show "invHoldForRule s f r (invariants N)" by satx
qed

lemma n_rul_t3Vsinv__1:
assumes a1: "(\<exists> i. i\<le>N\<and>r=n_rul_t3 N i)" and
a2: "(\<exists> p__Inv0 p__Inv2. p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__1  p__Inv0 p__Inv2)"
shows "invHoldForRule s f r (invariants N)" (is "?P1 s \<or> ?P2 s \<or> ?P3 s")
proof -
from a1 obtain i where a1:"i\<le>N\<and>r=n_rul_t3 N i" apply fastforce done
from a2 obtain p__Inv0 p__Inv2 where a2:"p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__1  p__Inv0 p__Inv2" apply fastforce done
have "(i=p__Inv2)\<or>(i=p__Inv0)\<or>(i~=p__Inv0\<and>i~=p__Inv2)" apply (cut_tac a1 a2, auto) done
moreover {
  assume b1: "(i=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i=p__Inv0)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i~=p__Inv0\<and>i~=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
ultimately show "invHoldForRule s f r (invariants N)" by satx
qed

lemma n_rul_t4Vsinv__1:
assumes a1: "(\<exists> i. i\<le>N\<and>r=n_rul_t4 N i)" and
a2: "(\<exists> p__Inv0 p__Inv2. p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__1  p__Inv0 p__Inv2)"
shows "invHoldForRule s f r (invariants N)" (is "?P1 s \<or> ?P2 s \<or> ?P3 s")
proof -
from a1 obtain i where a1:"i\<le>N\<and>r=n_rul_t4 N i" apply fastforce done
from a2 obtain p__Inv0 p__Inv2 where a2:"p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__1  p__Inv0 p__Inv2" apply fastforce done
have "(i=p__Inv2)\<or>(i=p__Inv0)\<or>(i~=p__Inv0\<and>i~=p__Inv2)" apply (cut_tac a1 a2, auto) done
moreover {
  assume b1: "(i=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i=p__Inv0)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i~=p__Inv0\<and>i~=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
ultimately show "invHoldForRule s f r (invariants N)" by satx
qed

lemma n_rul_t5Vsinv__1:
assumes a1: "(\<exists> i. i\<le>N\<and>r=n_rul_t5 N i)" and
a2: "(\<exists> p__Inv0 p__Inv2. p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__1  p__Inv0 p__Inv2)"
shows "invHoldForRule s f r (invariants N)" (is "?P1 s \<or> ?P2 s \<or> ?P3 s")
proof -
from a1 obtain i where a1:"i\<le>N\<and>r=n_rul_t5 N i" apply fastforce done
from a2 obtain p__Inv0 p__Inv2 where a2:"p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__1  p__Inv0 p__Inv2" apply fastforce done
have "(i=p__Inv2)\<or>(i=p__Inv0)\<or>(i~=p__Inv0\<and>i~=p__Inv2)" apply (cut_tac a1 a2, auto) done
moreover {
  assume b1: "(i=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i=p__Inv0)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
moreover {
  assume b1: "(i~=p__Inv0\<and>i~=p__Inv2)"
  have "?P1 s"
  proof(cut_tac a1 a2 b1, auto) qed
  then have "invHoldForRule s f r (invariants N)" by auto
}
ultimately show "invHoldForRule s f r (invariants N)" by satx
qed
end


section \<open>Dynamic Standard Control Dependence\<close>

theory DynStandardControlDependence imports Postdomination begin

context Postdomination begin

definition
  dyn_standard_control_dependence :: "'node \<Rightarrow> 'node \<Rightarrow> 'edge list \<Rightarrow> bool"
  ("_ controls\<^sub>s _ via _" [51,0,0])
where dyn_standard_control_dependence_def:"n controls\<^sub>s n' via as \<equiv>
    (\<exists>a a' as'. (as = a#as') \<and> (n' \<notin> set(sourcenodes as)) \<and> (n -as\<rightarrow>* n') \<and>
                   (n' postdominates (targetnode a)) \<and>
                   (valid_edge a') \<and> (sourcenode a' = n) \<and>
                   (\<not> n' postdominates (targetnode a')))"

lemma Exit_not_dyn_standard_control_dependent:
  assumes control:"n controls\<^sub>s (_Exit_) via as" shows "False"
proof -
  from control obtain a as' where path:"n -as\<rightarrow>* (_Exit_)" and as:"as = a#as'"
    and pd:"(_Exit_) postdominates (targetnode a)"
    by(auto simp:dyn_standard_control_dependence_def)
  from path as have "n -[]@a#as'\<rightarrow>* (_Exit_)" by simp
  hence "valid_edge a" by(fastforce dest:path_split)
  with pd show False by -(rule Exit_no_postdominator,auto)
qed

lemma dyn_standard_control_dependence_def_variant:
  "n controls\<^sub>s n' via as = ((n -as\<rightarrow>* n') \<and> (n \<noteq> n') \<and>
    (\<not> n' postdominates n) \<and> (n' \<notin> set(sourcenodes as)) \<and>
  (\<forall>n'' \<in> set(targetnodes as). n' postdominates n''))"
proof
  assume "(n -as\<rightarrow>* n') \<and> (n \<noteq> n') \<and> (\<not> n' postdominates n) \<and>
    (n' \<notin> set(sourcenodes as)) \<and>
    (\<forall>n''\<in>set (targetnodes as). n' postdominates n'')"
  hence path:"n -as\<rightarrow>* n'" and noteq:"n \<noteq> n'"
    and not_pd:"\<not> n' postdominates n"
    and notin:"n' \<notin> set(sourcenodes as)"
    and all:"\<forall>n''\<in>set (targetnodes as). n' postdominates n''"
    by auto
  have notExit:"n \<noteq> (_Exit_)"
  proof
    assume "n = (_Exit_)"
    with path have "n = n'" by(fastforce dest:path_Exit_source)
    with noteq show False by simp
  qed
  from path have valid:"valid_node n" and valid':"valid_node n'"
    by(auto dest:path_valid_node)
  show "n controls\<^sub>s n' via as"
  proof(cases as)
    case Nil
    with path valid not_pd notExit have False
      by(fastforce elim:path.cases dest:postdominate_refl)
    thus ?thesis by simp
  next
    case (Cons ax asx)
    with all have pd:"n' postdominates targetnode ax"
      by(auto simp:targetnodes_def)
    from path Cons have source:"n = sourcenode ax"
      and path2:"targetnode ax -asx\<rightarrow>* n'"
      by(auto intro:path_split_Cons)
    show ?thesis
    proof(cases "\<exists>as'. n -as'\<rightarrow>* (_Exit_)")
      case True
      with not_pd valid valid' obtain as' where path':"n -as'\<rightarrow>* (_Exit_)"
        and not_isin:"n' \<notin> set (sourcenodes as')"
        by(auto simp:postdominate_def)
      have "as' \<noteq> []"
      proof
        assume "as' = []"
        with path' have "n = (_Exit_)" by(auto elim:path.cases)
        with notExit show False by simp
      qed
      then obtain a' as'' where as':"as' = a'#as''"
        by(cases as',auto elim:path.cases)
      with path' have "n -[]@a'#as''\<rightarrow>* (_Exit_)" by simp
      hence source':"n = sourcenode a'"
        and valid_edge:"valid_edge a'"
        and path2':"targetnode a' -as''\<rightarrow>* (_Exit_)"
        by(fastforce dest:path_split)+
      from path2' not_isin as' valid'
      have "\<not> n' postdominates (targetnode a')"
        by(auto simp:postdominate_def sourcenodes_def)
      with pd path Cons source source' notin valid_edge show ?thesis
        by(auto simp:dyn_standard_control_dependence_def)
    next
      case False
      with valid valid' have "n' postdominates n"
        by(auto simp:postdominate_def)
      with not_pd have False by simp
      thus ?thesis by simp
    qed
  qed
next
  assume "n controls\<^sub>s n' via as"
  then obtain a nx a' nx' as' where notin:"n' \<notin> set(sourcenodes as)"
    and path:"n -as\<rightarrow>* n'" and as:"as = a#as'" and valid_edge:"valid_edge a'"
    and pd:"n' postdominates (targetnode a)"
    and source':"sourcenode a' = n"
    and not_pd:"\<not> n' postdominates (targetnode a')"
    by(auto simp:dyn_standard_control_dependence_def)
  from path as have source:"sourcenode a = n" by(auto elim:path.cases)
  from path as have notExit:"n \<noteq> (_Exit_)" by(auto elim:path.cases)
  from path have valid:"valid_node n" and valid':"valid_node n'"
    by(auto dest:path_valid_node)
  from notin as source have noteq:"n \<noteq> n'"
    by(fastforce simp:sourcenodes_def)
  from valid_edge have valid_target':"valid_node (targetnode a')"
    by(fastforce simp:valid_node_def)
  { assume pd':"n' postdominates n"
    hence all:"\<forall>as. n -as\<rightarrow>* (_Exit_) \<longrightarrow> n' \<in> set (sourcenodes as)"
      by(auto simp:postdominate_def)
    from not_pd valid' valid_target' obtain as'
      where "targetnode a' -as'\<rightarrow>* (_Exit_)"
      by(auto simp:postdominate_def)
    with source' valid_edge have path':"n -a'#as'\<rightarrow>* (_Exit_)"
      by(fastforce intro:Cons_path)
    with all have "n' \<in> set (sourcenodes (a'#as'))" by blast
    with source' have "n' = n \<or> n' \<in> set (sourcenodes as')"
      by(fastforce simp:sourcenodes_def)
    hence False
    proof
      assume "n' = n"
      with noteq show ?thesis by simp
    next
      assume isin:"n' \<in> set (sourcenodes as')"
      from path' have path2:"targetnode a' -as'\<rightarrow>* (_Exit_)"
        by(fastforce elim:path_split_Cons)
      thus ?thesis
      proof(cases "as' = []")
        case True
        with path2 have "targetnode a' = (_Exit_)" by(auto elim:path.cases)
        with valid_edge all source' have "n' = n"
          by(fastforce dest:path_edge simp:sourcenodes_def)
        with noteq show ?thesis by simp
      next
        case False
        from path2 not_pd valid' valid_edge obtain as''
          where path'':"targetnode a' -as''\<rightarrow>* (_Exit_)"
          and notin:"n' \<notin> set (sourcenodes as'')"
          by(auto simp:postdominate_def)
        from valid_edge path'' have "sourcenode a' -a'#as''\<rightarrow>* (_Exit_)"
          by(fastforce intro:Cons_path)
        with all source' have "n' \<in> set (sourcenodes ([a']@as''))" by simp
        with source' have "n' = n \<or> n' \<in> set (sourcenodes as'')"
          by(auto simp:sourcenodes_def)
        thus ?thesis
        proof
          assume "n' = n"
          with noteq show ?thesis by simp
        next
          assume "n' \<in> set (sourcenodes as'')"
          with notin show ?thesis by simp
        qed
      qed
    qed }
  hence not_pd':"\<not> n' postdominates n" by blast
  { fix n'' assume "n'' \<in> set (targetnodes as)"
    with as source have "n'' = targetnode a \<or> n'' \<in> set (targetnodes as')"
      by(auto simp:targetnodes_def)
    hence "n' postdominates n''"
    proof
      assume "n'' = targetnode a"
      with pd show ?thesis by simp
    next
      assume isin:"n'' \<in> set (targetnodes as')"
      hence "\<exists>ni \<in> set (targetnodes as'). ni = n''" by simp
      then obtain ns ns' where targets:"targetnodes as' = ns@n''#ns'"
        and all_noteq:"\<forall>ni \<in> set ns'. ni \<noteq> n''"
        by(fastforce elim!:rightmost_element_property)
      from targets obtain xs ax ys where ys:"ns' = targetnodes ys"
        and as':"as' = xs@ax#ys" and target'':"targetnode ax = n''"
        by(fastforce elim:map_append_append_maps simp:targetnodes_def)
      from all_noteq ys have notin_target:"n'' \<notin> set(targetnodes ys)"
        by auto
      from path as have "n -[]@a#as'\<rightarrow>* n'" by simp
      hence "targetnode a -as'\<rightarrow>* n'"
        by(fastforce dest:path_split)
      with isin have path':"targetnode a -as'\<rightarrow>* n'"
        by(fastforce split:if_split_asm simp:targetnodes_def)
      with as' target'' have path1:"targetnode a -xs\<rightarrow>* sourcenode ax"
        and valid_edge':"valid_edge ax"
        and path2:"n'' -ys\<rightarrow>* n'"
        by(auto intro:path_split)
      from valid_edge' have "sourcenode ax -[ax]\<rightarrow>* targetnode ax" by(rule path_edge)
      with path1 target'' have path_n'':"targetnode a -xs@[ax]\<rightarrow>* n''"
        by(fastforce intro:path_Append)
      from notin as as' have notin':"n'\<notin> set (sourcenodes (xs@[ax]))"
        by(simp add:sourcenodes_def)
      show ?thesis
      proof(rule ccontr)
        assume "\<not> n' postdominates n''"
        with valid' target'' valid_edge' obtain asx'
          where Exit_path:"n'' -asx'\<rightarrow>* (_Exit_)"
          and notin'':"n' \<notin> set(sourcenodes asx')" by(auto simp:postdominate_def)
        from path_n'' Exit_path
        have Exit_path':"targetnode a -(xs@[ax])@asx'\<rightarrow>* (_Exit_)"
          by(fastforce intro:path_Append)
        from notin' notin'' have "n' \<notin> set(sourcenodes (xs@ax#asx'))"
          by(simp add:sourcenodes_def)
        with pd Exit_path' show False by(simp add:postdominate_def)
      qed
    qed }
  with path not_pd' notin noteq show "(n -as\<rightarrow>* n') \<and> (n \<noteq> n') \<and>
    (\<not> n' postdominates n) \<and> (n' \<notin> set(sourcenodes as)) \<and>
    (\<forall>n'' \<in> set(targetnodes as). n' postdominates n'')" by blast
qed

lemma which_node_dyn_standard_control_dependence_source:
  assumes path:"(_Entry_) -as@a#as'\<rightarrow>* n"
  and Exit_path:"n -as''\<rightarrow>* (_Exit_)" and source:"sourcenode a = n'"
  and source':"sourcenode a' = n'"
  and no_source:"n \<notin> set(sourcenodes (a#as'))" and valid_edge':"valid_edge a'"
  and inner_node:"inner_node n" and not_pd:"\<not> n postdominates (targetnode a')"
  and last:"\<forall>ax ax'. ax \<in> set as' \<and> sourcenode ax = sourcenode ax' \<and>
    valid_edge ax' \<longrightarrow> n postdominates targetnode ax'"
  shows "n' controls\<^sub>s n via a#as'"
proof -
  from path source have path_n'n:"n' -a#as'\<rightarrow>* n" by(fastforce dest:path_split_second)
  from path have valid_edge:"valid_edge a" by(fastforce intro:path_split)
  show ?thesis
  proof(cases "n postdominates (targetnode a)")
    case True
    with path_n'n not_pd no_source source source' valid_edge' show ?thesis
      by(auto simp:dyn_standard_control_dependence_def)
  next
    case False
    hence not_pd':"\<not> n postdominates (targetnode a)" .
    show ?thesis
    proof(cases "as' = []")
      case True
      with path_n'n have "targetnode a = n" by(fastforce elim:path.cases)
      with inner_node have "n postdominates (targetnode a)"
        by(cases "n = (_Exit_)",auto intro:postdominate_refl simp:inner_node_def)
      with not_pd path_n'n no_source source source' valid_edge' show ?thesis
        by(fastforce simp:dyn_standard_control_dependence_def)
    next
      case False
      hence notempty':"as' \<noteq> []" .
      with path have path_nxn:"targetnode a -as'\<rightarrow>* n"
        by(fastforce dest:path_split)
      from Exit_path path_nxn have "\<exists>as. targetnode a -as\<rightarrow>* (_Exit_)"
        by(fastforce dest:path_Append)
      with not_pd' inner_node valid_edge obtain asx
        where path_Exit:"targetnode a -asx\<rightarrow>* (_Exit_)"
        and notin:"n \<notin> set (sourcenodes asx)"
        by(auto simp:postdominate_def inner_is_valid)
      show ?thesis
      proof(cases "\<exists>asx'. asx = as'@asx'")
        case True
        then obtain asx' where asx:"asx = as'@asx'" by blast
        from path notempty' have "targetnode a -as'\<rightarrow>* n"
          by(fastforce dest:path_split)
        with path_Exit inner_node asx notempty'
        obtain a'' as'' where "asx' = a''#as'' \<and> sourcenode a'' = n"
          apply(cases asx')
           apply(fastforce dest:path_det)
          by(fastforce dest:path_split path_det)
        with asx have "n \<in> set(sourcenodes asx)" by(simp add:sourcenodes_def)
        with notin have False by simp
        thus ?thesis by simp
      next
        case False
        hence all:"\<forall>asx'. asx \<noteq> as'@asx'" by simp
        then obtain j asx' where asx:"asx = (take j as')@asx'"
          and length:"j < length as'"
          and not_more:"\<forall>k > j. \<forall>asx''. asx \<noteq> (take k as')@asx''"
          by(auto elim:path_split_general)
        from asx length have "\<exists>as'1 as'2. asx = as'1@asx' \<and>
          as' = as'1@as'2 \<and> as'2 \<noteq> [] \<and> as'1 = take j as'"
          by simp(rule_tac x= "drop j as'" in exI,simp)
        then obtain as'1 as'' where asx:"asx = as'1@asx'"
          and take:"as'1 = take j as'"
          and x:"as' = as'1@as''" and x':"as'' \<noteq> []" by blast
        from x x' obtain a1 as'2 where as':"as' = as'1@a1#as'2" and "as'' = a1#as'2"
          by(cases as'') auto
        have notempty_x':"asx' \<noteq> []"
        proof(cases "asx' = []")
          case True
          with asx as' have "as' = asx@a1#as'2" by simp
          with path_n'n have "n' -(a#asx)@a1#as'2\<rightarrow>* n"
            by simp
          hence "n' -a#asx\<rightarrow>* sourcenode a1"
            and valid_edge1:"valid_edge a1" by(fastforce elim:path_split)+
          hence "targetnode a -asx\<rightarrow>* sourcenode a1"
            by(fastforce intro:path_split_Cons)
          with path_Exit have "(_Exit_) = sourcenode a1" by(rule path_det)
          from this[THEN sym] valid_edge1 have False by -(rule Exit_source,simp_all)
          thus ?thesis by simp
        qed simp
        with asx obtain a2 asx'1
          where asx:"asx = as'1@a2#asx'1"
          and asx':"asx' = a2#asx'1" by(cases asx') auto
        from path_n'n as' have "n' -(a#as'1)@a1#as'2\<rightarrow>* n" by simp
        hence "n' -a#as'1\<rightarrow>* sourcenode a1" and valid_edge1:"valid_edge a1"
          by(fastforce elim:path_split)+
        hence path1:"targetnode a -as'1\<rightarrow>* sourcenode a1"
          by(fastforce intro:path_split_Cons)
        from path_Exit asx
        have "targetnode a -as'1\<rightarrow>* sourcenode a2"
          and valid_edge2:"valid_edge a2"
          and path2:"targetnode a2 -asx'1\<rightarrow>* (_Exit_)"
          by(auto intro:path_split)
        with path1 have eq12:"sourcenode a1 = sourcenode a2"
          by(cases as'1,auto dest:path_det)
        from asx notin have "n \<notin> set (sourcenodes asx'1)"
          by(simp add:sourcenodes_def)
        with path2 have not_pd'2:"\<not> n postdominates targetnode a2"
          by(cases "asx'1 = []",auto simp:postdominate_def)
        from as' have "a1 \<in> set as'" by simp
        with eq12 last valid_edge2 have "n postdominates targetnode a2" by blast
        with not_pd'2 have False by simp
        thus ?thesis by simp
      qed
    qed
  qed
qed

lemma inner_node_dyn_standard_control_dependence_predecessor:
  assumes inner_node:"inner_node n"
  obtains n' as where "n' controls\<^sub>s n via as"
proof(atomize_elim)
  from inner_node obtain as' where pathExit:"n -as'\<rightarrow>* (_Exit_)"
    by(fastforce dest:inner_is_valid Exit_path)
  from inner_node obtain as where pathEntry:"(_Entry_) -as\<rightarrow>* n"
    by(fastforce dest:inner_is_valid Entry_path)
  with inner_node have notEmpty:"as \<noteq> []"
    by(auto elim:path.cases simp:inner_node_def)
  have "\<exists>a asx. (_Entry_) -a#asx\<rightarrow>* n \<and> n \<notin> set (sourcenodes (a#asx))"
  proof(cases "n \<in> set (sourcenodes as)")
    case True
    hence "\<exists>n'' \<in> set(sourcenodes as). n = n''" by simp
    then obtain ns' ns'' where nodes:"sourcenodes as = ns'@n#ns''"
      and notin:"\<forall>n'' \<in> set ns'. n \<noteq> n''"
      by(fastforce elim!:split_list_first_propE)
    from nodes obtain xs ys a'
      where xs:"sourcenodes xs = ns'" and as:"as = xs@a'#ys"
      and source:"sourcenode a' = n"
      by(fastforce elim:map_append_append_maps simp:sourcenodes_def)
    from pathEntry as have "(_Entry_) -xs@a'#ys\<rightarrow>* n" by simp
    hence path2:"(_Entry_) -xs\<rightarrow>* sourcenode a'"
      by(fastforce dest:path_split)
    show ?thesis
    proof(cases "xs = []")
      case True
      with path2 have "(_Entry_) = sourcenode a'" by(auto elim:path.cases)
      with pathEntry source notEmpty have "(_Entry_) -as\<rightarrow>* (_Entry_) \<and> as \<noteq> []"
        by(auto elim:path.cases)
      hence False by(fastforce dest:path_Entry_target)
      thus ?thesis by simp
    next
      case False
      then obtain n a'' xs' where "xs = a''#xs'" by(cases xs) auto
      with False path2 notin xs source show ?thesis by simp blast
    qed
  next
    case False
    from notEmpty obtain a as' where "as = a#as'" by (cases as) auto
    with False pathEntry show ?thesis by auto
  qed
  then obtain a asx where pathEntry':"(_Entry_) -a#asx\<rightarrow>* n"
    and notin:"n \<notin> set (sourcenodes (a#asx))" by blast
  show "\<exists>n' as. n' controls\<^sub>s n via as"
  proof(cases "\<forall>a' a''. a' \<in> set asx \<and> sourcenode a' = sourcenode a'' \<and>
      valid_edge a'' \<longrightarrow> n postdominates targetnode a''")
    case True
    from inner_node have not_pd:"\<not> n postdominates (_Exit_)"
      by(fastforce intro:empty_path simp:postdominate_def sourcenodes_def)
    from pathEntry' have path':"(_Entry_) -[]@a#asx\<rightarrow>* n" by simp
    hence eq:"sourcenode a = (_Entry_)"
      by(fastforce dest:path_split elim:path.cases)
    from Entry_Exit_edge obtain a' where "sourcenode a' = (_Entry_)"
      and "targetnode a' = (_Exit_)" and "valid_edge a'" by auto
    with path' inner_node not_pd True eq notin pathExit
    have "sourcenode a controls\<^sub>s n via a#asx"
      by -(erule which_node_dyn_standard_control_dependence_source,auto)
    thus ?thesis by blast
  next
    case False
    hence "\<exists>a' \<in> set asx. \<exists>a''. sourcenode a' = sourcenode a'' \<and> valid_edge a'' \<and>
      \<not> n postdominates targetnode a''"
      by fastforce
    then obtain ax asx' asx'' where "asx = asx'@ax#asx'' \<and>
      (\<exists>a''. sourcenode ax = sourcenode a'' \<and> valid_edge a'' \<and>
      \<not> n postdominates targetnode a'') \<and>
      (\<forall>z \<in> set asx''. \<not> (\<exists>a''. sourcenode z = sourcenode a'' \<and> valid_edge a'' \<and>
      \<not> n postdominates targetnode a''))"
      by(blast elim!:rightmost_element_property)
    then obtain a'' where as':"asx = asx'@ax#asx''"
      and eq:"sourcenode ax = sourcenode a''"
      and valid_edge:"valid_edge a''"
      and not_pd:"\<not> n postdominates targetnode a''"
      and last:"\<forall>z \<in> set asx''. \<not> (\<exists>a''. sourcenode z = sourcenode a'' \<and>
        valid_edge a'' \<and> \<not> n postdominates targetnode a'')"
      by blast
    from notin as' have notin':"n \<notin> set (sourcenodes (ax#asx''))"
      by(auto simp:sourcenodes_def)
    from as' pathEntry' have "(_Entry_) -(a#asx')@ax#asx''\<rightarrow>* n" by simp
    with inner_node not_pd notin' eq last pathExit valid_edge
    have "sourcenode ax controls\<^sub>s n via ax#asx''"
      by(fastforce elim!:which_node_dyn_standard_control_dependence_source)
    thus ?thesis by blast
  qed
qed

end

end


section \<open> Events for Reactive Processes \<close>

theory utp_rea_event
imports "UTP2.utp" "Shallow-Expressions.Shallow_Expressions"
begin

subsection \<open> Events \<close>

text \<open> Events of some type @{typ "'\<theta>"} are just the elements of that type. \<close>

type_synonym '\<theta> event = "'\<theta>"

subsection \<open> Channels \<close>

text \<open>
  Typed channels are modelled as prisms. Below, @{typ "'a"} determines the
  channel type and @{typ "'\<theta>"} the underlying event alphabet type. As with values, it
  is difficult to introduce channels as monomorphic types due to the fact that
  they can have arbitrary parametrisations in term of @{typ "'a"}. Applying a
  channel to an element of its type yields an event, as we may expect. Though
  this is not formalised here, we may also sensibly assume that all channel-
  representing functions are injective.
\<close>

type_synonym ('a, '\<theta>) chan = "'a \<Longrightarrow>\<^sub>\<triangle> '\<theta> event"

text \<open>
  A downside of the approach is that the event type @{typ "'\<theta>"} must be able
  to encode \emph{all} events of a process model, and hence cannot be fixed
  upfront for a single channel or channel set. To do so, we actually require
  a notion of `extensible' datatypes, in analogy to extensible record types.
  Another solution is to encode a notion of channel scoping that namely uses
  @{type sum} types to lift channel types into extensible ones, that is using
  channel-set specific scoping operators. This is a current work in progress.
\<close>

subsubsection \<open> Operators \<close>

text \<open>
  The next lifted function creates an expression that yields a channel event,
  from an expression on the channel type @{typ "'a"}.
\<close>

definition chan_apply ::
  "('a, '\<theta>) chan \<Rightarrow> ('a, '\<alpha>) expr \<Rightarrow> ('\<theta> event, '\<alpha>) expr" ("'(_\<cdot>/_')\<^sub>u") where
[pred]: "(c\<cdot>e)\<^sub>u = build\<^bsub>c\<^esub> \<circ> e"

lemma unrest_chan_apply [unrest]: "x \<sharp> e \<Longrightarrow> x \<sharp> (c\<cdot>e)\<^sub>u"
  by pred_auto

lemma usubst_chan_apply [usubst]: "\<sigma> \<dagger> (c\<cdot>v)\<^sub>u = (c\<cdot>\<sigma> \<dagger> v)\<^sub>u"
  by pred_auto

(* TODO: what should this be added to: [alpha] *)
lemma aext_event: "(c\<cdot>v)\<^sub>u \<up> a = (c\<cdot>v \<up> a)\<^sub>u"
  by pred_auto

end


theory Analyze_medium_sized_company
imports
  Iptables_Semantics.Parser
begin

parse_iptables_save company_fw="iptables-save"

thm company_fw_def
thm company_fw_INPUT_default_policy_def

value[code] "map (\<lambda>(c,rs). (c, map (quote_rewrite \<circ> common_primitive_rule_toString) rs)) company_fw"

definition "unfolded_INPUT = unfold_ruleset_INPUT company_fw_INPUT_default_policy (map_of_string_ipv4 (company_fw))"

value[code] "map (quote_rewrite \<circ> common_primitive_rule_toString) (unfolded_INPUT)"

value[code] "map (quote_rewrite \<circ> common_primitive_rule_toString) (upper_closure unfolded_INPUT)"

value[code] "upper_closure (packet_assume_new unfolded_INPUT)"

lemma "check_simple_fw_preconditions
    (upper_closure (optimize_matches abstract_for_simple_firewall
      (upper_closure (packet_assume_new unfolded_INPUT))))" by eval

value[code] "map simple_rule_ipv4_toString (to_simple_firewall
    (upper_closure (optimize_matches abstract_for_simple_firewall (upper_closure (packet_assume_new unfolded_INPUT)))))"

value[code] "map simple_rule_ipv4_toString (to_simple_firewall
    (lower_closure (optimize_matches abstract_for_simple_firewall (lower_closure (packet_assume_new unfolded_INPUT)))))"

definition "unfolded_FORWARD = unfold_ruleset_FORWARD company_fw_FORWARD_default_policy (map_of_string_ipv4 (company_fw))"

value[code] "map (quote_rewrite \<circ> common_primitive_rule_toString) (unfolded_FORWARD)"

value[code] "map (quote_rewrite \<circ> common_primitive_rule_toString) (upper_closure unfolded_FORWARD)"

value[code] "upper_closure (packet_assume_new unfolded_FORWARD)"

lemma "check_simple_fw_preconditions
    (upper_closure (optimize_matches abstract_for_simple_firewall (upper_closure (packet_assume_new unfolded_FORWARD))))" by eval

value[code] "map simple_rule_ipv4_toString (to_simple_firewall
    (upper_closure (optimize_matches abstract_for_simple_firewall (upper_closure (packet_assume_new unfolded_FORWARD)))))"

value[code] "map simple_rule_ipv4_toString (to_simple_firewall
    (lower_closure (optimize_matches abstract_for_simple_firewall (lower_closure (packet_assume_new unfolded_FORWARD)))))"

lemma "simple_fw_valid (to_simple_firewall
    (upper_closure (optimize_matches abstract_for_simple_firewall (upper_closure (packet_assume_new unfolded_FORWARD)))))"
  by eval

lemma "simple_fw_valid (to_simple_firewall
    (lower_closure (optimize_matches abstract_for_simple_firewall (lower_closure (packet_assume_new unfolded_FORWARD)))))"
  by eval
(*
text{*If we call the IP address spcae partitioning incorrectly (not prepocessed, still has interfaces), we get an error*}
value[code] " parts_connection_ssh
  (to_simple_firewall (upper_closure (optimize_matches abstract_for_simple_firewall (upper_closure (packet_assume_new unfolded_FORWARD)))))"
*)

(*Interfaces be gone! necessary for ip partition!*)
definition preprocess where
  "preprocess unfold closure ipassmt def fw \<equiv> to_simple_firewall (closure
              (optimize_matches (abstract_primitive (\<lambda>r. case r of Pos a \<Rightarrow> is_Iiface a \<or> is_Oiface a \<or> is_L4_Flags a | Neg a \<Rightarrow> is_Iiface a \<or> is_Oiface a \<or> is_Prot a \<or> is_L4_Flags a))
              (closure
              (iface_try_rewrite ipassmt None
              (closure
              (packet_assume_new
              (unfold def (map_of fw))))))))"

 definition "ipassmt = [(Iface ''lo'', [(ipv4addr_of_dotdecimal (127,0,0,0),8)]),
  (Iface ''eth0'', [(ipv4addr_of_dotdecimal (172,16,2,0),24)])
  ]"

lemma "access_matrix_pretty_ipv4 parts_connection_ssh
    (preprocess unfold_ruleset_FORWARD upper_closure ipassmt company_fw_FORWARD_default_policy company_fw) =
 ([(''46.4.115.113'',
    ''46.4.115.113 u {46.20.32.74 .. 46.20.32.75} u 54.68.106.202 u 62.141.33.131 u ''@
    ''63.245.217.112 u 74.119.117.71 u 80.190.166.25 u 80.237.184.24 u 80.252.91.41 u ''@
    ''82.196.187.209 u 82.199.80.141 u 83.133.189.139 u 83.169.54.252 u 83.169.59.64 u ''@
    ''85.25.248.94 u 85.90.254.45 u 85.195.127.21 u 88.198.208.110 u 91.215.101.185 u ''@
    ''93.184.220.20 u 93.184.221.133 u 94.198.59.132 u 94.198.59.134 u 95.131.121.65 u ''@
    ''95.131.121.199 u 95.172.69.42 u 144.76.67.119 u 151.80.102.139 u 176.9.103.51 u ''@
    ''178.63.153.114 u 178.250.0.101 u 178.250.2.73 u 178.250.2.77 u 178.250.2.98 u ''@
    ''178.250.2.102 u 184.168.47.225 u 188.65.74.70 u 194.97.151.143 u 194.97.153.231 u ''@
    ''194.126.239.34 u 195.20.250.231 u 206.191.168.170 u 212.45.104.69 u 212.227.67.37 u ''@
    ''213.9.42.248 u 213.203.221.32 u 213.203.221.43 u 216.38.172.131 u 217.72.250.66 u 217.72.250.84 u 217.72.250.89''),
   (''192.168.255.0'',
    ''{192.168.255.0 .. 192.168.255.255}''),
   (''172.16.2.0'',
    ''{172.16.2.0 .. 172.16.2.15} u 172.16.2.34 u 172.16.2.230 u {172.16.2.247 .. 172.16.2.255}''),
   (''172.16.2.16'',
    ''{172.16.2.16 .. 172.16.2.33} u {172.16.2.35 .. 172.16.2.229} u {172.16.2.231 .. 172.16.2.246}''),
   (''0.0.0.0'',
    ''{0.0.0.0 .. 46.4.115.112} u {46.4.115.114 .. 46.20.32.73} u {46.20.32.76 .. 54.68.106.201} u ''@
    ''{54.68.106.203 .. 62.141.33.130} u {62.141.33.132 .. 63.245.217.111} u ''@
    ''{63.245.217.113 .. 74.119.117.70} u {74.119.117.72 .. 80.190.166.24} u ''@
    ''{80.190.166.26 .. 80.237.184.23} u {80.237.184.25 .. 80.252.91.40} u ''@
    ''{80.252.91.42 .. 82.196.187.208} u {82.196.187.210 .. 82.199.80.140} u ''@
    ''{82.199.80.142 .. 83.133.189.138} u {83.133.189.140 .. 83.169.54.251} u ''@
    ''{83.169.54.253 .. 83.169.59.63} u {83.169.59.65 .. 85.25.248.93} u ''@
    ''{85.25.248.95 .. 85.90.254.44} u {85.90.254.46 .. 85.195.127.20} u ''@
    ''{85.195.127.22 .. 88.198.208.109} u {88.198.208.111 .. 91.215.101.184} u ''@
    ''{91.215.101.186 .. 93.184.220.19} u {93.184.220.21 .. 93.184.221.132} u ''@
    ''{93.184.221.134 .. 94.198.59.131} u 94.198.59.133 u {94.198.59.135 .. 95.131.121.64} u ''@
    ''{95.131.121.66 .. 95.131.121.198} u {95.131.121.200 .. 95.172.69.41} u ''@
    ''{95.172.69.43 .. 144.76.67.118} u {144.76.67.120 .. 151.80.102.138} u ''@
    ''{151.80.102.140 .. 172.16.1.255} u {172.16.3.0 .. 176.9.103.50} u ''@
    ''{176.9.103.52 .. 178.63.153.113} u {178.63.153.115 .. 178.250.0.100} u ''@
    ''{178.250.0.102 .. 178.250.2.72} u {178.250.2.74 .. 178.250.2.76} u ''@
    ''{178.250.2.78 .. 178.250.2.97} u {178.250.2.99 .. 178.250.2.101} u ''@
    ''{178.250.2.103 .. 184.168.47.224} u {184.168.47.226 .. 188.65.74.69} u ''@
    ''{188.65.74.71 .. 192.168.254.255} u {192.169.0.0 .. 194.97.151.142} u ''@
    ''{194.97.151.144 .. 194.97.153.230} u {194.97.153.232 .. 194.126.239.33} u ''@
    ''{194.126.239.35 .. 195.20.250.230} u {195.20.250.232 .. 206.191.168.169} u ''@
    ''{206.191.168.171 .. 212.45.104.68} u {212.45.104.70 .. 212.227.67.36} u ''@
    ''{212.227.67.38 .. 213.9.42.247} u {213.9.42.249 .. 213.203.221.31} u ''@
    ''{213.203.221.33 .. 213.203.221.42} u {213.203.221.44 .. 216.38.172.130} u ''@
    ''{216.38.172.132 .. 217.72.250.65} u {217.72.250.67 .. 217.72.250.83} u ''@
    ''{217.72.250.85 .. 217.72.250.88} u {217.72.250.90 .. 255.255.255.255}'')],
  [(''192.168.255.0'', ''172.16.2.0''),
   (''192.168.255.0'', ''172.16.2.16''),
   (''172.16.2.0'', ''192.168.255.0''),
   (''172.16.2.0'', ''172.16.2.0''),
   (''172.16.2.0'', ''172.16.2.16''),
   (''172.16.2.0'', ''0.0.0.0''),
   (''172.16.2.16'', ''192.168.255.0'')])" by eval (*the string @ takes quite some time*)

lemma "access_matrix_pretty_ipv4 parts_connection_http
    (preprocess unfold_ruleset_FORWARD upper_closure ipassmt company_fw_FORWARD_default_policy company_fw) =
 ([(''46.4.115.113'',
    ''46.4.115.113 u {46.20.32.74 .. 46.20.32.75} u 54.68.106.202 u 62.141.33.131 u 63.245.217.112 u 74.119.117.71 u 80.190.166.25 u 80.237.184.24 u 80.252.91.41 u 82.196.187.209 u 82.199.80.141 u 83.133.189.139 u 83.169.54.252 u 83.169.59.64 u 85.25.248.94 u 85.90.254.45 u 85.195.127.21 u 88.198.208.110 u 91.215.101.185 u 93.184.220.20 u 93.184.221.133 u 94.198.59.132 u 94.198.59.134 u 95.131.121.65 u 95.131.121.199 u 95.172.69.42 u 144.76.67.119 u 151.80.102.139 u 176.9.103.51 u 178.63.153.114 u 178.250.0.101 u 178.250.2.73 u 178.250.2.77 u 178.250.2.98 u 178.250.2.102 u 184.168.47.225 u 188.65.74.70 u 194.97.151.143 u 194.97.153.231 u 194.126.239.34 u 195.20.250.231 u 206.191.168.170 u 212.45.104.69 u 212.227.67.37 u 213.9.42.248 u 213.203.221.32 u 213.203.221.43 u 216.38.172.131 u 217.72.250.66 u 217.72.250.84 u 217.72.250.89''),
   (''192.168.255.0'',
    ''{192.168.255.0 .. 192.168.255.255}''),
   (''172.16.2.0'', ''{172.16.2.0 .. 172.16.2.255}''),
   (''0.0.0.0'',
    ''{0.0.0.0 .. 46.4.115.112} u {46.4.115.114 .. 46.20.32.73} u {46.20.32.76 .. 54.68.106.201} u {54.68.106.203 .. 62.141.33.130} u {62.141.33.132 .. 63.245.217.111} u {63.245.217.113 .. 74.119.117.70} u {74.119.117.72 .. 80.190.166.24} u {80.190.166.26 .. 80.237.184.23} u {80.237.184.25 .. 80.252.91.40} u {80.252.91.42 .. 82.196.187.208} u {82.196.187.210 .. 82.199.80.140} u {82.199.80.142 .. 83.133.189.138} u {83.133.189.140 .. 83.169.54.251} u {83.169.54.253 .. 83.169.59.63} u {83.169.59.65 .. 85.25.248.93} u {85.25.248.95 .. 85.90.254.44} u {85.90.254.46 .. 85.195.127.20} u {85.195.127.22 .. 88.198.208.109} u {88.198.208.111 .. 91.215.101.184} u {91.215.101.186 .. 93.184.220.19} u {93.184.220.21 .. 93.184.221.132} u {93.184.221.134 .. 94.198.59.131} u 94.198.59.133 u {94.198.59.135 .. 95.131.121.64} u {95.131.121.66 .. 95.131.121.198} u {95.131.121.200 .. 95.172.69.41} u {95.172.69.43 .. 144.76.67.118} u {144.76.67.120 .. 151.80.102.138} u {151.80.102.140 .. 172.16.1.255} u {172.16.3.0 .. 176.9.103.50} u {176.9.103.52 .. 178.63.153.113} u {178.63.153.115 .. 178.250.0.100} u {178.250.0.102 .. 178.250.2.72} u {178.250.2.74 .. 178.250.2.76} u {178.250.2.78 .. 178.250.2.97} u {178.250.2.99 .. 178.250.2.101} u {178.250.2.103 .. 184.168.47.224} u {184.168.47.226 .. 188.65.74.69} u {188.65.74.71 .. 192.168.254.255} u {192.169.0.0 .. 194.97.151.142} u {194.97.151.144 .. 194.97.153.230} u {194.97.153.232 .. 194.126.239.33} u {194.126.239.35 .. 195.20.250.230} u {195.20.250.232 .. 206.191.168.169} u {206.191.168.171 .. 212.45.104.68} u {212.45.104.70 .. 212.227.67.36} u {212.227.67.38 .. 213.9.42.247} u {213.9.42.249 .. 213.203.221.31} u {213.203.221.33 .. 213.203.221.42} u {213.203.221.44 .. 216.38.172.130} u {216.38.172.132 .. 217.72.250.65} u {217.72.250.67 .. 217.72.250.83} u {217.72.250.85 .. 217.72.250.88} u {217.72.250.90 .. 255.255.255.255}'')],
  [(''192.168.255.0'', ''172.16.2.0''),
   (''172.16.2.0'', ''192.168.255.0''),
   (''172.16.2.0'', ''172.16.2.0''),
   (''172.16.2.0'', ''0.0.0.0'')])" by eval

end


theory ELenses
imports Lenses
begin

  (* TODO: We could use (\<lambda>_::unit. undefined) to realize a 'default' lifting operation
    from plain lenses to elenses.

    For lifting optionals to elenses, we could use a default type class.

    Then, we could define coercions to do the lifting automatically!
  *)

  definition "lift f m \<equiv> case m of None \<Rightarrow> Inl f | Some x \<Rightarrow> Inr x"
  definition "lower m \<equiv> case m of Inl _ \<Rightarrow> None | Inr x \<Rightarrow> Some x"

  definition "pre m \<equiv> case m of Inl e \<Rightarrow> Some e | _ \<Rightarrow> None"

  lemma pre_simps[simp]: "pre (Inr x) = None" "pre (Inl l) = Some l"
    by (auto simp: pre_def split: sum.splits)

  lemma pre_eq_conv[simp]:
    "pre m = None \<longleftrightarrow> (\<exists>r. m = Inr r)"
    "pre m = Some l \<longleftrightarrow> (m = Inl l)"
    by (auto simp: pre_def split: sum.splits)

  lemma lift_simps[simp]:
    "lift f (None) = Inl f"
    "lift f (Some x) = Inr x"
    by (auto simp: lift_def)

  lemma lift_invert[simp]:
    "lift f m = Inr x \<longleftrightarrow> m=Some x"
    "lift f m = Inl f' \<longleftrightarrow> f'=f \<and> m=None"
    unfolding lift_def
    by (auto split: option.splits)

  lemma lower_simps[simp]:
    "lower (Inl f) = None"
    "lower (Inr x) = Some x"
    by (auto simp: lower_def)

  lemma lower_invert[simp]:
    "lower m = None \<longleftrightarrow> (\<exists>f. m = Inl f)"
    "lower m = Some x \<longleftrightarrow> m = Inr x"
    by (auto simp: lower_def split: sum.splits)

  lemma lower_lift_id[simp]: "lower (lift f m) = m"
    by (auto simp: lower_def lift_def split: option.split)

  datatype ('a,'b,'e) elens = ELENS (eget: "'a \<Rightarrow> 'e + 'b") (eput: "'b \<Rightarrow> 'a \<Rightarrow> 'e+'a")

  lemma sum_eqI[intro?]:
    assumes "\<And>l. s = Inl l \<longleftrightarrow> s'=Inl l"
    assumes "\<And>r. s = Inr r \<longleftrightarrow> s'=Inr r"
    shows "s=s'"
    apply (cases s; cases s'; simp)
    using assms by auto

  lemma elens_eqI[intro?]:
    assumes "\<And>s x. eget L s = Inr x \<longleftrightarrow> eget L' s = Inr x"
    assumes "\<And>s x. eget L s = Inl x \<longleftrightarrow> eget L' s = Inl x"
    assumes "\<And>x s s'. eput L x s = Inr s' \<longleftrightarrow> eput L' x s = Inr s'"
    assumes "\<And>x s f. eput L x s = Inl f \<longleftrightarrow> eput L' x s = Inl f"
    shows "L = L'"
    apply (cases L; cases L'; simp)
    apply (intro conjI ext sum_eqI)
    using assms by simp_all

  definition "lift_get f g s \<equiv> lift f (g s)"
  definition "lift_put f p x s \<equiv> lift f (p x s)"
  definition "lift_lens f L \<equiv> ELENS (lift_get f (get L)) (lift_put f (put L))"

  definition "lower_get g s \<equiv> lower (g s)"
  definition "lower_put p x s \<equiv> lower (p x s)"
  definition "lower_lens L \<equiv> LENS (lower_get (eget L)) (lower_put (eput L))"

  lemma lower_lift_gp_id[simp]:
    "lower_get (lift_get f g) = g"
    "lower_put (lift_put f p) = p"
    by (auto
      del: ext intro!: ext
      simp: lower_get_def lift_get_def lower_put_def lift_put_def)

  lemma lower_lift_lens_id[simp]:
    "lower_lens (lift_lens f L) = L"
    by (cases L) (auto simp: lower_lens_def lift_lens_def)

  abbreviation "eget' L \<equiv> get' (lower_lens L)"
  abbreviation "eput' L \<equiv> put' (lower_lens L)"

  definition "epre_get L s \<equiv> pre (eget L s)"
  definition "epre_put L x s \<equiv> pre (eput L x s)"

  (*
  abbreviation "epre_get L \<equiv> pre_get (lower_lens L)"
  abbreviation "epre_put L \<equiv> pre_put (lower_lens L)"
  abbreviation "epre_put_single_point L \<equiv> pre_put_single_point (lower_lens L)"
  *)

  abbreviation "elens L \<equiv> lens (lower_lens L)"
  definition "ehlens L \<equiv> hlens (lower_lens L) \<and> (\<forall>x s f. eput L x s = Inl f \<longleftrightarrow> eget L s = Inl f)"

  lemma ehlens_imp_hlens[simp]: "ehlens L \<Longrightarrow> hlens (lower_lens L)"
    by (auto simp: ehlens_def)

  lemma ehlens_put_Inl_conv[simp]: "ehlens L \<Longrightarrow> eput L x s = Inl f \<longleftrightarrow> eget L s = Inl f"
    by (auto simp: ehlens_def)

  (* TODO: Is reducing to optionals actually the best way? *)
  lemma lower_epre_get[simp]: "epre_get L s = None \<Longrightarrow> pre_get (lower_lens L) s"
    by (auto simp: epre_get_def lower_lens_def lower_get_def)

  lemma lower_epre_put[simp]: "epre_put L x s = None \<Longrightarrow> pre_put_single_point (lower_lens L) x s"
    by (auto simp: epre_put_def lower_lens_def lower_put_def pre_put_single_point_def)

  lemma lower_epre_put'[simp]: "elens L \<Longrightarrow> epre_put L x s = None \<Longrightarrow> pre_put (lower_lens L) s"
    by (meson lower_epre_put pre_put_single_point)

  lemma eget_rewrite1[simp]: "epre_get L s = None \<Longrightarrow> eget L s = Inr (eget' L s)"
    apply (auto simp: epre_get_def)
    by (simp add: lower_get_def lower_lens_def)

  lemma eget_rewrite2[simp]: "eget L s = Inr x \<longleftrightarrow> epre_get L s = None \<and> x = eget' L s"
    by (auto simp: epre_get_def lower_get_def lower_lens_def)

  lemma eget_nopre_conv[simp]: "eget L s = Inl e \<longleftrightarrow> epre_get L s = Some e"
    unfolding epre_get_def
    by (auto)

  lemma eput_rewrite1[simp]: "epre_put L x s = None \<Longrightarrow> eput L x s = Inr (eput' L x s)"
    apply (auto simp: epre_put_def)
    by (simp add: lower_put_def lower_lens_def)

  lemma eput_rewrite2[simp]: "eput L x s = Inr s' \<longleftrightarrow> epre_put L x s = None \<and> s' = eput' L x s"
    by (auto simp: epre_put_def lower_put_def lower_lens_def)

  lemma eput_nopre_conv[simp]: "eput L x s = Inl e \<longleftrightarrow> epre_put L x s = Some e"
    unfolding epre_put_def
    by (auto simp: )

  lemma epre_get_imp_pre_put[simp]:
    "elens L \<Longrightarrow> epre_get L s = None \<Longrightarrow> epre_put L x s = None"
    unfolding epre_get_def epre_put_def
    apply (auto)
    by (smt LENS_downstage(2) epre_get_def epre_put_def lens.pre_get_imp_putI lift_simps(1) lower_epre_get lower_lens_def lower_lift_id lower_put_def option.exhaust pre_eq_conv(2))

  lemma epre_get_lift_conv[simp]:
    "epre_get (lift_lens e L) s = None \<longleftrightarrow> pre_get L s"
    "epre_get (lift_lens e L) s = Some e' \<longleftrightarrow> e'=e \<and> \<not>pre_get L s"
    by (auto simp: epre_get_def lift_lens_def lift_get_def pre_get_def)

  lemma epre_put_lift_conv[simp]:
    "epre_put (lift_lens e L) x s = None \<longleftrightarrow> pre_put_single_point L x s"
    "epre_put (lift_lens e L) x s = Some e' \<longleftrightarrow> e'=e \<and> \<not>pre_put_single_point L x s"
    by (auto simp: epre_put_def lift_lens_def lift_put_def pre_put_single_point_def)

  lemma ehlens_lift[simp]: "ehlens (lift_lens f L) \<longleftrightarrow> hlens L"
    unfolding ehlens_def
    apply auto
    done

  lemma ehlens_pre_put_conv[simp]: "ehlens L \<Longrightarrow> epre_put L x s = epre_get L s"
    unfolding ehlens_def
    apply auto
    by (metis option.exhaust)

  lemmas [simp] = epre_get_def[symmetric]
  lemma epre_get_ELENS[simp]: "epre_get (ELENS g p) s = pre (g s)"
    by (auto simp: epre_get_def)

  lemmas [simp] = epre_put_def[symmetric]
  lemma epre_put_ELENS[simp]: "epre_put (ELENS g p) x s = pre (p x s)"
    by (auto simp: epre_put_def)

  definition ebcomp :: "('a, 'b, 'f) elens \<Rightarrow> ('b, 'c, 'f) elens \<Rightarrow> ('a, 'c, 'f) elens"
    (infixl "\<bullet>" 80)
    where "ebcomp L1 L2 \<equiv> ELENS
      (\<lambda>s. case eget L1 s of Inl r \<Rightarrow> Inl r | Inr s \<Rightarrow> eget L2 s)
      (\<lambda>x s. case eget L1 s of Inl r \<Rightarrow> Inl r | Inr s' \<Rightarrow>
             (case eput L2 x s' of Inl r \<Rightarrow> Inl r | Inr s' \<Rightarrow> eput L1 s' s))
    "

  lemma ebcomp_assoc[simp]: "L1\<bullet>(L2\<bullet>L3) = L1\<bullet>L2\<bullet>L3"
    apply (cases L1; cases L2; cases L3; simp)
    unfolding ebcomp_def
    apply (auto split: sum.splits del: ext intro!: ext)
    done

  lemma ebcomp_lower[simp]: "lower_lens (L1 \<bullet> L2) = lower_lens L1 \<bullet>\<^sub>L lower_lens L2"
    apply (cases L1; cases L2; simp)
    unfolding ebcomp_def lower_lens_def comp\<^sub>L_def lower_get_def lower_put_def
    apply (auto split: sum.splits Option.bind_splits del: ext intro!: ext)
    done

  lemma ebcomp_elens[simp]: "elens L1 \<Longrightarrow> elens L2 \<Longrightarrow> elens (L1 \<bullet> L2)"
    by (simp)

  lemma ebcomp_pre_get[simp]: "epre_get (L1 \<bullet> L2) s = (case epre_get L1 s of
      None \<Rightarrow> epre_get L2 (eget' L1 s)
    | Some e \<Rightarrow> Some e)"
    by (auto simp: ebcomp_def split: option.splits sum.splits)

  lemma ebcomp_pre_put[simp]: "elens L1 \<Longrightarrow> epre_put (L1 \<bullet> L2) x s = (case epre_get L1 s of
      None \<Rightarrow> epre_put L2 x (eget' L1 s)
    | Some e \<Rightarrow> Some e)"
    by (auto simp: ebcomp_def split: option.splits sum.splits)

  lemma ebcomp_get'[simp]: "\<lbrakk>elens L1; elens L2; epre_get L1 s = None; epre_get L2 (eget' L1 s) = None\<rbrakk>
    \<Longrightarrow> eget' (L1 \<bullet> L2) s = eget' L2 (eget' L1 s)"
    by (auto)

  lemma ebcomp_put'[simp]: "\<lbrakk>elens L1; elens L2; epre_get L1 s = None; epre_put L2 x (eget' L1 s) = None\<rbrakk>
    \<Longrightarrow> eput' (L1 \<bullet> L2) x s =  eput' L1 (eput' L2 x (eget' L1 s)) s"
    by (auto)

  definition "eid\<^sub>L \<equiv> ELENS (Inr) (\<lambda>x _. Inr x)"

  lemma lift_id\<^sub>L[simp]: "lift_lens f id\<^sub>L = eid\<^sub>L"
    unfolding lift_lens_def eid\<^sub>L_def lift_get_def lift_put_def
    by (auto del: ext intro!: ext)

  lemma lower_eid\<^sub>L[simp]: "lower_lens eid\<^sub>L = id\<^sub>L"
    unfolding lower_lens_def id\<^sub>L_def eid\<^sub>L_def lower_get_def lower_put_def
    by (auto del: ext intro!: ext)

  lemma eget_eid\<^sub>L_Inl_conv[simp]: "eget eid\<^sub>L s \<noteq> Inl f"
    by (auto simp: eid\<^sub>L_def)

  lemma eput_eid\<^sub>L_Inl_conv[simp]: "eput eid\<^sub>L x s \<noteq> Inl f"
    by (auto simp: eid\<^sub>L_def)

  lemma eid\<^sub>L_pre[simp]: "epre_get eid\<^sub>L s = None" "epre_put eid\<^sub>L x s = None"
    by (auto simp: eid\<^sub>L_def)

  lemma eid_left_neutral[simp]:
    assumes [simp]: "elens L"
    shows
    "eid\<^sub>L \<bullet> L = L"
    by (rule elens_eqI; auto split: option.splits)

  lemma eid_right_neutral[simp]:
    assumes [simp]: "ehlens L"
    shows
    "L \<bullet> eid\<^sub>L = L"
    by (rule elens_eqI; auto split: option.splits)

hide_const (open) lift lower pre

end


(*  Title:      HOL/Auth/n_mutualExFsm_lemma_invs_on_rules.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_mutualExFsm Protocol Case Study*}

theory n_mutualExFsm_lemma_invs_on_rules imports n_mutualExFsm_lemma_inv__1_on_rules n_mutualExFsm_lemma_inv__2_on_rules n_mutualExFsm_lemma_inv__3_on_rules n_mutualExFsm_lemma_inv__4_on_rules n_mutualExFsm_lemma_inv__5_on_rules
begin
lemma invs_on_rules:
  assumes a1: "f \<in> invariants N" and a2: "r \<in> rules N"
  shows "invHoldForRule s f r (invariants N)"
  proof -
  have b1: "(\<exists> p__Inv0 p__Inv1. p__Inv0\<le>N\<and>p__Inv1\<le>N\<and>p__Inv0~=p__Inv1\<and>f=inv__1  p__Inv0 p__Inv1)\<or>
    (\<exists> p__Inv0. p__Inv0\<le>N\<and>f=inv__2  p__Inv0)\<or>
    (\<exists> p__Inv0 p__Inv1. p__Inv0\<le>N\<and>p__Inv1\<le>N\<and>p__Inv0~=p__Inv1\<and>f=inv__3  p__Inv0 p__Inv1)\<or>
    (\<exists> p__Inv0. p__Inv0\<le>N\<and>f=inv__4  p__Inv0)\<or>
    (\<exists> p__Inv0 p__Inv1. p__Inv0\<le>N\<and>p__Inv1\<le>N\<and>p__Inv0~=p__Inv1\<and>f=inv__5  p__Inv0 p__Inv1)"
  apply (cut_tac a1, auto) done
    moreover {
      assume c1: "(\<exists> p__Inv0 p__Inv1. p__Inv0\<le>N\<and>p__Inv1\<le>N\<and>p__Inv0~=p__Inv1\<and>f=inv__1  p__Inv0 p__Inv1)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac a2 c1, metis lemma_inv__1_on_rules) done
    }

    moreover {
      assume c1: "(\<exists> p__Inv0. p__Inv0\<le>N\<and>f=inv__2  p__Inv0)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac a2 c1, metis lemma_inv__2_on_rules) done
    }

    moreover {
      assume c1: "(\<exists> p__Inv0 p__Inv1. p__Inv0\<le>N\<and>p__Inv1\<le>N\<and>p__Inv0~=p__Inv1\<and>f=inv__3  p__Inv0 p__Inv1)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac a2 c1, metis lemma_inv__3_on_rules) done
    }

    moreover {
      assume c1: "(\<exists> p__Inv0. p__Inv0\<le>N\<and>f=inv__4  p__Inv0)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac a2 c1, metis lemma_inv__4_on_rules) done
    }

    moreover {
      assume c1: "(\<exists> p__Inv0 p__Inv1. p__Inv0\<le>N\<and>p__Inv1\<le>N\<and>p__Inv0~=p__Inv1\<and>f=inv__5  p__Inv0 p__Inv1)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac a2 c1, metis lemma_inv__5_on_rules) done
    }

  ultimately show "invHoldForRule s f r (invariants N)"
  by satx
qed

end


(*  Title:      HOL/Auth/n_german_lemma_inv__47_on_rules.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_german Protocol Case Study*}

theory n_german_lemma_inv__47_on_rules imports n_german_lemma_on_inv__47
begin
section{*All lemmas on causal relation between inv__47*}
lemma lemma_inv__47_on_rules:
  assumes b1: "r \<in> rules N" and b2: "(\<exists> p__Inv3 p__Inv4. p__Inv3\<le>N\<and>p__Inv4\<le>N\<and>p__Inv3~=p__Inv4\<and>f=inv__47  p__Inv3 p__Inv4)"
  shows "invHoldForRule s f r (invariants N)"
  proof -
  have c1: "(\<exists> j. j\<le>N\<and>r=n_SendReqS  j)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendReqEI  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendReqES  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvReq N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInvE  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInvS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_SendGntE N i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)\<or>
    (\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)\<or>
    (\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)"
  apply (cut_tac b1, auto) done
    moreover {
      assume d1: "(\<exists> j. j\<le>N\<and>r=n_SendReqS  j)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendReqSVsinv__47) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendReqEI  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendReqEIVsinv__47) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendReqES  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendReqESVsinv__47) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvReq N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvReqVsinv__47) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInvE  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInvEVsinv__47) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInvS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInvSVsinv__47) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendInvAckVsinv__47) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvInvAck  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvInvAckVsinv__47) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntSVsinv__47) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_SendGntE N i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_SendGntEVsinv__47) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntS  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntSVsinv__47) done
    }

    moreover {
      assume d1: "(\<exists> i. i\<le>N\<and>r=n_RecvGntE  i)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_RecvGntEVsinv__47) done
    }

    moreover {
      assume d1: "(\<exists> i d. i\<le>N\<and>d\<le>N\<and>r=n_Store  i d)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac b2 d1, metis n_StoreVsinv__47) done
    }

  ultimately show "invHoldForRule s f r (invariants N)"
  by satx
qed

end