theory Practical
imports Main
begin

(***************************First-order logic*************************************)

(*1 mark*)
lemma "A\<or>A \<longrightarrow> A"
  apply (rule impI)
  by (erule disjE)

(*1 mark*)
lemma "(P\<longrightarrow>R)\<longrightarrow>(\<not>P\<or>R)"
  apply (rule impI)
  apply (rule classical)
  apply (erule impE)
   apply (rule classical)
   apply (erule notE)
  apply (rule disjI1)
   apply assumption
  by (rule disjI2)

(*1 mark*)
lemma "(P\<and>Q\<longrightarrow>R)\<longrightarrow>P\<longrightarrow>Q\<longrightarrow>R"
  apply (rule impI)+
  apply (rule classical)
  apply (erule impE)
  by (rule conjI)

(*3 marks*)
lemma "\<not>\<not>P \<or> \<not>P"
  apply (rule classical)
  apply (rule disjI1)
  apply (rule notI)
  apply (erule notE)
  by (rule disjI2)

(*4 marks*)
lemma "(P\<or>R)\<longleftrightarrow>(\<not>(\<not>P\<and> \<not>R))"
 apply (rule iffI)
   apply (rule classical)
   apply (rule notI)
   apply (erule notE)
   apply (erule conjE)
   apply (rule classical)
   apply (rule notI)
   apply (erule notE)
   apply (erule conjE)
   apply (erule disjE)
    apply assumption
   apply (erule notE)
   apply assumption
  apply (rule classical)
  apply (erule notE)
  apply (rule conjI)
   apply (rule classical)
   apply (rule notI)
   apply (erule notE)
  apply (rule disjI1)
   apply assumption
  apply (rule classical)
  apply (rule notI)
  apply (erule notE)
  by (rule disjI2)

(*  apply (rule iffI)
   apply (rule classical)
   apply (rule notI)
   apply (erule notE)
   apply (erule conjE)
   apply (rule classical)
   apply (rule notI)
   apply (erule notE)
   apply (erule conjE)
   apply (erule disjE)
    apply assumption
   apply (erule notE)
   apply assumption
  apply (rule classical)
  apply (erule notE)
  apply (rule conjI)
   apply (rule classical)
   apply (rule notI)
   apply (erule notE)
   apply (rule disjI1)
   apply assumption
  apply (rule classical)
  apply (rule notI)
  apply (erule notE)
  by (rule disjI2) *)

(*1 mark*)
lemma "(\<forall> x . F x) \<and> (\<forall> x . G x ) \<longrightarrow> (\<forall> x . F x \<and> G x )"
  apply (rule impI)
  apply (erule conjE)
  apply (rule allI)
  apply (erule_tac x="x" in allE)+
  apply (rule conjI)
  by assumption

(*1 mark*)
lemma "(\<forall> x y. R x y) \<longrightarrow> (\<forall> x . R x x )"
  apply (rule impI)
  apply (rule allI)
  apply (erule_tac x="x" in allE)
  apply (erule_tac x="x" in allE)
  by assumption

(*3 marks*)
lemma "(\<forall>x. P x)\<or>(\<exists>x.\<not>P x)"

  apply (rule classical)
  apply (rule disjI1)
  apply (rule allI)
  apply (rule classical)
  apply (erule notE)
  apply (rule disjI2)
  by (rule_tac x="x" in exI)

(*3 marks*)
lemma "(\<forall>x. \<not> (P x \<longrightarrow> Q x)) \<longrightarrow> \<not>(\<exists>x. \<not>P x \<and> Q x)"
  apply (rule impI)
  apply (rule notI)
  apply (erule exE)
  apply (erule conjE)
  apply (erule notE)
  apply (erule allE)
  apply (rule classical)
  apply (erule notE)
  by (rule impI)

(*3 marks*)
lemma "\<exists>Bob. (drunk Bob \<longrightarrow> (\<forall>y. drunk y))"
  apply (rule classical)
  apply (rule_tac x="Bob" in exI)
  apply (rule impI)
  apply (rule allI)
  apply (rule ccontr)
  apply (erule notE)
  apply (rule exI)
  apply (rule impI)
  apply (rule allI)
  by (erule notE)

(*4 marks*)
lemma "\<not> (\<exists> barber . man barber \<and> (\<forall> x . man x \<and> \<not>shaves x x \<longleftrightarrow> shaves barber x ))"
  apply (rule notI)
  apply (erule exE)
  apply (erule conjE)
  apply (erule_tac x="barber" in allE)
  apply (erule iffE)
  apply (erule impE)
   apply (rule conjI)
    apply assumption
   apply (rule classical)
   apply (rule notI)
   apply (erule notE)
   apply (erule impE)
    apply assumption
   apply (erule conjE)
   apply assumption
  apply (erule impE)
   apply assumption
  apply (erule conjE)
  by (erule notE)

locale incidence =
  fixes incidence_points_on_sections :: "'point \<Rightarrow> 'section \<Rightarrow> bool" (infix " \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t " 80)
  fixes region_to_section :: "'region \<Rightarrow> 'section"
  assumes section_nonempty: "\<exists>point. point \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t section"
(*Write here your axiom stating that every section has
                                            a point incident to it*) (*2 marks*)
  and section_uniqueness:"(\<And>p. (p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t s1 \<longleftrightarrow> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t s2)) \<Longrightarrow> s1 = s2"
(*Write here your axiom stating that two sections are the same
                                      if the same points are incident to each*) (*2 marks*)
begin

definition isPartOf ::"'section \<Rightarrow> 'section \<Rightarrow> bool" (infix "isPartOf" 80) where
"a isPartOf b \<equiv> (\<forall>p.(p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t a \<longrightarrow> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b))"
(*write your formalisation of definition D1 here*) (*1 mark*)

definition inclusion ::"'region \<Rightarrow> 'section \<Rightarrow> bool"(infix "isIncludedIn" 80) where
"R isIncludedIn s \<equiv> (region_to_section R) isPartOf s"
(*write your formalisation of definition D2 here*) (*1 mark*)

definition overlaps ::"'region \<Rightarrow> 'section \<Rightarrow> bool"(infix "overlaps" 80) where
"R overlaps s \<equiv> \<exists>p. p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t (region_to_section R) \<and> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t s"
(*write your formalisation of definition D3 here*) (*1 mark*)

lemma region_overlaps_itself: "R overlaps (region_to_section R)"
proof-
  from section_nonempty
  have " \<exists>p. p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t (region_to_section R)" by blast
  hence "\<exists>p. p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t (region_to_section R) \<and> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t (region_to_section R)" by blast
  thus "R overlaps (region_to_section R)" using overlaps_def by blast
qed

(*Write your structured proof here*) (*2 marks*)

(*Formalise and prove that isPartOf is reflexive, transitive and antisymmetric*) (*3 marks*)
 lemma isPartOf_reflexive: "R isPartOf R"
 proof-
   from section_uniqueness
   have "\<forall>p. p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t R \<longrightarrow> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t R" by blast
   thus "R isPartOf R" using isPartOf_def by blast
 qed
(*Formalise and prove that isPartOf is reflexive here*)

lemma isPartOf_transitive:
  assumes 1:"(a isPartOf b) \<and> (b isPartOf c)" shows "a isPartOf c"
proof-
  from 1
  have "(\<forall>p1. p1 \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t a \<longrightarrow> p1 \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b) \<and> (\<forall>p2. p2 \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b \<longrightarrow> p2 \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t c)" using isPartOf_def by blast
  hence "\<forall>p. (p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t a \<longrightarrow> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b) \<and> (p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b \<longrightarrow> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t c)" by blast
  hence "\<forall>p. (\<not>(p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t a) \<or> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b) \<and> (\<not>(p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b) \<or> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t c)" by blast
  hence "\<forall>p. (\<not>(p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t a) \<or> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t c) \<and> (\<not>(p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b) \<or> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b)" by blast
  hence "\<forall>p. (\<not>(p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t a) \<or> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t c)" by blast
  hence "\<forall>p. p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t a \<longrightarrow> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t c" by blast
  thus "a isPartOf c" using isPartOf_def by blast
qed
(*Formalise and prove that isPartOf is transitive here*)

lemma isPartOf_antisymmetric:
  assumes 1:"a isPartOf b \<and> b isPartOf a" shows "a = b"
proof-
  from 1
  have "\<And>p. (p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t a \<longrightarrow> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b) \<and> (p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b \<longrightarrow> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t a)" using isPartOf_def by blast
  hence "\<And>p. (\<not>(p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t a) \<or> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b) \<and> (\<not>(p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b) \<or> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t a)" by blast
  hence "\<And>p. (p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t a) \<longleftrightarrow> (p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t b)" by blast
  thus "a = b" using section_uniqueness by blast
qed
(*Formalise and prove that isPartOf is antisymmetric here*)

end

locale section_bundles =  incidence incidence_points_on_sections region_to_section
  for  incidence_points_on_sections :: "'point \<Rightarrow> 'section \<Rightarrow> bool"
  and region_to_section :: "'region \<Rightarrow> 'section" +
  fixes crossing :: "'region \<Rightarrow> 'section \<Rightarrow> bool" (infix "crosses" 80)
  and incidence_sections_on_bundles :: "'section \<Rightarrow> 'bundle \<Rightarrow> bool" (infix "\<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n" 80)
assumes SC1: "(R crosses S \<Longrightarrow> R overlaps S)"
 (*Write your formalisation of Axiom SC1 here*) (*1 mark*)
 and SI1: "\<And>s. (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n S1 \<longleftrightarrow> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n S2) \<Longrightarrow> S1 = S2"
 (*Write your formalisation of Axiom SI1 here*)     (*1 mark*)
begin

definition atLeastAsRestrictiveAs :: "'section \<Rightarrow> 'bundle \<Rightarrow> 'section \<Rightarrow> bool" where
"atLeastAsRestrictiveAs s1 b s2 \<equiv> s1 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s2 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s1 isPartOf s2"
(*Write your formalisation of atLeastAsRestrictiveAs here*) (*1 mark*)

notation
  atLeastAsRestrictiveAs ("_ \<le>\<^sub>_ _" [80, 80, 80] 80)

(*Formalise and prove that atLeastAsRestrictiveAs is reflexive, transitive and antisymmetric*) (*2 marks*)

(*Kulik and Eschenbach say 'The relation \<ge> is reflexive, transitive and antisymmetric for a given
sector bundle.' So, do they mean, given that the sections under consideration are in the bundle?
This is what we assume for reflexivity.*)
lemma atLeastAsRestrictiveAs_reflexive:
  assumes 1:"s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b"  shows "s \<le>\<^sub>b s"
proof-
  from isPartOf_reflexive
  have "s isPartOf s" by blast
  hence "s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b  \<and> s isPartOf s" using 1 by blast
  thus "s \<le>\<^sub>b s" using atLeastAsRestrictiveAs_def by blast
qed

lemma atLeastAsRestrictiveAs_transitive:
  assumes 0:"s1 \<le>\<^sub>b s2 \<and> s2 \<le>\<^sub>b s3" shows "s1 \<le>\<^sub>b s3"
(*Formalise and prove that atLeastAsRestrictiveAs is transitive*)
proof-
  from 0
  have 1:"(s1 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s2 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s1 isPartOf s2 ) \<and> (s3 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s2 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s2 isPartOf s3)" using atLeastAsRestrictiveAs_def by blast
  hence 2: "s1 isPartOf s3" using isPartOf_transitive by blast
  hence "s1 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s3 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s1 isPartOf s3" using 1 2 by blast
  thus "s1 \<le>\<^sub>b s3" using atLeastAsRestrictiveAs_def by blast
qed

lemma atLeastAsRestrictiveAs_antisymmetric:
  assumes 1:"s1 \<le>\<^sub>b s2 \<and> s2 \<le>\<^sub>b s1" shows "s1 = s2"
(*Formalise and prove that atLeastAsRestrictiveAs is antisymmetric*)
proof-
  from 1
  have "(s1 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s1 isPartOf s2 ) \<and> (s2 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b  \<and> s2 isPartOf s1)" using atLeastAsRestrictiveAs_def by blast
    hence "s1 isPartOf s2 \<and> s2 isPartOf s1" by blast
      thus "s1 = s2" using isPartOf_antisymmetric by blast
qed

end

locale comparison = section_bundles incidence_points_on_sections region_to_section
 crossing incidence_sections_on_bundles
  for  incidence_points_on_sections :: "'point \<Rightarrow> 'section \<Rightarrow> bool" (infix "\<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t" 80)
  and region_to_section :: "'region \<Rightarrow> 'section"
  and crossing :: "'region \<Rightarrow> 'section \<Rightarrow> bool" (infix "crosses" 80)
  and incidence_sections_on_bundles :: "'section \<Rightarrow> 'bundle \<Rightarrow> bool" (infix "\<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n" 80)+
assumes SB2: "s1 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s2 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<Longrightarrow> s1 \<le>\<^sub>b s2 \<or> s2 \<le>\<^sub>b s1"
(*Write your formalisation of Axiom SB2 here*) (*1 mark*)
begin

lemma T1:
  assumes 1: "R overlaps s1" shows "(s1 \<le>\<^sub>b s2 \<Longrightarrow> R overlaps s2)"
  using assms atLeastAsRestrictiveAs_def isPartOf_def overlaps_def by auto
(*Write your formalisation and proof of Theorem T1 here*) (*1 mark*)
(* proof-
  from 1
  have 2:"\<exists>p. p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t (region_to_section R) \<and> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t s1" using overlaps_def by blast
  have 3:" s1 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s2 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s1 isPartOf s2" using 1 atLeastAsRestrictiveAs_def by blast
  hence "(\<forall>p.(p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t s1 \<longrightarrow> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t s2))" using isPartOf_def by blast
  hence "\<exists>p. p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t (region_to_section R) \<and> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t s2" using 2 3 by blast
  thus "R overlaps s2" using overlaps_def by blast
qed *)

lemma T2:
(*Write your formalisation and proof of Theorem T2 here*) (*1 mark*)
  assumes 1:"R isIncludedIn s" "s \<le>\<^sub>b s'" shows " (s \<le>\<^sub>b s' \<Longrightarrow> R isIncludedIn s')"
  using assms(1) atLeastAsRestrictiveAs_def inclusion_def isPartOf_transitive by blast

definition isCore (infix "isCoreOf" 80) where
"s isCoreOf b = (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> (\<forall>s'. s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> s \<le>\<^sub>b s'))"

definition isHull (infix "isHullOf" 80) where
"s isHullOf b = (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> (\<forall>s'. s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> s' \<le>\<^sub>b s))"
(*Write your definition of hull here*) (*1 mark*)

end

locale crossing_sector = comparison incidence_points_on_sections
          region_to_section crossing incidence_sections_on_bundles
          for incidence_points_on_sections :: "'point \<Rightarrow> 'section \<Rightarrow> bool" (infix "\<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t" 80)
and region_to_section :: "'region \<Rightarrow> 'section"
and crossing :: "'region \<Rightarrow> 'section \<Rightarrow> bool" (infix "crosses" 80)
and incidence_sections_on_bundles :: "'section \<Rightarrow> 'bundle \<Rightarrow> bool" (infix "\<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n" 80) +
assumes SC2: "R crosses s1 \<Longrightarrow> \<forall>s2. atLeastAsRestrictiveAs s2 S s1 \<longrightarrow> R crosses s2"
(*Write your formalisation of Axiom SC2 here*) (*1 mark*)
begin

lemma overlaps_core:
  assumes 1:"((R overlaps s) \<and> (s isCoreOf b))" shows "((s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R overlaps s'))"
proof-
  from 1
  have "((R overlaps s) \<and> (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> (s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> s \<le>\<^sub>b s')))" using isCore_def by blast
  hence "((s \<le>\<^sub>b s' \<longrightarrow> R overlaps s') \<and> (s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> s \<le>\<^sub>b s'))" using T1 by blast
  hence "((\<not>(s \<le>\<^sub>b s') \<or>  R overlaps s') \<and> (\<not>(s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b) \<or> s \<le>\<^sub>b s'))" by blast
  hence "(\<not>(s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b) \<or> R overlaps s') \<and> (\<not>(s \<le>\<^sub>b s') \<or> s \<le>\<^sub>b s')" by blast
  thus "(s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R overlaps s')" by blast
qed
(*Write your formalisation and structured proof of the remark `If a region
overlaps the core of a section bundle then it overlaps every section of the section bundle'*)
(*4 marks*)

lemma crosses_hull:
  assumes 1:"R crosses s \<and> s isHullOf b" shows "((s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R overlaps s'))"
proof-
  from 1
  have "((s' \<le>\<^sub>b s \<longrightarrow> R crosses s')) \<and> s isHullOf b" using SC2 by blast
  hence "((s' \<le>\<^sub>b s \<longrightarrow> R crosses s')) \<and> (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> (s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> s' \<le>\<^sub>b s))" using isHull_def by blast
  hence "(\<not>(s' \<le>\<^sub>b s) \<or> R crosses s') \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> (\<not>(s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b) \<or>  s' \<le>\<^sub>b s)" by blast
  hence "(\<not>(s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b) \<or> R crosses s') \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> (\<not>(s' \<le>\<^sub>b s) \<or> s' \<le>\<^sub>b s)" by blast
  thus "(s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b) \<longrightarrow> R overlaps s'" using SC1 by blast
qed
(*Write your formalisation and structured proof of the remark `If a region
crosses the hull of a section bundle then it crosses every sector of the section bundle'*)
(*4 marks*)

lemma not_overlap_hull:
  assumes 1: "\<not>R overlaps s \<and> s isHullOf b" shows "s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> \<not>R overlaps s'"
proof-
  from 1
  have "\<not>R overlaps s \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> (s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> s' \<le>\<^sub>b s)" using isHull_def by blast
  hence "\<not>R overlaps s \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> (\<not>(s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b) \<or> s' \<le>\<^sub>b s)" by blast
  hence "\<not>R overlaps s \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> \<not>(s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b) \<or> \<not>R overlaps s \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s' \<le>\<^sub>b s" by blast
  hence "\<not>(R overlaps s \<or> \<not>s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<or> (s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b)) \<or> \<not>R overlaps s \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s' \<le>\<^sub>b s" by blast
  hence "(R overlaps s \<or> \<not>s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<or> (s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b)) \<longrightarrow> \<not>R overlaps s \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s' \<le>\<^sub>b s" by blast
  hence "s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> \<not>R overlaps s \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s' \<le>\<^sub>b s" by blast
  hence "s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> \<not>R overlaps s' \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s' \<le>\<^sub>b s" using T1 by blast
  thus "s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> \<not>R overlaps s'" by blast
qed
(*Write your formalisation and structured proof of the remark `If a region
does not overlap the hull of a section bundle, it does not overlap any of its sections'*)
(*4 marks*)

definition overlapsAsMuchAs :: "'region \<Rightarrow> 'bundle \<Rightarrow> 'region \<Rightarrow> bool"  where
"overlapsAsMuchAs R b R' == (\<forall>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R' overlaps s \<longrightarrow> R overlaps s)"

notation
  overlapsAsMuchAs ("_ \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>_ _" [80, 80, 80] 80)

definition eq_overlapsAsMuchAs :: "'region \<Rightarrow> 'bundle \<Rightarrow> 'region \<Rightarrow> bool"  where
"eq_overlapsAsMuchAs R b R' == R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<and> R' \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R"

notation
  eq_overlapsAsMuchAs ("_ \<cong>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>_ _" [80, 80, 80] 80)

abbreviation
rev_overlapsAsMuchAs :: "'region \<Rightarrow> 'bundle \<Rightarrow> 'region \<Rightarrow> bool"  ("_ \<le>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>_ _" [80, 80, 80] 80)
where"rev_overlapsAsMuchAs R b R' == overlapsAsMuchAs R' b R"

definition more_overlapsAsMuchAs :: "'region \<Rightarrow> 'bundle \<Rightarrow> 'region \<Rightarrow> bool"  where
"more_overlapsAsMuchAs R b R' == R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<and> \<not>(R' \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R)"

notation
  more_overlapsAsMuchAs ("_ >\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>_ _" [80, 80, 80] 80)

abbreviation
less_overlapsAsMuchAs :: "'region \<Rightarrow> 'bundle \<Rightarrow> 'region \<Rightarrow> bool"  ("_ <\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>_ _" [80, 80, 80] 80)
where"less_overlapsAsMuchAs R b R' == more_overlapsAsMuchAs R' b R"

(*Formalise and prove that overlapsAsMuchAs is reflexive and transitive*) (*2 marks*)

lemma overlapsAsMuchAs_reflexive:"R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R"
  by (simp add: overlapsAsMuchAs_def)
(*Write your formalisation and proof that overlapsAsMuchAs is reflexive here*)

lemma overlapsAsMuchAs_transitive:"A \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b B \<and> B \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b C \<Longrightarrow> A \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b C"
  by (simp add: overlapsAsMuchAs_def)
(*Write your formalisation and proof that overlapsAsMuchAs is transitive here*)

lemma T3: "(R >\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R') = (\<exists>s. (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> R overlaps s \<and> \<not>(R' overlaps s)))"
 proof-
   { assume 1:"(\<exists>s. (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> R overlaps s \<and> \<not>(R' overlaps s)))"
  from 1
  have "\<forall>s'.\<exists>s.(s \<le>\<^sub>b s' \<or> s' \<le>\<^sub>b s \<or> \<not> s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b) \<and> R overlaps s \<and> \<not>(R' overlaps s) \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b" using SB2 by blast
  hence "\<forall>s'.\<exists>s.(R overlaps s' \<or> \<not>(R' overlaps s') \<or> \<not> s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b) \<and> R overlaps s \<and> \<not>(R' overlaps s) \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b" using T1 by blast
  hence "\<forall>s'.\<exists>s.(R' overlaps s'\<longrightarrow> R overlaps s' \<or> \<not> s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b) \<and> R overlaps s \<and> \<not>(R' overlaps s) \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b" by blast
  hence "\<forall>s'.\<exists>s.(s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R' overlaps s'\<longrightarrow> R overlaps s') \<and> R overlaps s \<and> \<not>(R' overlaps s) \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b" by blast
  hence "\<exists>s. (R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<and> R overlaps s \<and> \<not>(R' overlaps s) \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b)" using overlapsAsMuchAs_def by blast
  hence "\<exists>s. \<not>(\<not>R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<or> \<not>R overlaps s \<or> R' overlaps s \<or> \<not>s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b)" by blast
  hence "\<exists>s. \<not>(\<not>R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<or> (R overlaps s \<longrightarrow> R' overlaps s) \<or> \<not>s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b)" by blast
  hence "\<exists>s. \<not>(\<not>R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<or> (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R overlaps s \<longrightarrow> R' overlaps s))" by blast
  hence "\<exists>s. R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<and> \<not>(s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R overlaps s \<longrightarrow> R' overlaps s)" by blast
  hence "R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<and> \<not>R' \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R" using overlapsAsMuchAs_def by blast
  hence f1:"R >\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R'" using more_overlapsAsMuchAs_def by blast}

  moreover
  {assume 2: "R >\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R'"
  from 2
  have "R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<and> \<not>(R' \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R)" using more_overlapsAsMuchAs_def by blast
  hence "(\<forall>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R' overlaps s \<longrightarrow> R overlaps s) \<and> \<not>(\<forall>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R overlaps s \<longrightarrow> R' overlaps s)" using overlapsAsMuchAs_def by blast
  hence "(\<forall>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> \<not> R' overlaps s \<or> R overlaps s) \<and> \<not>(\<forall>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> \<not> R overlaps s \<or>  R' overlaps s)" by blast
  hence "(\<forall>s. \<not> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<or> \<not> R' overlaps s \<or> R overlaps s) \<and> \<not>(\<forall>s. \<not> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<or> \<not> R overlaps s \<or> R' overlaps s)" by blast
  hence "(\<forall>s. \<not> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<or> \<not> R' overlaps s \<or> R overlaps s) \<and> (\<exists>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> R overlaps s \<and> \<not> R' overlaps s)" by blast
  hence "\<exists>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> R overlaps s \<and> \<not> R' overlaps s" by blast
  hence f2:"(\<exists>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> R overlaps s \<and> \<not> R' overlaps s)"  by blast}

  ultimately
  have  "(R >\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R') = (\<exists>s. (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> R overlaps s \<and> \<not>(R' overlaps s)))" by blast
  thus "(R >\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R') = (\<exists>s. (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> R overlaps s \<and> \<not>(R' overlaps s)))" by blast

qed

(* "overlapsAsMuchAs R b R' == (\<forall>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R' overlaps s \<longrightarrow> R overlaps s)" *)
(* assumes SB2: "s1 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s2 \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<Longrightarrow> s1 \<le>\<^sub>b s2 \<or> s2 \<le>\<^sub>b s1" *)
(*   assumes 1:"R overlaps s1" shows "(s1 \<le>\<^sub>b s2 \<Longrightarrow> R overlaps s2)"  *)

  (* by (smt T1 comparison.SB2 comparison_axioms more_overlapsAsMuchAs_def overlapsAsMuchAs_def) *)
(*Write your formalisation and structured proof of Theorem T3 here. You must attempt to
formalise Kulik et al.'s reasoning*) (*11 marks*)

(*In under 200 words, compare and contrast the mechanical proof that you produced with the
pen-and-paper proof by Kulik et al.\. In particular, indicate any reasoning, proof parts, and/or
useful lemmas that you had to make explicit during the mechanisation but may have been glossed over
 or assumed by the pen-and-paper proof. Also highlight any inaccuracies in their language or
notation. Note any parts where you had to diverge from their reasoning, and why.
Write your answer in a comment here.*) (*4 marks*)

lemma T4: "R >\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<or> R \<cong>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<or> R <\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R'"
  using T3 eq_overlapsAsMuchAs_def overlapsAsMuchAs_def by auto
(*Write your formalisation and proof of Theorem T4 here*) (*1 mark*)

lemma T5: "R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<or> R \<le>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R'"
(*  using T4 eq_overlapsAsMuchAs_def more_overlapsAsMuchAs_def by auto *)
proof-
  from T4
  have "(R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<and> \<not>(R' \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R)) \<or> R \<cong>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<or> (R' \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R \<and> \<not>(R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R'))" using more_overlapsAsMuchAs_def by blast
  hence "(R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<and> \<not>(R' \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R)) \<or> (R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<and> R' \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R) \<or> (R' \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R \<and> \<not>(R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R'))" using eq_overlapsAsMuchAs_def by blast
  thus "(R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R' \<or> R' \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R)" by blast
qed
 (*Write your formalisation and structured proof of Theorem T5 here.
You must show it follows from T4*) (*3 marks*)

(********************Challenge problem****************************************)

(* definition isCore (infix "isCoreOf" 80) where
"s isCoreOf b = (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> (\<forall>s'. s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> s \<le>\<^sub>b s'))" *)

definition crosses_isIncludedIn :: "'region \<Rightarrow>'section \<Rightarrow> bool" where
"crosses_isIncludedIn R s = (R crosses s \<or> region_to_section R isPartOf s)"

(*Write your definition of the relation ci here.
Kulik et al. say `If a region crosses or is included in a section we write ci'.*) (*2 marks*)

definition crosses_isIncludedInAsMuchAs :: "'region \<Rightarrow> 'bundle \<Rightarrow> 'region \<Rightarrow> bool"  where
"crosses_isIncludedInAsMuchAs R b R' = (\<forall>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R' crosses s \<longrightarrow> R crosses s)"
(*Write your definition of `crosses or is included in as much
as' here*) (*2 marks*)

notation
  crosses_isIncludedInAsMuchAs ("_ \<ge>\<^sub>c\<^sub>i \<^sub>_ _" [80, 80, 80] 80)

definition belongsAsMuchAs :: "'region \<Rightarrow> 'bundle \<Rightarrow> 'region \<Rightarrow> bool" where
"belongsAsMuchAs R b R' = (R \<ge>\<^sub>c\<^sub>i \<^sub>b R' \<or> R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R')"
(*Write your definition of `belongs as much as here: definition D8 in
the paper.*) (*2 marks*)

notation
  belongsAsMuchAs ("_ \<ge> \<^sub>_ _" [80, 80, 80] 80)

(*Formalise and write structured proofs of Theorems T6-T8 for both crossesIncludedInAsMuchAs and
belongsAsMuchAs*) (*14 marks*)

lemma T6_crosses_isIncludedInAsMuchAs:
  assumes 1:"\<not> R overlaps s \<and> s isHullOf b" shows "(R' \<ge>\<^sub>c\<^sub>i \<^sub>b R)"
  using SC1 assms crosses_isIncludedInAsMuchAs_def not_overlap_hull by blast
(* proof-
  from 1

qed *)
(* lemma not_overlap_hull:
  assumes 1: "\<not>R overlaps s \<and> s isHullOf b" shows "s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> \<not>R overlaps s'"

"crosses_isIncludedInAsMuchAs R b R' = (\<forall>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R' crosses s \<longrightarrow> R crosses s)"

assumes SC1: "(R crosses S \<Longrightarrow> R overlaps S)"

"R overlaps s \<equiv> \<exists>p. p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t (region_to_section R) \<and> p \<iota>\<^sub>p\<^sub>o\<^sub>i\<^sub>n\<^sub>t s"

"s isHullOf b = (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> (\<forall>s'. s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> s' \<le>\<^sub>b s))"

"overlapsAsMuchAs R b R' == (\<forall>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R' overlaps s \<longrightarrow> R overlaps s)" *)

(*  using SC1 crosses_isIncludedInAsMuchAs_def not_overlap_hull by blast *)

lemma T6_belongsAsMuchAs:
  assumes 1:"\<not> R overlaps s \<and> s isHullOf b" shows "\<forall>R'.(R' \<ge> \<^sub>b R)"
proof-
  from 1
  have "\<forall>R'.(R' \<ge>\<^sub>c\<^sub>i \<^sub>b R) \<or> \<not>(s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R crosses s \<longrightarrow> R' crosses s) \<and> s isHullOf b" using T6_crosses_isIncludedInAsMuchAs crosses_isIncludedInAsMuchAs_def by blast
  hence "\<forall>R'.(R' \<ge>\<^sub>c\<^sub>i \<^sub>b R) \<or> \<not>(s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> (\<not>R crosses s \<or> R' crosses s)) \<and> s isHullOf b" by blast
  hence "\<forall>R'.(R' \<ge>\<^sub>c\<^sub>i \<^sub>b R) \<or> \<not>(\<not>s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<or> \<not>R crosses s \<or> R' crosses s) \<and> s isHullOf b" by blast
  hence "\<forall>R'.(R' \<ge>\<^sub>c\<^sub>i \<^sub>b R) \<or> (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> R crosses s \<and> \<not>R' crosses s) \<and> s isHullOf b" by blast
  hence "\<forall>R'.(R' \<ge>\<^sub>c\<^sub>i \<^sub>b R) \<or> (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> R overlaps s \<and> \<not>R' crosses s) \<and> s isHullOf b" using SC1 by blast
  hence "\<forall>R'.(R' \<ge>\<^sub>c\<^sub>i \<^sub>b R) \<or> (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> R overlaps s \<and> \<not>R' crosses s \<and> (s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> s' \<le>\<^sub>b s))" using isHull_def by blast
  hence "\<forall>R'.(R' \<ge>\<^sub>c\<^sub>i \<^sub>b R) \<or> (s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> R overlaps s \<and> \<not>R' crosses s \<and> (\<not>s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<or> (s' \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<and> s' isPartOf s)))" using atLeastAsRestrictiveAs_def by blast
qed

(*  using T6_crosses_isIncludedInAsMuchAs assms belongsAsMuchAs_def by blast

"crosses_isIncludedInAsMuchAs R b R' = (\<forall>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R' crosses s \<longrightarrow> R crosses s)"

assumes SC1: "(R crosses S \<Longrightarrow> R overlaps S)"

lemma T6_crosses_isIncludedInAsMuchAs:
  assumes 1:"\<not> R overlaps s \<and> s isHullOf b" shows "\<forall>R'.(R' \<ge>\<^sub>c\<^sub>i \<^sub>b R)"

"overlapsAsMuchAs R b R' == (\<forall>s. s \<iota>\<^sub>s\<^sub>e\<^sub>c\<^sub>t\<^sub>i\<^sub>o\<^sub>n b \<longrightarrow> R' overlaps s \<longrightarrow> R overlaps s)"

"belongsAsMuchAs R b R' = (R \<ge>\<^sub>c\<^sub>i \<^sub>b R' \<or> R \<ge>\<^sub>o\<^sub>v\<^sub>e\<^sub>r\<^sub>l\<^sub>a\<^sub>p\<^sub>s \<^sub>b R')" *)

lemma T7_crosses_isIncludedInAsMuchAs: "R isIncludedIn s \<and> s isCoreOf b \<Longrightarrow> \<forall>R'.(R \<ge>\<^sub>c\<^sub>i \<^sub>b R')"
  sorry

lemma T7_belongsAsMuchAs: "R isIncludedIn s \<and> s isCoreOf b \<Longrightarrow> \<forall>R'.(R \<ge> \<^sub>b R')"
  by (meson T1 belongsAsMuchAs_def inclusion_def isCore_def isPartOf_def overlapsAsMuchAs_def overlaps_def region_overlaps_itself)

lemma T8_crosses_isIncludedInAsMuchAs: "R crosses s \<and> s isHullOf b \<Longrightarrow> \<forall>R'.(R \<ge>\<^sub>c\<^sub>i \<^sub>b R')"
  using SC2 crosses_isIncludedInAsMuchAs_def isHull_def by blast

lemma T8_belongsAsMuchAs: "R crosses s \<and> s isHullOf b \<Longrightarrow> \<forall>R'.(R \<ge> \<^sub>b R')"
  by (simp add: T8_crosses_isIncludedInAsMuchAs belongsAsMuchAs_def)

end

end


section \<open>Stuttering\<close>

theory Stuttering
imports
  Stuttering_Equivalence.StutterEquivalence
  LList_Prefixes
begin

  function nth_least_ext :: "nat set \<Rightarrow> nat \<Rightarrow> nat"
    where
      "enat k < esize A \<Longrightarrow> nth_least_ext A k = nth_least A k" |
      "enat k \<ge> esize A \<Longrightarrow> nth_least_ext A k = Suc (Max A + (k - card A))"
    by force+ termination by lexicographic_order

  lemma nth_least_ext_strict_mono:
    assumes "k < l"
    shows "nth_least_ext s k < nth_least_ext s l"
  proof (cases "enat l < esize s")
    case True
    have 1: "enat k < esize s" using assms True by (metis enat_ord_simps(2) less_trans)
    show ?thesis using nth_least_strict_mono assms True 1 by simp
  next
    case False
    have 1: "finite s" using False esize_infinite_enat by auto
    have 2: "enat l \<ge> esize s" using False by simp
    have 3: "l \<ge> card s" using 1 2 by simp
    show ?thesis
    proof (cases "enat k < esize s")
      case True
      have 4: "s \<noteq> {}" using True by auto
      have "nth_least_ext s k = nth_least s k" using True by simp
      also have "\<dots> \<le> Max s" using nth_least_le_Max 1 4 True by this
      also have "\<dots> < Suc (Max s)" by auto
      also have "\<dots> \<le> Suc (Max s + (l - card s))" by auto
      also have "Suc (Max s + (l - card s)) = nth_least_ext s l" using 2 by simp
      finally show ?thesis by this
    next
      case False
      have 4: "enat k \<ge> esize s" using False by simp
      have 5: "k \<ge> card s" using 1 4 by simp
      have "nth_least_ext s k = Suc (Max s + (k - card s))" using 4 by simp
      also have "\<dots> < Suc (Max s + (l - card s))" using assms 5 by simp
      also have "\<dots> = nth_least_ext s l" using 2 by simp
      finally show ?thesis by this
    qed
  qed

  definition stutter_selection :: "nat set \<Rightarrow> 'a llist \<Rightarrow> bool"
    where "stutter_selection s w \<equiv> 0 \<in> s \<and>
      (\<forall> k i. enat i < llength w \<longrightarrow> enat (Suc k) < esize s \<longrightarrow>
      nth_least s k < i \<longrightarrow> i < nth_least s (Suc k) \<longrightarrow> w ?! i = w ?! nth_least s k) \<and>
      (\<forall> i. enat i < llength w \<longrightarrow> finite s \<longrightarrow> Max s < i \<longrightarrow> w ?! i = w ?! Max s)"

  lemma stutter_selectionI[intro]:
    assumes "0 \<in> s"
    assumes "\<And> k i. enat i < llength w \<Longrightarrow> enat (Suc k) < esize s \<Longrightarrow>
      nth_least s k < i \<Longrightarrow> i < nth_least s (Suc k) \<Longrightarrow> w ?! i = w ?! nth_least s k"
    assumes "\<And> i. enat i < llength w \<Longrightarrow> finite s \<Longrightarrow> Max s < i \<Longrightarrow> w ?! i = w ?! Max s"
    shows "stutter_selection s w"
    using assms unfolding stutter_selection_def by auto
  lemma stutter_selectionD_0[dest]:
    assumes "stutter_selection s w"
    shows "0 \<in> s"
    using assms unfolding stutter_selection_def by auto
  lemma stutter_selectionD_inside[dest]:
    assumes "stutter_selection s w"
    assumes "enat i < llength w" "enat (Suc k) < esize s"
    assumes "nth_least s k < i" "i < nth_least s (Suc k)"
    shows "w ?! i = w ?! nth_least s k"
    using assms unfolding stutter_selection_def by auto
  lemma stutter_selectionD_infinite[dest]:
    assumes "stutter_selection s w"
    assumes "enat i < llength w" "finite s" "Max s < i"
    shows "w ?! i = w ?! Max s"
    using assms unfolding stutter_selection_def by auto

  lemma stutter_selection_stutter_sampler[intro]:
    assumes "linfinite w" "stutter_selection s w"
    shows "stutter_sampler (nth_least_ext s) (lnth w)"
  unfolding stutter_sampler_def
  proof safe
    show "nth_least_ext s 0 = 0" using assms(2) by (cases "enat 0 < esize s", auto)
    show "strict_mono (nth_least_ext s)" using strict_monoI nth_least_ext_strict_mono by blast
  next
    fix k i
    assume 1: "nth_least_ext s k < i" "i < nth_least_ext s (Suc k)"
    show "w ?! i = w ?! nth_least_ext s k"
    proof (cases "enat (Suc k)" "esize s" rule: linorder_cases)
      case less
      have "w ?! i = w ?! nth_least s k"
      proof (rule stutter_selectionD_inside)
        show "stutter_selection s w" using assms(2) by this
        show "enat i < llength w" using assms(1) by auto
        show "enat (Suc k) < esize s" using less by this
        show "nth_least s k < i" using 1(1) less by auto
        show "i < nth_least s (Suc k)" using 1(2) less by simp
      qed
      also have "w ?! nth_least s k = w ?! nth_least_ext s k" using less by auto
      finally show ?thesis by this
    next
      case equal
      have 2: "enat k < esize s" using equal by (metis enat_ord_simps(2) lessI)
      have 3: "finite s" using equal by (metis esize_infinite_enat less_irrefl)
      have 4: "\<And> i. i > Max s \<Longrightarrow> w ?! i = w ?! Max s" using assms 3 by auto
      have 5: "k = card s - 1" using equal 3 by (metis diff_Suc_1 enat.inject esize_set.simps(1))
      have "Max s = nth_least s (card s - 1)" using nth_least_Max 3 assms(2) by force
      also have "\<dots> = nth_least s k" unfolding 5 by rule
      also have "\<dots> = nth_least_ext s k" using 2 by simp
      finally have 6: "Max s = nth_least_ext s k" by this
      have "w ?! i = w ?! Max s" using 1(1) 4 6 by auto
      also have "\<dots> = w ?! nth_least_ext s k" unfolding 6 by rule
      finally show ?thesis by this
    next
      case greater
      have 2: "enat k \<ge> esize s" using greater by (metis Suc_ile_eq not_le)
      have 3: "finite s" using greater by (metis esize_infinite_enat less_asym)
      have 4: "\<And> i. i > Max s \<Longrightarrow> w ?! i = w ?! Max s" using assms 3 by auto
      have "w ?! i = w ?! Max s" using 1(1) 2 4 by auto
      also have "\<dots> = w ?! Suc (Max s + (k - card s))" using 4 by simp
      also have "\<dots> = w ?! nth_least_ext s k" using 2 by simp
      finally show ?thesis by this
    qed
  qed

  lemma stutter_equivI_selection[intro]:
    assumes "linfinite u" "linfinite v"
    assumes "stutter_selection s u" "stutter_selection t v"
    assumes "lselect s u = lselect t v"
    shows "lnth u \<approx> lnth v"
  proof (rule stutter_equivI)
    have 1: "llength (lselect s u) = llength (lselect t v)" unfolding assms(5) by rule
    have 2: "esize s = esize t" using 1 assms(1, 2) unfolding lselect_llength by simp
    show "stutter_sampler (nth_least_ext s) (lnth u)" using assms(1, 3) by rule
    show "stutter_sampler (nth_least_ext t) (lnth v)" using assms(2, 4) by rule
    show "lnth u \<circ> nth_least_ext s = lnth v \<circ> nth_least_ext t"
    proof (rule ext, unfold comp_apply)
      fix i
      show "u ?! nth_least_ext s i = v ?! nth_least_ext t i"
      proof (cases "enat i < esize s")
        case True
        have 3: "enat i < llength (lselect s u)" "enat i < llength (lselect t v)"
          using assms(1, 2) 2 True unfolding lselect_llength by auto
        have "u ?! nth_least_ext s i = u ?! nth_least s i" using True by simp
        also have "\<dots> = lselect s u ?! i" using 3(1) by simp
        also have "\<dots> = lselect t v ?! i" unfolding assms(5) by rule
        also have "\<dots> = v ?! nth_least t i" using 3(2) by simp
        also have "\<dots> = v ?! nth_least_ext t i" using True unfolding 2 by simp
        finally show "u ?! nth_least_ext s i = v ?! nth_least_ext t i" by this
      next
        case False
        have 3: "s \<noteq> {}" "t \<noteq> {}" using assms(3, 4) by auto
        have 4: "finite s" "finite t" using esize_infinite_enat 2 False by metis+
        have 5: "\<And> i. i > Max s \<Longrightarrow> u ?! i = u ?! Max s" using assms(1, 3) 4(1) by auto
        have 6: "\<And> i. i > Max t \<Longrightarrow> v ?! i = v ?! Max t" using assms(2, 4) 4(2) by auto
        have 7: "esize s = enat (card s)" "esize t = enat (card t)" using 4 by auto
        have 8: "card s \<noteq> 0" "card t \<noteq> 0" using 3 4 by auto
        have 9: "enat (card s - 1) < llength (lselect s u)"
          using assms(1) 7(1) 8(1) unfolding lselect_llength by simp
        have 10: "enat (card t - 1) < llength (lselect t v)"
          using assms(2) 7(2) 8(2) unfolding lselect_llength by simp
        have "u ?! nth_least_ext s i = u ?! Suc (Max s + (i - card s))" using False by simp
        also have "\<dots> = u ?! Max s" using 5 by simp
        also have "\<dots> = u ?! nth_least s (card s - 1)" using nth_least_Max 4(1) 3(1) by force
        also have "\<dots> = lselect s u ?! (card s - 1)" using lselect_lnth 9 by simp
        also have "\<dots> = lselect s u ?! (card t - 1)" using 2 4 by simp
        also have "\<dots> = lselect t v ?! (card t - 1)" unfolding assms(5) by rule
        also have "\<dots> = v ?! nth_least t (card t - 1)" using lselect_lnth 10 by simp
        also have "\<dots> = v ?! Max t" using nth_least_Max 4(2) 3(2) by force
        also have "\<dots> = v ?! Suc (Max t + (i - card t))" using 6 by simp
        also have "\<dots> = v ?! nth_least_ext t i" using 2 False by simp
        finally show ?thesis by this
      qed
    qed
  qed

  definition stuttering_invariant :: "'a word set \<Rightarrow> bool"
    where "stuttering_invariant A \<equiv> \<forall> u v. u \<approx> v \<longrightarrow> u \<in> A \<longleftrightarrow> v \<in> A"

  lemma stuttering_invariant_complement[intro!]:
    assumes "stuttering_invariant A"
    shows "stuttering_invariant (- A)"
    using assms unfolding stuttering_invariant_def by simp

  lemma stutter_equiv_forw_subst[trans]: "w\<^sub>1 = w\<^sub>2 \<Longrightarrow> w\<^sub>2 \<approx> w\<^sub>3 \<Longrightarrow> w\<^sub>1 \<approx> w\<^sub>3" by auto

  lemma stutter_sampler_build:
    assumes "stutter_sampler f w"
    shows "stutter_sampler (0 ## (Suc \<circ> f)) (a ## w)"
  unfolding stutter_sampler_def
  proof safe
    have 0: "f 0 = 0" using assms unfolding stutter_sampler_def by auto
    have 1: "f x < f y" if "x < y" for x y
      using assms that unfolding stutter_sampler_def strict_mono_def by auto
    have 2: "(0 ## (Suc \<circ> f)) x < (0 ## (Suc \<circ> f)) y" if "x < y" for x y
      using 1 that by (cases x; cases y) (auto)
    have 3: "w n = w (f k)" if "f k < n" "n < f (Suc k)" for k n
      using assms that unfolding stutter_sampler_def by auto
    show "(0 ## (Suc \<circ> f)) 0 = 0" by simp
    show "strict_mono (0 ## (Suc \<circ> f))" using 2 by rule
    show "(a ## w) n = (a ## w) ((0 ## (Suc \<circ> f)) k)"
      if "(0 ## (Suc \<circ> f)) k < n" "n < (0 ## (Suc \<circ> f)) (Suc k)" for k n
      using 0 3 that by (cases k; cases n) (force)+
  qed
  lemma stutter_extend_build:
    assumes "u \<approx> v"
    shows "a ## u \<approx> a ## v"
  proof -
    obtain f g where 1: "stutter_sampler f u" "stutter_sampler g v" "u \<circ> f = v \<circ> g"
      using stutter_equivE assms by this
    show ?thesis
    proof (intro stutter_equivI ext)
      show "stutter_sampler (0 ## (Suc \<circ> f)) (a ## u)" using stutter_sampler_build 1(1) by this
      show "stutter_sampler (0 ## (Suc \<circ> g)) (a ## v)" using stutter_sampler_build 1(2) by this
      show "(a ## u \<circ> 0 ## (Suc \<circ> f)) i = (a ## v \<circ> 0 ## (Suc \<circ> g)) i" for i
        using fun_cong[OF 1(3)] by (cases i) (auto)
    qed
  qed
  lemma stutter_extend_concat:
    assumes "u \<approx> v"
    shows "w \<frown> u \<approx> w \<frown> v"
    using stutter_extend_build assms by (induct w, force+)
  lemma build_stutter: "w 0 ## w \<approx> w"
  proof (rule stutter_equivI)
    show "stutter_sampler (Suc (0 := 0)) (w 0 ## w)"
    unfolding stutter_sampler_def
    proof safe
      show "(Suc (0 := 0)) 0 = 0" by simp
      show "strict_mono (Suc (0 := 0))" by (rule strict_monoI, simp)
    next
      fix k n
      assume 1: "(Suc (0 := 0)) k < n" "n < (Suc (0 := 0)) (Suc k)"
      show "(w 0 ## w) n = (w 0 ## w) ((Suc (0 := 0)) k)" using 1 by (cases n, auto)
    qed
    show "stutter_sampler id w" by rule
    show "w 0 ## w \<circ> (Suc (0 := 0)) = w \<circ> id" by auto
  qed
  lemma replicate_stutter: "replicate n (v 0) \<frown> v \<approx> v"
  proof (induct n)
    case 0
    show ?case using stutter_equiv_refl by simp
  next
    case (Suc n)
    have "replicate (Suc n) (v 0) \<frown> v = v 0 ## replicate n (v 0) \<frown> v" by simp
    also have "\<dots> = (replicate n (v 0) \<frown> v) 0 ## replicate n (v 0) \<frown> v" by (cases n, auto)
    also have "\<dots> \<approx> replicate n (v 0) \<frown> v" using build_stutter by this
    also have "\<dots> \<approx> v" using Suc by this
    finally show ?case by this
  qed

  lemma replicate_stutter': "u \<frown> replicate n (v 0) \<frown> v \<approx> u \<frown> v"
    using stutter_extend_concat replicate_stutter by this

end


theory T111
imports Main
begin
lemma "(
(\<forall> x::nat. \<forall> y::nat. meet(x, y) = meet(y, x)) &
(\<forall> x::nat. \<forall> y::nat. join(x, y) = join(y, x)) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. meet(x, meet(y, z)) = meet(meet(x, y), z)) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. join(x, join(y, z)) = join(join(x, y), z)) &
(\<forall> x::nat. \<forall> y::nat. meet(x, join(x, y)) = x) &
(\<forall> x::nat. \<forall> y::nat. join(x, meet(x, y)) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. mult(x, join(y, z)) = join(mult(x, y), mult(x, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. mult(join(x, y), z) = join(mult(x, z), mult(y, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. meet(x, over(join(mult(x, y), z), y)) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. meet(y, undr(x, join(mult(x, y), z))) = y) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. join(mult(over(x, y), y), x) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. join(mult(y, undr(y, x)), x) = x) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. mult(x, meet(y, z)) = meet(mult(x, y), mult(x, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. undr(x, join(y, z)) = join(undr(x, y), undr(x, z))) &
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. over(x, meet(y, z)) = join(over(x, y), over(x, z))) &
(\<forall> x::nat. \<forall> y::nat. invo(join(x, y)) = meet(invo(x), invo(y))) &
(\<forall> x::nat. \<forall> y::nat. invo(meet(x, y)) = join(invo(x), invo(y))) &
(\<forall> x::nat. invo(invo(x)) = x)
) \<longrightarrow>
(\<forall> x::nat. \<forall> y::nat. \<forall> z::nat. over(join(x, y), z) = join(over(x, z), over(y, z)))
"
nitpick[card nat=8,timeout=86400]
oops
end


theory maximum2
  imports "~~/src/HOL/Hoare/Hoare_Logic"
    "~~/src/HOL/Hoare/List"
begin

(* ******************* *)
(* ******************* *)
(* ******************* *)

definition maximum :: "nat list \<Rightarrow> nat" where
  "maximum l = foldr max l 0"

value "maximum [1,3,5,4,2]"    (* 5 *)
value "maximum []"             (* 0 *)

lemma max_hdtl_eq [simp] : "l \<noteq> [] \<Longrightarrow> max (hd l) (maximum (tl l)) = maximum l"
  apply (induct l)
  apply auto
  by (simp add: maximum_def)

(* ********* *)
(* * lemma * *)
(* ********* *)

(* 3 subgoals, 1., 2., 3. *)
(* 1. *)
lemma l1 : "max (maximum x) y = maximum l \<Longrightarrow>
       x \<noteq> [] \<Longrightarrow> y \<le> hd x \<Longrightarrow> max (maximum (tl x)) (hd x) = maximum l"
  by (metis max.assoc max.commute max_def max_hdtl_eq) (* Sledgehammer *)

(* 2. *)
lemma l2 : "max (maximum x) y = maximum l \<Longrightarrow>
       x \<noteq> [] \<Longrightarrow> \<not> y \<le> hd x \<Longrightarrow> max (maximum (tl x)) y = maximum l"
  by (metis max.assoc max.commute max_def max_hdtl_eq) (* Sledgehammer *)

(* 3. *)
lemma l3 : "max (maximum []) y = maximum l \<Longrightarrow> y = maximum l"
  by (simp add: maximum_def) (* Sledgehammer *)

(* ******** *)
(* * main * *)
(* ******** *)

theorem "VARS x y l
  {x = l \<and> y = 0}
  y := 0;
  WHILE x \<noteq> []
  INV {max (maximum x) y = maximum l}
  DO
    IF y \<le> hd x THEN
      y := hd x
    ELSE
      SKIP
    FI;
    x := tl x
  OD
  {y = maximum l}"
  apply vcg
  apply auto
  (* 3 subgoals, 1., 2., 3. *)
  by (simp_all add: l1 l2 l3)

end

(* END *)


section\<open>Miscellaneous technical lemmas\<close>

(*
  Title:   Miscellaneous_Lemmas.thy
  Authors: Angeliki Koutsoukou-Argyraki, Mantas Bakšys, and Chelsea Edmonds
  Affiliation: University of Cambridge
  Date: August 2022.
*)

theory Miscellaneous_Lemmas
  imports
    "HOL-Library.Indicator_Function"
    "HOL-Analysis.Convex"
begin

lemma set_pairs_filter_subset: "A \<subseteq> B \<Longrightarrow> {p . p \<in> A \<times> A \<and> P p} \<subseteq> {p. p \<in> B \<times> B \<and> P p}"
  by (intro subsetI) blast

lemma card_set_ss_indicator:
  assumes "A \<subseteq> B"
  assumes "finite B"
  shows "card A = (\<Sum> p \<in> B. indicator A p)"
proof -
  obtain C where ceq: "C = B - A" by blast
  then have beq: "B = A \<union> C" using assms by blast
  have bint: "A \<inter> C = {}" using ceq by blast
  have finite: "finite A" using assms finite_subset by auto
  have zero: "\<And> p. p \<in> C \<Longrightarrow> indicator (A) p = 0"
    by (simp add: ceq)
  then have "card A = (\<Sum> p \<in> A . indicator (A) p)"
    by simp
  also have "... = (\<Sum> p \<in> A . indicator A p) + (\<Sum> p \<in> C . indicator A p)"
    using zero by (metis add_cancel_left_right sum.neutral)
  finally show "card A = (\<Sum> p \<in> B. indicator A p)" using beq bint assms
    by (metis add.commute ceq sum.subset_diff)
qed

lemma card_cartesian_prod_square: "finite X \<Longrightarrow> card (X \<times> X) = (card X)^2"
  using card_cartesian_product by (simp add: power2_eq_square)

lemma (in ordered_ab_group_add) diff_strict1_mono:
  assumes "a > a'" "b \<le> b'"
  shows "a - b > a' - b'"
  using diff_strict_mono assms
  by (metis local.diff_strict_right_mono local.dual_order.not_eq_order_implies_strict)

lemma card_cartesian_product_6: "card (A \<times> A \<times> A \<times> A \<times> A \<times> A) = (card A) ^ 6"
proof-
  have "card (A \<times> A \<times> A \<times> A \<times> A \<times> A) =
    card A * card A * card A * card A * card A * card A"
    using card_cartesian_product mult.commute by metis
  then show ?thesis by algebra
qed

lemma card_cartesian_product3: "card (X \<times> Y \<times> Z) = card X * card Y * card Z"
  using card_cartesian_product  by (metis mult.commute mult.left_commute)

lemma card_le_image_div:
  fixes A:: "'a set" and B:: "'b set" and f:: "'a \<Rightarrow> 'b set" and r:: real
  assumes "finite B" and "pairwise (\<lambda> s t. disjnt (f s) (f t)) A" and "\<forall> d \<in> A. (card (f d)) \<ge> r"
  and "\<forall> d \<in> A. f d \<subseteq> B" and "r > 0"
  shows "card A \<le> card B / r"

proof (cases "finite A")
  assume hA: "finite A"
  have hpair_disj: "pairwise disjnt (f ` A)" using assms by (metis pairwiseD pairwise_imageI)
  have "r * card A = (\<Sum> d \<in> A. r)" by simp
  also have "... \<le> (\<Sum> d \<in> A. card (f d))" using assms sum_mono by fastforce
  also have "... = sum card (f ` A)" using assms hA by (simp add: sum_card_image)
  also have "... = card (\<Union> d \<in> A. f d)" using assms hA hpair_disj
    by (metis Sup_upper card_Union_disjoint finite_UN_I rev_finite_subset)
  also have "... \<le> card B" using assms card_mono
    by (metis UN_subset_iff of_nat_le_iff)
  finally have "r * card A \<le> card B" by linarith
  thus ?thesis using divide_le_eq assms by (simp add: mult_imp_le_div_pos mult_of_nat_commute)
next
  assume "\<not> finite A"
  thus ?thesis using assms by auto
qed

lemma list_middle_eq:
  "length xs = length ys \<Longrightarrow> hd xs = hd ys \<Longrightarrow> last xs = last ys
    \<Longrightarrow> butlast (tl xs) = butlast (tl ys) \<Longrightarrow> xs = ys"
  apply (induct xs ys rule: list_induct2, simp)
  by (metis append_butlast_last_id butlast.simps(1) butlast.simps(2) butlast_tl hd_Cons_tl
      impossible_Cons le_refl list.sel(3) neq_Nil_conv)

lemma list2_middle_singleton:
  assumes "length xs = 3"
  shows "butlast (tl xs) = [xs ! 1]"
proof (simp add: list_eq_iff_nth_eq assms)
  have l: "length (butlast (tl xs)) = 1" using length_butlast length_tl assms by simp
  then have " butlast (tl xs) ! 0 = (tl xs) ! 0" using nth_butlast[of 0 "tl xs"] by simp
  then show "butlast (tl xs) ! 0 = xs ! Suc 0" using nth_tl[of 0 xs]  l by simp
qed

lemma le_powr_half_mult:
  fixes x y z:: real
  assumes "x ^ 2 \<le> y * z" and "0 \<le> y" and "0 \<le> z"
  shows "x \<le> y powr(1/2) * z powr (1/2)"
  using assms power2_eq_square
  by (metis dual_order.trans linorder_linear powr_ge_pzero powr_half_sqrt powr_mult real_le_rsqrt
    real_sqrt_le_0_iff)

lemma Cauchy_Schwarz_ineq_sum2:
  fixes f g:: "'a \<Rightarrow> real" and A:: "'a set"
  shows "(\<Sum> d \<in> A. f d * g d) \<le>
    (\<Sum> d \<in> A. (f d)^2) powr (1/2) * (\<Sum> d \<in> A. (g d)^2) powr (1/2)"
  using Convex.Cauchy_Schwarz_ineq_sum[of "f" "g" "A"] le_powr_half_mult sum_nonneg zero_le_power2
  by (metis (mono_tags, lifting))

end


theory TopoS_ENF
imports Main TopoS_Interface "Lib/TopoS_Util" TopoS_withOffendingFlows
begin

section\<open>Special Structures of Security Invariants\<close>

text \<open>Security Invariants may have a common structure:
  If the function @{term "sinvar"} is predicate which starts with \<open>\<forall> (v\<^sub>1, v\<^sub>2) \<in> edges G. \<dots>\<close>,
  we call this the all edges normal form (ENF).
  We found that this form has some nice properties.
  Also, locale instantiation is easier in ENF with the help of the following lemmata.\<close>

subsection \<open>Simple Edges Normal Form (ENF)\<close>

context SecurityInvariant_withOffendingFlows
begin

  definition sinvar_all_edges_normal_form :: "('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> bool" where
  "sinvar_all_edges_normal_form P \<equiv> \<forall> G nP. sinvar G nP = (\<forall> (e1, e2)\<in> edges G. P (nP e1) (nP e2))"

  text\<open>reflexivity is needed for convenience. If a security invariant is not reflexive, that means that all nodes with the default
    parameter \<open>\<bottom>\<close> are not allowed to communicate with each other. Non-reflexivity is possible, but requires more work.\<close>
  definition ENF_refl :: "('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> bool" where
  "ENF_refl P \<equiv> sinvar_all_edges_normal_form P \<and> (\<forall> p1. P p1 p1)"

  lemma monotonicity_sinvar_mono: "sinvar_all_edges_normal_form P \<Longrightarrow> sinvar_mono"
  unfolding sinvar_all_edges_normal_form_def sinvar_mono_def
  by auto

end

subsubsection \<open>Offending Flows\<close>

context SecurityInvariant_withOffendingFlows
begin

  text\<open>The insight: for all edges in the members of the offending flows, @{term "\<not> P"} holds.\<close>
  lemma ENF_offending_imp_not_P:
    assumes "sinvar_all_edges_normal_form P" "F \<in> set_offending_flows G nP" "(e1, e2) \<in> F"
    shows "\<not> P (nP e1) (nP e2)"
  using assms
  unfolding sinvar_all_edges_normal_form_def set_offending_flows_def is_offending_flows_min_set_def is_offending_flows_def
  by (fastforce simp: graph_ops)

  text\<open>Hence, the members of @{const set_offending_flows} must look as follows.\<close>
  lemma ENF_offending_set_P_representation:
    assumes "sinvar_all_edges_normal_form P" "F \<in> set_offending_flows G nP"
    shows "F = {(e1,e2). (e1, e2) \<in> edges G \<and> \<not> P (nP e1) (nP e2)}" (is "F = ?E")
  proof -
    { fix a b
      assume "(a, b) \<in> F"
      hence "(a, b) \<in> ?E"
        using assms
        by (auto simp: set_offending_flows_def ENF_offending_imp_not_P)
    }
    moreover
    { fix x
      assume "x \<in> ?E"
      hence "x \<in> F"
        using assms
        unfolding sinvar_all_edges_normal_form_def set_offending_flows_def is_offending_flows_min_set_def
        by (fastforce simp: is_offending_flows_def graph_ops)
    }
    ultimately show ?thesis
      by blast
  qed

  text\<open>We can show left to right of the desired representation of @{const set_offending_flows}\<close>
  lemma ENF_offending_subseteq_lhs:
    assumes "sinvar_all_edges_normal_form P"
    shows "set_offending_flows G nP \<subseteq> { {(e1,e2). (e1, e2) \<in> edges G \<and> \<not> P (nP e1) (nP e2)} }"
  using assms
  by (force simp: ENF_offending_set_P_representation)

  text\<open>if @{const set_offending_flows} is not empty, we have the other direction.\<close>
  lemma ENF_offending_not_empty_imp_ENF_offending_subseteq_rhs:
    assumes "sinvar_all_edges_normal_form P" "set_offending_flows G nP \<noteq> {}"
    shows "{ {(e1,e2) \<in> edges G. \<not> P (nP e1) (nP e2)} } \<subseteq> set_offending_flows G nP"
  using assms ENF_offending_set_P_representation
  by blast

  lemma ENF_notevalmodel_imp_offending_not_empty:
  "sinvar_all_edges_normal_form P \<Longrightarrow> \<not> sinvar G nP \<Longrightarrow> set_offending_flows G nP \<noteq> {}"
    (*TODO get easier from monotonicity? but would require valid graph assumption ...*)
    proof -
      assume enf: "sinvar_all_edges_normal_form P"
      and ns: "\<not> sinvar G nP"

      {
        let ?F'="{(e1,e2) \<in> (edges G). \<not>P (nP e1) (nP e2)}"
        \<comment> \<open>select @{term "?F'"} as the list of all edges which violate @{term "P"}\<close>

        from enf have ENF_notevalmodel_offending_imp_ex_offending_min:
            "\<And>F. is_offending_flows F G nP \<Longrightarrow> F \<subseteq> edges G \<Longrightarrow>
             \<exists>F'. F' \<subseteq> edges G \<and> is_offending_flows_min_set F' G nP"
          unfolding sinvar_all_edges_normal_form_def is_offending_flows_min_set_def is_offending_flows_def
          by (-) (rule exI[where x="?F'"], fastforce simp: graph_ops)

        from enf ns have "\<exists>F. F \<subseteq> (edges G) \<and> is_offending_flows F G nP"
          unfolding sinvar_all_edges_normal_form_def is_offending_flows_def
          by (-) (rule exI[where x="?F'"], fastforce simp: graph_ops)

        from enf ns this ENF_notevalmodel_offending_imp_ex_offending_min have ENF_notevalmodel_imp_ex_offending_min:
          "\<exists>F. F \<subseteq> edges G \<and> is_offending_flows_min_set F G nP" by blast
        } note ENF_notevalmodel_imp_ex_offending_min=this

      from ENF_notevalmodel_imp_ex_offending_min show "set_offending_flows G nP \<noteq> {}" using set_offending_flows_def by simp
    qed

  lemma ENF_offending_case1:
    "\<lbrakk> sinvar_all_edges_normal_form P;  \<not> sinvar G nP \<rbrakk> \<Longrightarrow>
    { {(e1,e2). (e1, e2) \<in> (edges G) \<and> \<not> P (nP e1) (nP e2)} } = set_offending_flows G nP"
    apply(rule)
     apply(frule ENF_notevalmodel_imp_offending_not_empty, simp)
     apply(rule ENF_offending_not_empty_imp_ENF_offending_subseteq_rhs, simp)
     apply simp
    apply(rule ENF_offending_subseteq_lhs)
    apply simp
  done

  lemma ENF_offending_case2:
    "\<lbrakk> sinvar_all_edges_normal_form P; sinvar G nP \<rbrakk> \<Longrightarrow>
    {} = set_offending_flows G nP"
    apply(drule sinvar_no_offending[of G nP])
    apply simp
  done

  theorem ENF_offending_set:
    "\<lbrakk> sinvar_all_edges_normal_form P \<rbrakk> \<Longrightarrow>
    set_offending_flows G nP = (if sinvar G nP then
      {}
     else
      { {(e1,e2). (e1, e2) \<in> edges G \<and> \<not> P (nP e1) (nP e2)} })"
  by(simp add: ENF_offending_case1 ENF_offending_case2)
end

subsubsection \<open>Lemmata\<close>

  lemma (in SecurityInvariant_withOffendingFlows)  ENF_offending_members:
    "\<lbrakk> \<not> sinvar G nP; sinvar_all_edges_normal_form P; f \<in> set_offending_flows G nP\<rbrakk> \<Longrightarrow>
    f \<subseteq> (edges G) \<and> (\<forall> (e1, e2)\<in> f. \<not> P (nP e1) (nP e2))"
  by(auto simp add: ENF_offending_set)

subsubsection \<open>Instance Helper\<close>

  lemma (in SecurityInvariant_withOffendingFlows) ENF_refl_not_offedning:
        "\<lbrakk> \<not> sinvar G nP; f \<in> set_offending_flows G nP;
          ENF_refl P\<rbrakk> \<Longrightarrow>
          \<forall>(e1,e2) \<in> f. e1 \<noteq> e2"
  proof -
  assume a_not_eval: "\<not> sinvar G nP"
    and   a_enf_refl: "ENF_refl P"
    and   a_offedning: "f \<in> set_offending_flows G nP"

    from a_enf_refl have a_enf: "sinvar_all_edges_normal_form P" using ENF_refl_def by simp
    hence a_ENF: "\<And> G nP. sinvar G nP  = (\<forall> (e1, e2) \<in> edges G. P (nP e1) (nP e2))" using sinvar_all_edges_normal_form_def by simp

    from a_enf_refl ENF_refl_def have a_refl: "\<forall> (e1,e1) \<in> f. P (nP e1) (nP e1)" by simp
    from ENF_offending_members[OF a_not_eval a_enf a_offedning] have "\<forall> (e1, e2) \<in> f. \<not> P (nP e1) (nP e2)" by fast
    from this a_refl show "\<forall>(e1,e2) \<in> f. e1 \<noteq> e2" by fast
  qed

  lemma (in SecurityInvariant_withOffendingFlows) ENF_default_update_fst:
  fixes "default_node_properties" :: "'a" ("\<bottom>")
  assumes modelInv: "\<not> sinvar G nP"
    and   ENFdef: "sinvar_all_edges_normal_form P"
    and   secdef: "\<forall> (nP::'v \<Rightarrow> 'a) e1 e2. \<not> (P (nP e1) (nP e2)) \<longrightarrow> \<not> (P \<bottom> (nP e2))"
  shows
    "\<not> (\<forall> (e1, e2) \<in> edges G. P ((nP(i := \<bottom>)) e1) (nP e2))"
  proof -
    from ENFdef have ENF: "\<And> G nP. sinvar G nP  = (\<forall> (e1, e2)\<in> edges G. P (nP e1) (nP e2))"
      using sinvar_all_edges_normal_form_def by simp
    from modelInv ENF have modelInv': "\<not> (\<forall> (e1, e2)\<in> edges G. P (nP e1) (nP e2))" by simp
    from this secdef have modelInv'': "\<not> (\<forall> (e1, e2)\<in> edges G. P \<bottom> (nP e2))" by blast
      have simpUpdateI: "\<And> e1 e2. \<not> P (nP e1) (nP e2) \<Longrightarrow> \<not> P \<bottom> (nP e2) \<Longrightarrow> \<not> P ((nP(i := \<bottom>)) e1) (nP e2)" by simp
      hence "\<And> X. \<exists>(e1,e2) \<in> X. \<not> P (nP e1) (nP e2) \<Longrightarrow> \<exists>(e1,e2) \<in> X.\<not> P \<bottom> (nP e2) \<Longrightarrow> \<exists>(e1,e2) \<in> X.\<not> P ((nP(i := \<bottom>)) e1) (nP e2)"
        using secdef by blast
    from this modelInv' modelInv'' show "\<not> (\<forall> (e1, e2) \<in> edges G. P ((nP(i := \<bottom>)) e1) (nP e2))" by blast
  qed

  lemma (in SecurityInvariant_withOffendingFlows)
    fixes "default_node_properties" :: "'a" ("\<bottom>")
    shows "\<not> sinvar G nP \<Longrightarrow> sinvar_all_edges_normal_form P \<Longrightarrow>
    (\<forall> (nP::'v \<Rightarrow> 'a) e1 e2. \<not> (P (nP e1) (nP e2)) \<longrightarrow>  \<not> (P \<bottom> (nP e2))) \<Longrightarrow>
    (\<forall> (nP::'v \<Rightarrow> 'a) e1 e2. \<not> (P (nP e1) (nP e2)) \<longrightarrow> \<not> (P (nP e1) \<bottom>)) \<Longrightarrow>
    (\<forall> (nP::'v \<Rightarrow> 'a) e1 e2. \<not> P \<bottom> \<bottom>)
    \<Longrightarrow> \<not> sinvar G (nP(i := \<bottom>))"
  proof -
    assume a1: "\<not> sinvar G nP"
    and   a2d: "sinvar_all_edges_normal_form P"
    and    a3: "\<forall> (nP::'v \<Rightarrow> 'a) e1 e2. \<not> (P (nP e1) (nP e2)) \<longrightarrow> \<not> (P \<bottom> (nP e2))"
    and    a4: "\<forall> (nP::'v \<Rightarrow> 'a) e1 e2. \<not> (P (nP e1) (nP e2)) \<longrightarrow> \<not> (P (nP e1) \<bottom>)"
    and    a5: "\<forall> (nP::'v \<Rightarrow> 'a) e1 e2. \<not> P \<bottom> \<bottom>"

    from a2d have a2: "\<And> G nP. sinvar G nP  = (\<forall> (e1, e2) \<in> edges G. P (nP e1) (nP e2))"
      using sinvar_all_edges_normal_form_def by simp

    from ENF_default_update_fst[OF a1 a2d] a3 have subgoal1: "\<not> (\<forall> (e1, e2) \<in> edges G. P ((nP(i := \<bottom>)) e1) (nP e2))" by blast

    let ?nP' = "(nP(i := \<bottom>))"

    from subgoal1 have "\<exists> (e1, e2) \<in> edges G. \<not> P (?nP' e1) (nP e2)" by blast
    from this obtain e11 e21 where s1cond: "(e11, e21) \<in> edges G \<and> \<not> P (?nP' e11) (nP e21)" by blast

    from s1cond have "i \<noteq> e11 \<Longrightarrow> \<not> P (nP e11) (nP e21)" by simp
    from s1cond have "e11 \<noteq> e21 \<Longrightarrow> \<not> P (?nP' e11) (?nP' e21)"
      apply simp
      apply(rule conjI)
       apply blast
      apply(insert a4)
      by force
    from s1cond a4 fun_upd_apply have ex1: "e11 \<noteq> e21 \<Longrightarrow> \<not> P (?nP' e11) (?nP' e21)" by metis
    from s1cond a5 have ex2: "e11 = e21 \<Longrightarrow> \<not> P (?nP' e11) (?nP' e21)" by auto

    from ex1 ex2 s1cond have "\<exists> (e1, e2) \<in> edges G. \<not> P (?nP' e1) (?nP' e2)" by blast
    hence "\<not> (\<forall> (e1, e2) \<in> edges G. P ((nP(i := \<bottom>)) e1) ((nP(i := \<bottom>)) e2))" by fast
    from this a2 show "\<not> sinvar G (nP(i := \<bottom>))" by presburger
  qed

  (* fsts version *)
  lemma (in SecurityInvariant_withOffendingFlows)  ENF_fsts_refl_instance:
    fixes "default_node_properties" :: "'a" ("\<bottom>")
    assumes a_enf_refl: "ENF_refl P"
    and   a3: "\<forall> (nP::'v \<Rightarrow> 'a) e1 e2. \<not> (P (nP e1) (nP e2)) \<longrightarrow> \<not> (P \<bottom> (nP e2))" (*changed \<And> to \<forall>*)
    and   a_offending: "f \<in> set_offending_flows G nP"
    and   a_i_fsts: "i \<in> fst ` f"
    shows
          "\<not> sinvar G (nP(i := \<bottom>))"
  proof -
    from a_offending have a_not_eval: "\<not> sinvar G nP" by (metis equals0D sinvar_no_offending)
    from valid_without_offending_flows[OF a_offending] have a_offending_rm: "sinvar (delete_edges G f) nP" .

    from a_enf_refl have a_enf: "sinvar_all_edges_normal_form P" using ENF_refl_def by simp
    hence a2: "\<And> G nP. sinvar G nP  = (\<forall> (e1, e2) \<in> edges G. P (nP e1) (nP e2))" using sinvar_all_edges_normal_form_def by simp

    from ENF_offending_members[OF a_not_eval a_enf a_offending] have a_f_3_in_f: "\<And> e1 e2. (e1, e2) \<in> f \<Longrightarrow> \<not> P (nP e1) (nP e2)" by fast

    let ?nP' = "(nP(i := \<bottom>))"

    (* obain from f *)
    from offending_not_empty[OF a_offending] ENF_offending_members[OF a_not_eval a_enf a_offending] a_i_fsts hd_in_set
      obtain e1 e2 where e1e2cond: "(e1, e2) \<in> f \<and> e1 = i" by force

    from conjunct1[OF e1e2cond] a_f_3_in_f have e1e2notP: "\<not> P (nP e1) (nP e2)" by simp
    from this a3 have "\<not> P \<bottom> (nP e2)" by simp
    from this e1e2notP have e1e2subgoal1: "\<not> P (?nP' e1) (nP e2)" by simp

    from ENF_refl_not_offedning[OF a_not_eval a_offending a_enf_refl] conjunct1[OF e1e2cond] have ENF_refl: "e1 \<noteq> e2" by fast

    from e1e2subgoal1 have "e1 \<noteq> e2 \<Longrightarrow> \<not> P (?nP' e1) (?nP' e2)"
      apply simp
      apply(rule conjI)
       apply blast
      apply(insert conjunct2[OF e1e2cond])
      by simp

    from this ENF_refl ENF_offending_members[OF a_not_eval a_enf a_offending]  conjunct1[OF e1e2cond] have
      "\<exists> (e1, e2) \<in> edges G. \<not> P (?nP' e1) (?nP' e2)" by blast
    hence "\<not> (\<forall> (e1, e2) \<in> edges G. P ((nP(i := \<bottom>)) e1) ((nP(i := \<bottom>)) e2))" by fast
    from this a2 show "\<not> sinvar G (nP(i := \<bottom>))" by presburger
  qed

  (* snds version *)
  lemma (in SecurityInvariant_withOffendingFlows)  ENF_snds_refl_instance:
    fixes "default_node_properties" :: "'a" ("\<bottom>")
    assumes a_enf_refl: "ENF_refl P"
    and   a3: "\<forall> (nP::'v \<Rightarrow> 'a) e1 e2. \<not> (P (nP e1) (nP e2)) \<longrightarrow> \<not> (P (nP e1) \<bottom>)"
    and   a_offending: "f \<in> set_offending_flows G nP"
    and   a_i_snds: "i \<in> snd ` f"
    shows
          "\<not> sinvar G (nP(i := \<bottom>))"
  proof -
    from a_offending have a_not_eval: "\<not> sinvar G nP" by (metis equals0D sinvar_no_offending)
    from valid_without_offending_flows[OF a_offending] have a_offending_rm: "sinvar (delete_edges G f) nP" .
    from a_enf_refl have a_enf: "sinvar_all_edges_normal_form P" using ENF_refl_def by simp
    hence a2: "\<And> G nP. sinvar G nP  = (\<forall> (e1, e2) \<in> edges G. P (nP e1) (nP e2))" using sinvar_all_edges_normal_form_def by simp

    from ENF_offending_members[OF a_not_eval a_enf a_offending] have a_f_3_in_f: "\<And> e1 e2. (e1, e2) \<in> f \<Longrightarrow> \<not> P (nP e1) (nP e2)" by fast

    let ?nP' = "(nP(i := \<bottom>))"

    (* obain from f *)
    from offending_not_empty[OF a_offending] ENF_offending_members[OF a_not_eval a_enf a_offending] a_i_snds hd_in_set
      obtain e1 e2 where e1e2cond: "(e1, e2) \<in> f \<and> e2 = i" by force

    from conjunct1[OF e1e2cond] a_f_3_in_f have e1e2notP: "\<not> P (nP e1) (nP e2)" by simp
    from this a3 have "\<not> P (nP e1) \<bottom>" by auto
    from this e1e2notP have e1e2subgoal1: "\<not> P (nP e1) (?nP' e2)" by simp

    from ENF_refl_not_offedning[OF a_not_eval a_offending a_enf_refl] e1e2cond have ENF_refl: "e1 \<noteq> e2" by fast

    from e1e2subgoal1 have "e1 \<noteq> e2 \<Longrightarrow> \<not> P (?nP' e1) (?nP' e2)"
      apply simp
      apply(rule conjI)
       apply(insert conjunct2[OF e1e2cond])
       by simp_all

    from this ENF_refl e1e2cond ENF_offending_members[OF a_not_eval a_enf a_offending]  conjunct1[OF e1e2cond] have
      "\<exists> (e1, e2) \<in> edges G. \<not> P (?nP' e1) (?nP' e2)" by blast
    hence "\<not> (\<forall> (e1, e2) \<in> edges G. P ((nP(i := \<bottom>)) e1) ((nP(i := \<bottom>)) e2))" by fast
    from this a2 show "\<not> sinvar G (nP(i := \<bottom>))" by presburger
  qed

(*ENF_sr*)

subsection \<open>edges normal form ENF with sender and receiver names\<close>
  definition (in SecurityInvariant_withOffendingFlows) sinvar_all_edges_normal_form_sr :: "('a \<Rightarrow> 'v \<Rightarrow> 'a \<Rightarrow> 'v \<Rightarrow> bool) \<Rightarrow> bool" where
    "sinvar_all_edges_normal_form_sr P \<equiv> \<forall> G nP. sinvar G nP = (\<forall> (s, r)\<in> edges G. P (nP s) s (nP r) r)"

  lemma (in SecurityInvariant_withOffendingFlows) ENFsr_monotonicity_sinvar_mono: "\<lbrakk> sinvar_all_edges_normal_form_sr P \<rbrakk> \<Longrightarrow>
    sinvar_mono"
    apply(simp add: sinvar_all_edges_normal_form_sr_def sinvar_mono_def)
    by blast

subsubsection \<open>Offending Flows:\<close>

  theorem (in SecurityInvariant_withOffendingFlows) ENFsr_offending_set:
    assumes ENFsr: "sinvar_all_edges_normal_form_sr P"
    shows "set_offending_flows G nP = (if sinvar G nP then
      {}
     else
      { {(s,r). (s, r) \<in> edges G \<and> \<not> P (nP s) s (nP r) r} })" (is "?A = ?B")
  proof(cases "sinvar G nP")
  case True thus "?A = ?B"
    by(simp add: set_offending_flows_def is_offending_flows_min_set_def is_offending_flows_def)
  next
  case False
   from ENFsr have ENFsr_offending_imp_not_P: "\<And> F s r. F \<in> set_offending_flows G nP \<Longrightarrow> (s, r) \<in> F  \<Longrightarrow> \<not> P (nP s) s (nP r) r"
     unfolding sinvar_all_edges_normal_form_sr_def
     apply(simp add: set_offending_flows_def is_offending_flows_def is_offending_flows_min_set_def graph_ops)
     apply clarify
     by fastforce
   from ENFsr have  ENFsr_offending_set_P_representation:
    "\<And> F. F \<in> set_offending_flows G nP  \<Longrightarrow> F = {(s,r). (s, r) \<in> edges G \<and> \<not> P (nP s) s (nP r) r}"
      apply -
      apply rule
       apply rule
       apply clarify
       apply(rename_tac a b)
       apply rule
        apply(auto simp add:set_offending_flows_def)[1]
       apply(simp add: ENFsr_offending_imp_not_P)
      unfolding sinvar_all_edges_normal_form_sr_def
      apply(simp add:set_offending_flows_def is_offending_flows_def is_offending_flows_min_set_def graph_ops)
      apply clarify
      apply(rename_tac a b a1 b1)
      apply(blast)
    done

    from ENFsr False have ENFsr_offending_flows_exist: "set_offending_flows G nP \<noteq> {}"
      apply(simp add: set_offending_flows_def is_offending_flows_min_set_def is_offending_flows_def sinvar_all_edges_normal_form_sr_def
            delete_edges_def add_edge_def)
      apply(clarify)
      apply(rename_tac s r)
      apply(rule_tac x="{(s,r). (s,r) \<in> (edges G) \<and> \<not>P (nP s) s (nP r) r}" in exI)
      apply(simp)
      by blast

    from ENFsr have ENFsr_offenindg_not_empty_imp_ENF_offending_subseteq_rhs:
      "set_offending_flows G nP \<noteq> {}  \<Longrightarrow>
      { {(s,r). (s, r) \<in> edges G \<and> \<not> P (nP s) s (nP r) r} } \<subseteq> set_offending_flows G nP"
      apply -
      apply rule
      using ENFsr_offending_set_P_representation
      by blast

    from ENFsr have ENFsr_offending_subseteq_lhs:
      "(set_offending_flows G nP) \<subseteq> { {(s,r). (s, r) \<in> edges G \<and> \<not> P (nP s) s (nP r) r} }"
      apply -
      apply rule
      by(simp add: ENFsr_offending_set_P_representation)

    from False ENFsr_offenindg_not_empty_imp_ENF_offending_subseteq_rhs[OF ENFsr_offending_flows_exist] ENFsr_offending_subseteq_lhs show "?A = ?B"
      by force
  qed

(*ENFnrSR*)

subsection \<open>edges normal form not refl ENFnrSR\<close>
  definition (in SecurityInvariant_withOffendingFlows) sinvar_all_edges_normal_form_not_refl_SR :: "('a \<Rightarrow> 'v \<Rightarrow> 'a \<Rightarrow> 'v \<Rightarrow> bool) \<Rightarrow> bool" where
    "sinvar_all_edges_normal_form_not_refl_SR P \<equiv>
    \<forall> G nP. sinvar G nP = (\<forall> (s, r) \<in> edges G. s \<noteq> r \<longrightarrow> P (nP s) s (nP r) r)"

  text\<open>we derive everything from the ENFnrSR form\<close>
  lemma (in SecurityInvariant_withOffendingFlows) ENFnrSR_to_ENFsr:
    "sinvar_all_edges_normal_form_not_refl_SR P \<Longrightarrow> sinvar_all_edges_normal_form_sr (\<lambda> p1 v1 p2 v2. v1 \<noteq> v2 \<longrightarrow> P p1 v1 p2 v2)"
    by(simp add: sinvar_all_edges_normal_form_sr_def sinvar_all_edges_normal_form_not_refl_SR_def)

subsubsection \<open>Offending Flows\<close>

subsubsection \<open>Instance helper\<close>

  (* fsts version *)
  lemma (in SecurityInvariant_withOffendingFlows)  ENFnrSR_fsts_weakrefl_instance:
    fixes "default_node_properties" :: "'a" ("\<bottom>")
    assumes a_enf: "sinvar_all_edges_normal_form_not_refl_SR P"
    and   a_weakrefl: "\<forall> s r. P \<bottom> s \<bottom> r"
    and   a_botdefault: "\<forall> s r. (nP r) \<noteq> \<bottom> \<longrightarrow> \<not> P (nP s) s (nP r) r \<longrightarrow> \<not> P \<bottom> s (nP r) r"
    and   a_alltobot: "\<forall> s r. P (nP s) s \<bottom> r"
    and   a_offending: "f \<in> set_offending_flows G nP"
    and   a_i_fsts: "i \<in> fst` f"
    shows
          "\<not> sinvar G (nP(i := \<bottom>))"
  proof -
    from a_offending have a_not_eval: "\<not> sinvar G nP" by (metis ex_in_conv sinvar_no_offending)
    from valid_without_offending_flows[OF a_offending] have a_offending_rm: "sinvar (delete_edges G f) nP" .
    from a_enf have a_enf': "\<And> G nP. sinvar G nP  = (\<forall> (e1, e2)\<in> (edges G). e1 \<noteq> e2 \<longrightarrow> P (nP e1) e1 (nP e2) e2)"
      using sinvar_all_edges_normal_form_not_refl_SR_def by simp

    from ENFnrSR_offending_set[OF a_enf] a_not_eval a_offending have a_f_3_in_f: "\<And> e1 e2. (e1, e2)\<in>f \<Longrightarrow> \<not> P (nP e1) e1 (nP e2) e2" by(simp)
    from ENFnrSR_offending_set[OF a_enf] a_not_eval a_offending have a_f_3_neq: "\<And> e1 e2. (e1, e2)\<in>f \<Longrightarrow> e1 \<noteq> e2" by simp

    let ?nP' = "(nP(i := \<bottom>))"

    from ENFnrSR_offending_set[OF a_enf] a_not_eval a_offending a_i_fsts
      obtain e1 e2 where e1e2cond: "(e1, e2) \<in> f \<and> e1 = i" by fastforce

    from conjunct1[OF e1e2cond] a_offending have "(e1, e2) \<in> edges G"
      by (metis (lifting, no_types) SecurityInvariant_withOffendingFlows.set_offending_flows_def mem_Collect_eq rev_subsetD)

    from conjunct1[OF e1e2cond] a_f_3_in_f have e1e2notP: "\<not> P (nP e1) e1 (nP e2) e2" by simp
    from e1e2notP a_weakrefl have e1ore2neqbot: "(nP e1) \<noteq> \<bottom> \<or> (nP e2) \<noteq> \<bottom>" by fastforce
    from e1e2notP a_alltobot have "(nP e2) \<noteq> \<bottom>" by fastforce
    from this e1e2notP a_botdefault have "\<not> P \<bottom> e1 (nP e2) e2" by simp
    from this e1e2notP have e1e2subgoal1: "\<not> P (?nP' e1) e1 (nP e2) e2" by auto

    from a_f_3_neq e1e2cond have "e2 \<noteq> e1" by blast

    from e1e2subgoal1 have "e1 \<noteq> e2 \<Longrightarrow> \<not> P (?nP' e1) e1 (?nP' e2) e2"
      apply simp
      apply(rule conjI)
       apply blast
      apply(insert e1e2cond)
      by simp
    from this \<open>e2 \<noteq> e1\<close> have "\<not> P (?nP' e1) e1 (?nP' e2) e2" by simp

    from this \<open>e2 \<noteq> e1\<close> ENFnrSR_offending_set[OF a_enf] a_offending \<open>(e1, e2) \<in> edges G\<close> have
      "\<exists> (e1, e2)\<in>(edges G). e2 \<noteq> e1 \<and> \<not> P (?nP' e1) e1 (?nP' e2) e2" by blast
    hence "\<not> (\<forall> (e1, e2)\<in>(edges G). e2 \<noteq> e1 \<longrightarrow> P ((nP(i := \<bottom>)) e1) e1 ((nP(i := \<bottom>)) e2) e2)" by fast
    from this a_enf' show "\<not> sinvar G (nP(i := \<bottom>))" by fast
  qed

  (* snds version *)
  lemma (in SecurityInvariant_withOffendingFlows)  ENFnrSR_snds_weakrefl_instance:
    fixes "default_node_properties" :: "'a" ("\<bottom>")
    assumes a_enf: "sinvar_all_edges_normal_form_not_refl_SR P"
    and   a_weakrefl: "\<forall> s r. P \<bottom> s \<bottom> r"
    and   a_botdefault: "\<forall> s r. (nP s) \<noteq> \<bottom> \<longrightarrow> \<not> P (nP s) s (nP r) r \<longrightarrow> \<not> P (nP s) s \<bottom> r"
    and   a_bottoall: "\<forall> s r. P \<bottom> s (nP r) r"
    and   a_offending: "f \<in> set_offending_flows G nP"
    and   a_i_snds: "i \<in> snd` f"
    shows
          "\<not> sinvar G (nP(i := \<bottom>))"
  proof -
    from a_offending have a_not_eval: "\<not> sinvar G nP" by (metis equals0D sinvar_no_offending)
    from valid_without_offending_flows[OF a_offending] have a_offending_rm: "sinvar (delete_edges G f) nP" .
    from a_enf have a_enf': "\<And> G nP. sinvar G nP  = (\<forall> (e1, e2)\<in>(edges G). e1 \<noteq> e2 \<longrightarrow> P (nP e1) e1 (nP e2) e2)"
      using sinvar_all_edges_normal_form_not_refl_SR_def by simp

    from ENFnrSR_offending_set[OF a_enf] a_not_eval a_offending have a_f_3_in_f: "\<And> s r. (s, r)\<in>f \<Longrightarrow> \<not> P (nP s) s (nP r) r" by simp
    from ENFnrSR_offending_set[OF a_enf] a_not_eval a_offending have a_f_3_neq: "\<And> s r. (s, r)\<in>f \<Longrightarrow> s \<noteq> r" by simp

    let ?nP' = "(nP(i := \<bottom>))"

    from ENFnrSR_offending_set[OF a_enf] a_not_eval a_offending a_i_snds
      obtain e1 e2 where e1e2cond: "(e1, e2)\<in>f \<and> e2 = i" by fastforce

    from conjunct1[OF e1e2cond] a_offending have "(e1, e2) \<in> edges G"
      by (metis (lifting, no_types) SecurityInvariant_withOffendingFlows.set_offending_flows_def mem_Collect_eq rev_subsetD)

    from conjunct1[OF e1e2cond] a_f_3_in_f have e1e2notP: "\<not> P (nP e1) e1 (nP e2) e2" by simp
    from e1e2notP a_weakrefl have e1ore2neqbot: "(nP e1) \<noteq> \<bottom> \<or> (nP e2) \<noteq> \<bottom>" by fastforce
    from e1e2notP a_bottoall have x1: "(nP e1) \<noteq> \<bottom>" by fastforce
    from this e1e2notP a_botdefault have x2: "\<not> P (nP e1) e1 \<bottom> e2" by fast
    from this e1e2notP have e1e2subgoal1: "\<not> P (nP e1) e1 (?nP' e2) e2" by auto

    from a_f_3_neq e1e2cond have "e2 \<noteq> e1" by blast

    from e1e2subgoal1 have "e1 \<noteq> e2 \<Longrightarrow> \<not> P (?nP' e1) e1 (?nP' e2) e2" by(simp add: e1e2cond)

    from this \<open>e2 \<noteq> e1\<close> ENFnrSR_offending_set[OF a_enf] a_offending \<open>(e1, e2) \<in> edges G\<close> have
      "\<exists> (e1, e2)\<in>(edges G). e2 \<noteq> e1 \<and> \<not> P (?nP' e1) e1 (?nP' e2) e2" by fastforce
    hence "\<not> (\<forall> (e1, e2)\<in>(edges G). e2 \<noteq> e1 \<longrightarrow> P ((nP(i := \<bottom>)) e1) e1 ((nP(i := \<bottom>)) e2) e2)" by fast
    from this a_enf' show "\<not> sinvar G (nP(i := \<bottom>))" by fast
  qed

(*ENFnr*)

subsection \<open>edges normal form not refl ENFnr\<close>
  definition (in SecurityInvariant_withOffendingFlows) sinvar_all_edges_normal_form_not_refl :: "('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> bool" where
    "sinvar_all_edges_normal_form_not_refl P \<equiv> \<forall> G nP. sinvar G nP = (\<forall> (e1, e2) \<in> edges G. e1 \<noteq> e2 \<longrightarrow> P (nP e1) (nP e2))"

  text\<open>we derive everything from the ENFnrSR form\<close>
  lemma (in SecurityInvariant_withOffendingFlows) ENFnr_to_ENFnrSR:
    "sinvar_all_edges_normal_form_not_refl P \<Longrightarrow> sinvar_all_edges_normal_form_not_refl_SR (\<lambda> v1 _ v2 _. P v1 v2)"
    by(simp add: sinvar_all_edges_normal_form_not_refl_def sinvar_all_edges_normal_form_not_refl_SR_def)

  (*most of results are now implied from previous lemma*)

subsubsection \<open>Offending Flows\<close>
   theorem (in SecurityInvariant_withOffendingFlows) ENFnr_offending_set:
    "\<lbrakk> sinvar_all_edges_normal_form_not_refl P \<rbrakk> \<Longrightarrow>
    set_offending_flows G nP = (if sinvar G nP then
      {}
     else
      { {(e1,e2). (e1, e2) \<in> edges G \<and> e1 \<noteq> e2 \<and> \<not> P (nP e1) (nP e2)} })"
    apply(drule ENFnr_to_ENFnrSR)
    by(drule(1) ENFnrSR_offending_set)

subsubsection \<open>Instance helper\<close>
  (* fsts version *)
  lemma (in SecurityInvariant_withOffendingFlows)  ENFnr_fsts_weakrefl_instance:
    fixes "default_node_properties" :: "'a" ("\<bottom>")
    assumes a_enf: "sinvar_all_edges_normal_form_not_refl P"
    and   a_botdefault: "\<forall> e1 e2. e2 \<noteq> \<bottom> \<longrightarrow> \<not> P e1 e2 \<longrightarrow> \<not> P \<bottom> e2"
    and   a_alltobot: "\<forall> e1. P e1 \<bottom>"
    and   a_offending: "f \<in> set_offending_flows G nP"
    and   a_i_fsts: "i \<in> fst` f"
    shows
          "\<not> sinvar G (nP(i := \<bottom>))"
  proof -
    from assms show ?thesis
    apply -
    apply(drule ENFnr_to_ENFnrSR)
    apply(drule ENFnrSR_fsts_weakrefl_instance)
         by auto
  qed

  (* snds version *)
  lemma (in SecurityInvariant_withOffendingFlows)  ENFnr_snds_weakrefl_instance:
    fixes "default_node_properties" :: "'a" ("\<bottom>")
    assumes a_enf: "sinvar_all_edges_normal_form_not_refl P"
    and   a_botdefault: "\<forall> e1 e2. \<not> P e1 e2 \<longrightarrow> \<not> P e1 \<bottom>"
    and   a_bottoall: "\<forall> e2. P \<bottom> e2"
    and   a_offending: "f \<in> set_offending_flows G nP"
    and   a_i_snds: "i \<in> snd` f"
    shows
          "\<not> sinvar G (nP(i := \<bottom>))"
  proof -
    from assms show ?thesis
    apply -
    apply(drule ENFnr_to_ENFnrSR)
    apply(drule ENFnrSR_snds_weakrefl_instance)
         by auto
  qed

  (* snds version DRAFT*)
  lemma (in SecurityInvariant_withOffendingFlows)  ENF_weakrefl_instance_FALSE:
    fixes "default_node_properties" :: "'a" ("\<bottom>")
    assumes a_wfG: "wf_graph G"
    and   a_not_eval: "\<not> sinvar G nP"
    and   a_enf: "sinvar_all_edges_normal_form P"
    and   a_weakrefl: "P \<bottom> \<bottom>"
    and   a_botisolated: "\<And> e2. e2 \<noteq> \<bottom> \<Longrightarrow> \<not> P \<bottom> e2"
    and   a_botdefault: "\<And> e1 e2. e1 \<noteq> \<bottom> \<Longrightarrow> \<not> P e1 e2 \<Longrightarrow> \<not> P e1 \<bottom>"
    and   a_offending: "f \<in> set_offending_flows G nP"
    and   a_offending_rm: "sinvar (delete_edges G f) nP"
    and   a_i_fsts: "i \<in> snd` f"
    and   a_not_eval_upd: "\<not> sinvar G (nP(i := \<bottom>))"
    shows "False"
oops

end