(*  Title:      HOL/Algebra/Ideal.thy
    Author:     Stephan Hohe, TU Muenchen
*)

theory Ideal
imports Ring AbelCoset
begin

section \<open>Ideals\<close>

subsection \<open>Definitions\<close>

subsubsection \<open>General definition\<close>

locale ideal = additive_subgroup I R + ring R for I and R (structure) +
  assumes I_l_closed: "\<lbrakk>a \<in> I; x \<in> carrier R\<rbrakk> \<Longrightarrow> x \<otimes> a \<in> I"
      and I_r_closed: "\<lbrakk>a \<in> I; x \<in> carrier R\<rbrakk> \<Longrightarrow> a \<otimes> x \<in> I"

sublocale ideal \<subseteq> abelian_subgroup I R
proof (intro abelian_subgroupI3 abelian_group.intro)
  show "additive_subgroup I R"
    by (simp add: is_additive_subgroup)
  show "abelian_monoid R"
    by (simp add: abelian_monoid_axioms)
  show "abelian_group_axioms R"
    using abelian_group_def is_abelian_group by blast
qed

lemma (in ideal) is_ideal: "ideal I R"
  by (rule ideal_axioms)

lemma idealI:
  fixes R (structure)
  assumes "ring R"
  assumes a_subgroup: "subgroup I (add_monoid R)"
    and I_l_closed: "\<And>a x. \<lbrakk>a \<in> I; x \<in> carrier R\<rbrakk> \<Longrightarrow> x \<otimes> a \<in> I"
    and I_r_closed: "\<And>a x. \<lbrakk>a \<in> I; x \<in> carrier R\<rbrakk> \<Longrightarrow> a \<otimes> x \<in> I"
  shows "ideal I R"
proof -
  interpret ring R by fact
  show ?thesis
    by (auto simp: ideal.intro ideal_axioms.intro additive_subgroupI a_subgroup ring_axioms I_l_closed I_r_closed)
qed

subsubsection (in ring) \<open>Ideals Generated by a Subset of @{term "carrier R"}\<close>

definition genideal :: "_ \<Rightarrow> 'a set \<Rightarrow> 'a set"  ("Idl\<index> _" [80] 79)
  where "genideal R S = \<Inter>{I. ideal I R \<and> S \<subseteq> I}"

subsubsection \<open>Principal Ideals\<close>

locale principalideal = ideal +
  assumes generate: "\<exists>i \<in> carrier R. I = Idl {i}"

lemma (in principalideal) is_principalideal: "principalideal I R"
  by (rule principalideal_axioms)

lemma principalidealI:
  fixes R (structure)
  assumes "ideal I R"
    and generate: "\<exists>i \<in> carrier R. I = Idl {i}"
  shows "principalideal I R"
proof -
  interpret ideal I R by fact
  show ?thesis
    by (intro principalideal.intro principalideal_axioms.intro)
      (rule is_ideal, rule generate)
qed

(* NEW ====== *)
lemma (in ideal) rcos_const_imp_mem:
  assumes "i \<in> carrier R" and "I +> i = I" shows "i \<in> I"
  using additive_subgroup.zero_closed[OF ideal.axioms(1)[OF ideal_axioms]] assms
  by (force simp add: a_r_coset_def')
(* ========== *)

(* NEW ====== *)
lemma (in ring) a_rcos_zero:
  assumes "ideal I R" "i \<in> I" shows "I +> i = I"
  using abelian_subgroupI3[OF ideal.axioms(1) is_abelian_group]
  by (simp add: abelian_subgroup.a_rcos_const assms)
(* ========== *)

(* NEW ====== *)
lemma (in ring) ideal_is_normal:
  assumes "ideal I R" shows "I \<lhd> (add_monoid R)"
  using abelian_subgroup.a_normal[OF abelian_subgroupI3[OF ideal.axioms(1)]]
        abelian_group_axioms assms
  by auto
(* ========== *)

(* NEW ====== *)
lemma (in ideal) a_rcos_sum:
  assumes "a \<in> carrier R" and "b \<in> carrier R" shows "(I +> a) <+> (I +> b) = I +> (a \<oplus> b)"
  using normal.rcos_sum[OF ideal_is_normal[OF ideal_axioms]] assms
  unfolding set_add_def a_r_coset_def by simp
(* ========== *)

(* NEW ====== *)
lemma (in ring) set_add_comm:
  assumes "I \<subseteq> carrier R" "J \<subseteq> carrier R" shows "I <+> J = J <+> I"
proof -
  { fix I J assume "I \<subseteq> carrier R" "J \<subseteq> carrier R" hence "I <+> J \<subseteq> J <+> I"
      using a_comm unfolding set_add_def' by (auto, blast) }
  thus ?thesis
    using assms by auto
qed
(* ========== *)

subsubsection \<open>Maximal Ideals\<close>

locale maximalideal = ideal +
  assumes I_notcarr: "carrier R \<noteq> I"
    and I_maximal: "\<lbrakk>ideal J R; I \<subseteq> J; J \<subseteq> carrier R\<rbrakk> \<Longrightarrow> (J = I) \<or> (J = carrier R)"

lemma (in maximalideal) is_maximalideal: "maximalideal I R"
  by (rule maximalideal_axioms)

lemma maximalidealI:
  fixes R
  assumes "ideal I R"
    and I_notcarr: "carrier R \<noteq> I"
    and I_maximal: "\<And>J. \<lbrakk>ideal J R; I \<subseteq> J; J \<subseteq> carrier R\<rbrakk> \<Longrightarrow> (J = I) \<or> (J = carrier R)"
  shows "maximalideal I R"
proof -
  interpret ideal I R by fact
  show ?thesis
    by (intro maximalideal.intro maximalideal_axioms.intro)
      (rule is_ideal, rule I_notcarr, rule I_maximal)
qed

subsubsection \<open>Prime Ideals\<close>

locale primeideal = ideal + cring +
  assumes I_notcarr: "carrier R \<noteq> I"
    and I_prime: "\<lbrakk>a \<in> carrier R; b \<in> carrier R; a \<otimes> b \<in> I\<rbrakk> \<Longrightarrow> a \<in> I \<or> b \<in> I"

lemma (in primeideal) primeideal: "primeideal I R"
  by (rule primeideal_axioms)

lemma primeidealI:
  fixes R (structure)
  assumes "ideal I R"
    and "cring R"
    and I_notcarr: "carrier R \<noteq> I"
    and I_prime: "\<And>a b. \<lbrakk>a \<in> carrier R; b \<in> carrier R; a \<otimes> b \<in> I\<rbrakk> \<Longrightarrow> a \<in> I \<or> b \<in> I"
  shows "primeideal I R"
proof -
  interpret ideal I R by fact
  interpret cring R by fact
  show ?thesis
    by (intro primeideal.intro primeideal_axioms.intro)
      (rule is_ideal, rule is_cring, rule I_notcarr, rule I_prime)
qed

lemma primeidealI2:
  fixes R (structure)
  assumes "additive_subgroup I R"
    and "cring R"
    and I_l_closed: "\<And>a x. \<lbrakk>a \<in> I; x \<in> carrier R\<rbrakk> \<Longrightarrow> x \<otimes> a \<in> I"
    and I_r_closed: "\<And>a x. \<lbrakk>a \<in> I; x \<in> carrier R\<rbrakk> \<Longrightarrow> a \<otimes> x \<in> I"
    and I_notcarr: "carrier R \<noteq> I"
    and I_prime: "\<And>a b. \<lbrakk>a \<in> carrier R; b \<in> carrier R; a \<otimes> b \<in> I\<rbrakk> \<Longrightarrow> a \<in> I \<or> b \<in> I"
  shows "primeideal I R"
proof -
  interpret additive_subgroup I R by fact
  interpret cring R by fact
  show ?thesis apply intro_locales
    apply (intro ideal_axioms.intro)
    apply (erule (1) I_l_closed)
    apply (erule (1) I_r_closed)
    by (simp add: I_notcarr I_prime primeideal_axioms.intro)
qed

subsection \<open>Special Ideals\<close>

lemma (in ring) zeroideal: "ideal {\<zero>} R"
  by (intro idealI subgroup.intro) (simp_all add: ring_axioms)

lemma (in ring) oneideal: "ideal (carrier R) R"
  by (rule idealI) (auto intro: ring_axioms add.subgroupI)

lemma (in "domain") zeroprimeideal: "primeideal {\<zero>} R"
proof -
  have "carrier R \<noteq> {\<zero>}"
    by (simp add: carrier_one_not_zero)
  then show ?thesis
    by (metis (no_types, lifting) domain_axioms domain_def integral primeidealI singleton_iff zeroideal)
qed

subsection \<open>General Ideal Properies\<close>

lemma (in ideal) one_imp_carrier:
  assumes I_one_closed: "\<one> \<in> I"
  shows "I = carrier R"
proof
  show "carrier R \<subseteq> I"
    using I_r_closed assms by fastforce
  show "I \<subseteq> carrier R"
    by (rule a_subset)
qed

lemma (in ideal) Icarr:
  assumes iI: "i \<in> I"
  shows "i \<in> carrier R"
  using iI by (rule a_Hcarr)

subsection \<open>Intersection of Ideals\<close>

paragraph \<open>Intersection of two ideals\<close>
text \<open>The intersection of any two ideals is again an ideal in @{term R}\<close>

lemma (in ring) i_intersect:
  assumes "ideal I R"
  assumes "ideal J R"
  shows "ideal (I \<inter> J) R"
proof -
  interpret ideal I R by fact
  interpret ideal J R by fact
  have IJ: "I \<inter> J \<subseteq> carrier R"
    by (force simp: a_subset)
  show ?thesis
    apply (intro idealI subgroup.intro)
    apply (simp_all add: IJ ring_axioms I_l_closed assms ideal.I_l_closed ideal.I_r_closed flip: a_inv_def)
    done
qed

text \<open>The intersection of any Number of Ideals is again an Ideal in @{term R}\<close>

lemma (in ring) i_Intersect:
  assumes Sideals: "\<And>I. I \<in> S \<Longrightarrow> ideal I R" and notempty: "S \<noteq> {}"
  shows "ideal (\<Inter>S) R"
proof -
  { fix x y J
    assume "\<forall>I\<in>S. x \<in> I" "\<forall>I\<in>S. y \<in> I" and JS: "J \<in> S"
    interpret ideal J R by (rule Sideals[OF JS])
    have "x \<oplus> y \<in> J"
      by (simp add: JS \<open>\<forall>I\<in>S. x \<in> I\<close> \<open>\<forall>I\<in>S. y \<in> I\<close>) }
  moreover
    have "\<zero> \<in> J" if "J \<in> S" for J
      by (simp add: that Sideals additive_subgroup.zero_closed ideal.axioms(1))
  moreover
  { fix x J
    assume "\<forall>I\<in>S. x \<in> I" and JS: "J \<in> S"
    interpret ideal J R by (rule Sideals[OF JS])
    have "\<ominus> x \<in> J"
      by (simp add: JS \<open>\<forall>I\<in>S. x \<in> I\<close>) }
  moreover
  { fix x y J
    assume "\<forall>I\<in>S. x \<in> I" and ycarr: "y \<in> carrier R" and JS: "J \<in> S"
    interpret ideal J R by (rule Sideals[OF JS])
    have "y \<otimes> x \<in> J" "x \<otimes> y \<in> J"
      using I_l_closed I_r_closed JS \<open>\<forall>I\<in>S. x \<in> I\<close> ycarr by blast+ }
  moreover
  { fix x
    assume "\<forall>I\<in>S. x \<in> I"
    obtain I0 where I0S: "I0 \<in> S"
      using notempty by blast
    interpret ideal I0 R by (rule Sideals[OF I0S])
    have "x \<in> I0"
      by (simp add: I0S \<open>\<forall>I\<in>S. x \<in> I\<close>)
    with a_subset have "x \<in> carrier R" by fast }
  ultimately show ?thesis
    by unfold_locales (auto simp: Inter_eq simp flip: a_inv_def)
qed

subsection \<open>Addition of Ideals\<close>

lemma (in ring) add_ideals:
  assumes idealI: "ideal I R" and idealJ: "ideal J R"
  shows "ideal (I <+> J) R"
proof (rule ideal.intro)
  show "additive_subgroup (I <+> J) R"
    by (intro ideal.axioms[OF idealI] ideal.axioms[OF idealJ] add_additive_subgroups)
  show "ring R"
    by (rule ring_axioms)
  show "ideal_axioms (I <+> J) R"
  proof -
    { fix x i j
      assume xcarr: "x \<in> carrier R" and iI: "i \<in> I" and jJ: "j \<in> J"
      from xcarr ideal.Icarr[OF idealI iI] ideal.Icarr[OF idealJ jJ]
      have "\<exists>h\<in>I. \<exists>k\<in>J. (i \<oplus> j) \<otimes> x = h \<oplus> k"
        by (meson iI ideal.I_r_closed idealJ jJ l_distr local.idealI) }
    moreover
    { fix x i j
      assume xcarr: "x \<in> carrier R" and iI: "i \<in> I" and jJ: "j \<in> J"
      from xcarr ideal.Icarr[OF idealI iI] ideal.Icarr[OF idealJ jJ]
      have "\<exists>h\<in>I. \<exists>k\<in>J. x \<otimes> (i \<oplus> j) = h \<oplus> k"
        by (meson iI ideal.I_l_closed idealJ jJ local.idealI r_distr) }
    ultimately show "ideal_axioms (I <+> J) R"
      by (intro ideal_axioms.intro) (auto simp: set_add_defs)
  qed
qed

subsection (in ring) \<open>Ideals generated by a subset of @{term "carrier R"}\<close>

text \<open>@{term genideal} generates an ideal\<close>
lemma (in ring) genideal_ideal:
  assumes Scarr: "S \<subseteq> carrier R"
  shows "ideal (Idl S) R"
unfolding genideal_def
proof (rule i_Intersect, fast, simp)
  from oneideal and Scarr
  show "\<exists>I. ideal I R \<and> S \<le> I" by fast
qed

lemma (in ring) genideal_self:
  assumes "S \<subseteq> carrier R"
  shows "S \<subseteq> Idl S"
  unfolding genideal_def by fast

lemma (in ring) genideal_self':
  assumes carr: "i \<in> carrier R"
  shows "i \<in> Idl {i}"
  by (simp add: genideal_def)

text \<open>@{term genideal} generates the minimal ideal\<close>
lemma (in ring) genideal_minimal:
  assumes "ideal I R" "S \<subseteq> I"
  shows "Idl S \<subseteq> I"
  unfolding genideal_def by rule (elim InterD, simp add: assms)

text \<open>Generated ideals and subsets\<close>
lemma (in ring) Idl_subset_ideal:
  assumes Iideal: "ideal I R"
    and Hcarr: "H \<subseteq> carrier R"
  shows "(Idl H \<subseteq> I) = (H \<subseteq> I)"
proof
  assume a: "Idl H \<subseteq> I"
  from Hcarr have "H \<subseteq> Idl H" by (rule genideal_self)
  with a show "H \<subseteq> I" by simp
next
  fix x
  assume "H \<subseteq> I"
  with Iideal have "I \<in> {I. ideal I R \<and> H \<subseteq> I}" by fast
  then show "Idl H \<subseteq> I" unfolding genideal_def by fast
qed

lemma (in ring) subset_Idl_subset:
  assumes Icarr: "I \<subseteq> carrier R"
    and HI: "H \<subseteq> I"
  shows "Idl H \<subseteq> Idl I"
proof -
  from Icarr have Iideal: "ideal (Idl I) R"
    by (rule genideal_ideal)
  from HI and Icarr have "H \<subseteq> carrier R"
    by fast
  with Iideal have "(H \<subseteq> Idl I) = (Idl H \<subseteq> Idl I)"
    by (rule Idl_subset_ideal[symmetric])
  then show "Idl H \<subseteq> Idl I"
    by (meson HI Icarr genideal_self order_trans)
qed

lemma (in ring) Idl_subset_ideal':
  assumes acarr: "a \<in> carrier R" and bcarr: "b \<in> carrier R"
  shows "Idl {a} \<subseteq> Idl {b} \<longleftrightarrow> a \<in> Idl {b}"
proof -
  have "Idl {a} \<subseteq> Idl {b} \<longleftrightarrow> {a} \<subseteq> Idl {b}"
    by (simp add: Idl_subset_ideal acarr bcarr genideal_ideal)
  also have "\<dots> \<longleftrightarrow> a \<in> Idl {b}"
    by blast
  finally show ?thesis .
qed

lemma (in ring) genideal_zero: "Idl {\<zero>} = {\<zero>}"
proof
  show "Idl {\<zero>} \<subseteq> {\<zero>}"
    by (simp add: genideal_minimal zeroideal)
  show "{\<zero>} \<subseteq> Idl {\<zero>}"
    by (simp add: genideal_self')
qed

lemma (in ring) genideal_one: "Idl {\<one>} = carrier R"
proof -
  interpret ideal "Idl {\<one>}" "R" by (rule genideal_ideal) fast
  show "Idl {\<one>} = carrier R"
    using genideal_self' one_imp_carrier by blast
qed

text \<open>Generation of Principal Ideals in Commutative Rings\<close>

definition cgenideal :: "_ \<Rightarrow> 'a \<Rightarrow> 'a set"  ("PIdl\<index> _" [80] 79)
  where "cgenideal R a = {x \<otimes>\<^bsub>R\<^esub> a | x. x \<in> carrier R}"

text \<open>genhideal (?) really generates an ideal\<close>
lemma (in cring) cgenideal_ideal:
  assumes acarr: "a \<in> carrier R"
  shows "ideal (PIdl a) R"
  unfolding cgenideal_def
proof (intro subgroup.intro idealI[OF ring_axioms], simp_all)
  show "{x \<otimes> a |x. x \<in> carrier R} \<subseteq> carrier R"
    by (blast intro: acarr)
  show "\<And>x y. \<lbrakk>\<exists>u. x = u \<otimes> a \<and> u \<in> carrier R; \<exists>x. y = x \<otimes> a \<and> x \<in> carrier R\<rbrakk>
              \<Longrightarrow> \<exists>v. x \<oplus> y = v \<otimes> a \<and> v \<in> carrier R"
    by (metis assms cring.cring_simprules(1) is_cring l_distr)
  show "\<exists>x. \<zero> = x \<otimes> a \<and> x \<in> carrier R"
    by (metis assms l_null zero_closed)
  show "\<And>x. \<exists>u. x = u \<otimes> a \<and> u \<in> carrier R
            \<Longrightarrow> \<exists>v. inv\<^bsub>add_monoid R\<^esub> x = v \<otimes> a \<and> v \<in> carrier R"
    by (metis a_inv_def add.inv_closed assms l_minus)
  show "\<And>b x. \<lbrakk>\<exists>x. b = x \<otimes> a \<and> x \<in> carrier R; x \<in> carrier R\<rbrakk>
       \<Longrightarrow> \<exists>z. x \<otimes> b = z \<otimes> a \<and> z \<in> carrier R"
    by (metis assms m_assoc m_closed)
  show "\<And>b x. \<lbrakk>\<exists>x. b = x \<otimes> a \<and> x \<in> carrier R; x \<in> carrier R\<rbrakk>
       \<Longrightarrow> \<exists>z. b \<otimes> x = z \<otimes> a \<and> z \<in> carrier R"
    by (metis assms m_assoc m_comm m_closed)
qed

lemma (in ring) cgenideal_self:
  assumes icarr: "i \<in> carrier R"
  shows "i \<in> PIdl i"
  unfolding cgenideal_def
proof simp
  from icarr have "i = \<one> \<otimes> i"
    by simp
  with icarr show "\<exists>x. i = x \<otimes> i \<and> x \<in> carrier R"
    by fast
qed

text \<open>@{const "cgenideal"} is minimal\<close>

lemma (in ring) cgenideal_minimal:
  assumes "ideal J R"
  assumes aJ: "a \<in> J"
  shows "PIdl a \<subseteq> J"
proof -
  interpret ideal J R by fact
  show ?thesis
    unfolding cgenideal_def
    using I_l_closed aJ by blast
qed

lemma (in cring) cgenideal_eq_genideal:
  assumes icarr: "i \<in> carrier R"
  shows "PIdl i = Idl {i}"
proof
  show "PIdl i \<subseteq> Idl {i}"
    by (simp add: cgenideal_minimal genideal_ideal genideal_self' icarr)
  show "Idl {i} \<subseteq> PIdl i"
    by (simp add: cgenideal_ideal cgenideal_self genideal_minimal icarr)
qed

lemma (in cring) cgenideal_eq_rcos: "PIdl i = carrier R #> i"
  unfolding cgenideal_def r_coset_def by fast

lemma (in cring) cgenideal_is_principalideal:
  assumes "i \<in> carrier R"
  shows "principalideal (PIdl i) R"
proof -
  have "\<exists>i'\<in>carrier R. PIdl i = Idl {i'}"
    using cgenideal_eq_genideal assms by auto
  then show ?thesis
    by (simp add: cgenideal_ideal assms principalidealI)
qed

subsection \<open>Union of Ideals\<close>

lemma (in ring) union_genideal:
  assumes idealI: "ideal I R" and idealJ: "ideal J R"
  shows "Idl (I \<union> J) = I <+> J"
proof
  show "Idl (I \<union> J) \<subseteq> I <+> J"
  proof (rule ring.genideal_minimal [OF ring_axioms])
    show "ideal (I <+> J) R"
      by (rule add_ideals[OF idealI idealJ])
    have "\<And>x. x \<in> I \<Longrightarrow> \<exists>xa\<in>I. \<exists>xb\<in>J. x = xa \<oplus> xb"
      by (metis additive_subgroup.zero_closed ideal.Icarr idealJ ideal_def local.idealI r_zero)
    moreover have "\<And>x. x \<in> J \<Longrightarrow> \<exists>xa\<in>I. \<exists>xb\<in>J. x = xa \<oplus> xb"
      by (metis additive_subgroup.zero_closed ideal.Icarr idealJ ideal_def l_zero local.idealI)
    ultimately show "I \<union> J \<subseteq> I <+> J"
      by (auto simp: set_add_defs)
  qed
next
  show "I <+> J \<subseteq> Idl (I \<union> J)"
    by (auto simp: set_add_defs genideal_def additive_subgroup.a_closed ideal_def set_mp)
qed

subsection \<open>Properties of Principal Ideals\<close>

text \<open>The zero ideal is a principal ideal\<close>
corollary (in ring) zeropideal: "principalideal {\<zero>} R"
  using genideal_zero principalidealI zeroideal by blast

text \<open>The unit ideal is a principal ideal\<close>
corollary (in ring) onepideal: "principalideal (carrier R) R"
  using genideal_one oneideal principalidealI by blast

text \<open>Every principal ideal is a right coset of the carrier\<close>
lemma (in principalideal) rcos_generate:
  assumes "cring R"
  shows "\<exists>x\<in>I. I = carrier R #> x"
proof -
  interpret cring R by fact
  from generate obtain i where icarr: "i \<in> carrier R" and I1: "I = Idl {i}"
    by fast+
  then have "I = PIdl i"
    by (simp add: cgenideal_eq_genideal)
  moreover have "i \<in> I"
    by (simp add: I1 genideal_self' icarr)
  moreover have "PIdl i = carrier R #> i"
    unfolding cgenideal_def r_coset_def by fast
  ultimately show "\<exists>x\<in>I. I = carrier R #> x"
    by fast
qed

(* Next lemma contributed by Paulo Emílio de Vilhena. *)

text \<open>This next lemma would be trivial if placed in a theory that imports QuotRing,
      but it makes more sense to have it here (easier to find and coherent with the
      previous developments).\<close>

lemma (in cring) cgenideal_prod:
  assumes "a \<in> carrier R" "b \<in> carrier R"
  shows "(PIdl a) <#> (PIdl b) = PIdl (a \<otimes> b)"
proof -
  have "(carrier R #> a) <#> (carrier R #> b) = carrier R #> (a \<otimes> b)"
  proof
    show "(carrier R #> a) <#> (carrier R #> b) \<subseteq> carrier R #> a \<otimes> b"
    proof
      fix x assume "x \<in> (carrier R #> a) <#> (carrier R #> b)"
      then obtain r1 r2 where r1: "r1 \<in> carrier R" and r2: "r2 \<in> carrier R"
                          and "x = (r1 \<otimes> a) \<otimes> (r2 \<otimes> b)"
        unfolding set_mult_def r_coset_def by blast
      hence "x = (r1 \<otimes> r2) \<otimes> (a \<otimes> b)"
        by (simp add: assms local.ring_axioms m_lcomm ring.ring_simprules(11))
      thus "x \<in> carrier R #> a \<otimes> b"
        unfolding r_coset_def using r1 r2 assms by blast
    qed
  next
    show "carrier R #> a \<otimes> b \<subseteq> (carrier R #> a) <#> (carrier R #> b)"
    proof
      fix x assume "x \<in> carrier R #> a \<otimes> b"
      then obtain r where r: "r \<in> carrier R" "x = r \<otimes> (a \<otimes> b)"
        unfolding r_coset_def by blast
      hence "x = (r \<otimes> a) \<otimes> (\<one> \<otimes> b)"
        using assms by (simp add: m_assoc)
      thus "x \<in> (carrier R #> a) <#> (carrier R #> b)"
        unfolding set_mult_def r_coset_def using assms r by blast
    qed
  qed
  thus ?thesis
    using cgenideal_eq_rcos[of a] cgenideal_eq_rcos[of b] cgenideal_eq_rcos[of "a \<otimes> b"] by simp
qed

subsection \<open>Prime Ideals\<close>

lemma (in ideal) primeidealCD:
  assumes "cring R"
  assumes notprime: "\<not> primeideal I R"
  shows "carrier R = I \<or> (\<exists>a b. a \<in> carrier R \<and> b \<in> carrier R \<and> a \<otimes> b \<in> I \<and> a \<notin> I \<and> b \<notin> I)"
proof (rule ccontr, clarsimp)
  interpret cring R by fact
  assume InR: "carrier R \<noteq> I"
    and "\<forall>a. a \<in> carrier R \<longrightarrow> (\<forall>b. a \<otimes> b \<in> I \<longrightarrow> b \<in> carrier R \<longrightarrow> a \<in> I \<or> b \<in> I)"
  then have I_prime: "\<And> a b. \<lbrakk>a \<in> carrier R; b \<in> carrier R; a \<otimes> b \<in> I\<rbrakk> \<Longrightarrow> a \<in> I \<or> b \<in> I"
    by simp
  have "primeideal I R"
    by (simp add: I_prime InR is_cring is_ideal primeidealI)
  with notprime show False by simp
qed

lemma (in ideal) primeidealCE:
  assumes "cring R"
  assumes notprime: "\<not> primeideal I R"
  obtains "carrier R = I"
    | "\<exists>a b. a \<in> carrier R \<and> b \<in> carrier R \<and> a \<otimes> b \<in> I \<and> a \<notin> I \<and> b \<notin> I"
proof -
  interpret R: cring R by fact
  assume "carrier R = I ==> thesis"
    and "\<exists>a b. a \<in> carrier R \<and> b \<in> carrier R \<and> a \<otimes> b \<in> I \<and> a \<notin> I \<and> b \<notin> I \<Longrightarrow> thesis"
  then show thesis using primeidealCD [OF R.is_cring notprime] by blast
qed

text \<open>If \<open>{\<zero>}\<close> is a prime ideal of a commutative ring, the ring is a domain\<close>
lemma (in cring) zeroprimeideal_domainI:
  assumes pi: "primeideal {\<zero>} R"
  shows "domain R"
proof (intro domain.intro is_cring domain_axioms.intro)
  show "\<one> \<noteq> \<zero>"
    using genideal_one genideal_zero pi primeideal.I_notcarr by force
  show "a = \<zero> \<or> b = \<zero>" if ab: "a \<otimes> b = \<zero>" and carr: "a \<in> carrier R" "b \<in> carrier R" for a b
  proof -
    interpret primeideal "{\<zero>}" "R" by (rule pi)
    show "a = \<zero> \<or> b = \<zero>"
      using I_prime ab carr by blast
  qed
qed

corollary (in cring) domain_eq_zeroprimeideal: "domain R = primeideal {\<zero>} R"
  using domain.zeroprimeideal zeroprimeideal_domainI by blast

subsection \<open>Maximal Ideals\<close>

lemma (in ideal) helper_I_closed:
  assumes carr: "a \<in> carrier R" "x \<in> carrier R" "y \<in> carrier R"
    and axI: "a \<otimes> x \<in> I"
  shows "a \<otimes> (x \<otimes> y) \<in> I"
proof -
  from axI and carr have "(a \<otimes> x) \<otimes> y \<in> I"
    by (simp add: I_r_closed)
  also from carr have "(a \<otimes> x) \<otimes> y = a \<otimes> (x \<otimes> y)"
    by (simp add: m_assoc)
  finally show "a \<otimes> (x \<otimes> y) \<in> I" .
qed

lemma (in ideal) helper_max_prime:
  assumes "cring R"
  assumes acarr: "a \<in> carrier R"
  shows "ideal {x\<in>carrier R. a \<otimes> x \<in> I} R"
proof -
  interpret cring R by fact
  show ?thesis
  proof (rule idealI, simp_all)
    show "ring R"
      by (simp add: local.ring_axioms)
    show "subgroup {x \<in> carrier R. a \<otimes> x \<in> I} (add_monoid R)"
      by (rule subgroup.intro) (auto simp: r_distr acarr r_minus simp flip: a_inv_def)
    show "\<And>b x. \<lbrakk>b \<in> carrier R \<and> a \<otimes> b \<in> I; x \<in> carrier R\<rbrakk>
                 \<Longrightarrow> a \<otimes> (x \<otimes> b) \<in> I"
      using acarr helper_I_closed m_comm by auto
    show "\<And>b x. \<lbrakk>b \<in> carrier R \<and> a \<otimes> b \<in> I; x \<in> carrier R\<rbrakk>
                \<Longrightarrow> a \<otimes> (b \<otimes> x) \<in> I"
      by (simp add: acarr helper_I_closed)
  qed
qed

text \<open>In a cring every maximal ideal is prime\<close>
lemma (in cring) maximalideal_prime:
  assumes "maximalideal I R"
  shows "primeideal I R"
proof -
  interpret maximalideal I R by fact
  show ?thesis
  proof (rule ccontr)
    assume neg: "\<not> primeideal I R"
    then obtain a b where acarr: "a \<in> carrier R" and bcarr: "b \<in> carrier R"
      and abI: "a \<otimes> b \<in> I" and anI: "a \<notin> I" and bnI: "b \<notin> I"
      using primeidealCE [OF is_cring]
      by (metis I_notcarr)
    define J where "J = {x\<in>carrier R. a \<otimes> x \<in> I}"
    from is_cring and acarr have idealJ: "ideal J R"
      unfolding J_def by (rule helper_max_prime)
    have IsubJ: "I \<subseteq> J"
      using I_l_closed J_def a_Hcarr acarr by blast
    from abI and acarr bcarr have "b \<in> J"
      unfolding J_def by fast
    with bnI have JnI: "J \<noteq> I" by fast
    have "\<one> \<notin> J"
      unfolding J_def by (simp add: acarr anI)
    then have Jncarr: "J \<noteq> carrier R" by fast
    interpret ideal J R by (rule idealJ)
    have "J = I \<or> J = carrier R"
      by (simp add: I_maximal IsubJ a_subset is_ideal)
    with JnI and Jncarr show False by simp
  qed
qed

subsection \<open>Derived Theorems\<close>

text \<open>A non-zero cring that has only the two trivial ideals is a field\<close>
lemma (in cring) trivialideals_fieldI:
  assumes carrnzero: "carrier R \<noteq> {\<zero>}"
    and haveideals: "{I. ideal I R} = {{\<zero>}, carrier R}"
  shows "field R"
proof (intro cring_fieldI equalityI)
  show "Units R \<subseteq> carrier R - {\<zero>}"
    by (metis Diff_empty Units_closed Units_r_inv_ex carrnzero l_null one_zeroD subsetI subset_Diff_insert)
  show "carrier R - {\<zero>} \<subseteq> Units R"
  proof
    fix x
    assume xcarr': "x \<in> carrier R - {\<zero>}"
    then have xcarr: "x \<in> carrier R" and xnZ: "x \<noteq> \<zero>" by auto
    from xcarr have xIdl: "ideal (PIdl x) R"
      by (intro cgenideal_ideal) fast
    have "PIdl x \<noteq> {\<zero>}"
      using xcarr xnZ cgenideal_self by blast
    with haveideals have "PIdl x = carrier R"
      by (blast intro!: xIdl)
    then have "\<one> \<in> PIdl x" by simp
    then have "\<exists>y. \<one> = y \<otimes> x \<and> y \<in> carrier R"
      unfolding cgenideal_def by blast
    then obtain y where ycarr: " y \<in> carrier R" and ylinv: "\<one> = y \<otimes> x"
      by fast
    have "\<exists>y \<in> carrier R. y \<otimes> x = \<one> \<and> x \<otimes> y = \<one>"
      using m_comm xcarr ycarr ylinv by auto
    with xcarr show "x \<in> Units R"
      unfolding Units_def by fast
  qed
qed

lemma (in field) all_ideals: "{I. ideal I R} = {{\<zero>}, carrier R}"
proof (intro equalityI subsetI)
  fix I
  assume a: "I \<in> {I. ideal I R}"
  then interpret ideal I R by simp

  show "I \<in> {{\<zero>}, carrier R}"
  proof (cases "\<exists>a. a \<in> I - {\<zero>}")
    case True
    then obtain a where aI: "a \<in> I" and anZ: "a \<noteq> \<zero>"
      by fast+
    have aUnit: "a \<in> Units R"
      by (simp add: aI anZ field_Units)
    then have a: "a \<otimes> inv a = \<one>" by (rule Units_r_inv)
    from aI and aUnit have "a \<otimes> inv a \<in> I"
      by (simp add: I_r_closed del: Units_r_inv)
    then have oneI: "\<one> \<in> I" by (simp add: a[symmetric])
    have "carrier R \<subseteq> I"
      using oneI one_imp_carrier by auto
    with a_subset have "I = carrier R" by fast
    then show "I \<in> {{\<zero>}, carrier R}" by fast
  next
    case False
    then have IZ: "\<And>a. a \<in> I \<Longrightarrow> a = \<zero>" by simp
    have a: "I \<subseteq> {\<zero>}"
      using False by auto
    have "\<zero> \<in> I" by simp
    with a have "I = {\<zero>}" by fast
    then show "I \<in> {{\<zero>}, carrier R}" by fast
  qed
qed (auto simp: zeroideal oneideal)

\<comment>\<open>"Jacobson Theorem 2.2"\<close>
lemma (in cring) trivialideals_eq_field:
  assumes carrnzero: "carrier R \<noteq> {\<zero>}"
  shows "({I. ideal I R} = {{\<zero>}, carrier R}) = field R"
  by (fast intro!: trivialideals_fieldI[OF carrnzero] field.all_ideals)

text \<open>Like zeroprimeideal for domains\<close>
lemma (in field) zeromaximalideal: "maximalideal {\<zero>} R"
proof (intro maximalidealI zeroideal)
  from one_not_zero have "\<one> \<notin> {\<zero>}" by simp
  with one_closed show "carrier R \<noteq> {\<zero>}" by fast
next
  fix J
  assume Jideal: "ideal J R"
  then have "J \<in> {I. ideal I R}" by fast
  with all_ideals show "J = {\<zero>} \<or> J = carrier R"
    by simp
qed

lemma (in cring) zeromaximalideal_fieldI:
  assumes zeromax: "maximalideal {\<zero>} R"
  shows "field R"
proof (intro trivialideals_fieldI maximalideal.I_notcarr[OF zeromax])
  have "J = carrier R" if Jn0: "J \<noteq> {\<zero>}" and idealJ: "ideal J R" for J
  proof -
    interpret ideal J R by (rule idealJ)
    have "{\<zero>} \<subseteq> J"
      by force
    from zeromax idealJ this a_subset
    have "J = {\<zero>} \<or> J = carrier R"
      by (rule maximalideal.I_maximal)
    with Jn0 show "J = carrier R"
      by simp
  qed
  then show "{I. ideal I R} = {{\<zero>}, carrier R}"
    by (auto simp: zeroideal oneideal)
qed

lemma (in cring) zeromaximalideal_eq_field: "maximalideal {\<zero>} R = field R"
  using field.zeromaximalideal zeromaximalideal_fieldI by blast

end


(*  Title:      Fun With Functions
    Author:     Tobias Nipkow
*)

theory FunWithFunctions imports Complex_Main begin

text\<open>See \cite{Tao2006}. Was first brought to our attention by Herbert
Ehler who provided a similar proof.\<close>

theorem identity1: fixes f :: "nat \<Rightarrow> nat"
assumes fff: "\<And>n. f(f(n)) < f(Suc(n))"
shows "f(n) = n"
proof -
  { fix m n have key: "n \<le> m \<Longrightarrow> n \<le> f(m)"
    proof(induct n arbitrary: m)
      case 0 show ?case by simp
    next
      case (Suc n)
      hence "m \<noteq> 0" by simp
      then obtain k where [simp]: "m = Suc k" by (metis not0_implies_Suc)
      have "n \<le> f(k)" using Suc by simp
      hence "n \<le> f(f(k))" using Suc by simp
      also have "\<dots> < f(m)" using fff by simp
      finally show ?case by simp
    qed }
  hence "\<And>n. n \<le> f(n)" by simp
  hence "\<And>n. f(n) < f(Suc n)" by(metis fff order_le_less_trans)
  hence "f(n) < n+1" by (metis fff lift_Suc_mono_less_iff[of f] Suc_eq_plus1)
  with \<open>n \<le> f(n)\<close> show "f n = n" by arith
qed

text\<open>See \cite{Tao2006}. Possible extension:
Should also hold if the range of \<open>f\<close> is the reals!
\<close>

lemma identity2: fixes f :: "nat \<Rightarrow> nat"
assumes "f(k) = k" and "k \<ge> 2"
and f_times: "\<And>m n. f(m*n) = f(m)*f(n)"
and f_mono: "\<And>m n. m<n \<Longrightarrow> f m < f n"
shows "f(n) = n"
proof -
  have 0: "f(0) = 0"
    by (metis f_mono f_times mult_1_right mult_is_0 nat_less_le nat_mult_eq_cancel_disj not_less_eq)
  have 1: "f(1) = 1"
    by (metis f_mono f_times gr_implies_not0 mult_eq_self_implies_10 nat_mult_1_right zero_less_one)
  have 2: "f 2 = 2"
  proof -
    have "2 + (k - 2) = k" using \<open>k \<ge> 2\<close> by arith
    hence "f(2) \<le> 2"
      using mono_nat_linear_lb[of f 2 "k - 2",OF f_mono] \<open>f k = k\<close>
      by simp
    thus "f 2 = 2" using 1 f_mono[of 1 2] by arith
  qed
  show ?thesis
  proof(induct rule:less_induct)
    case (less i)
    show ?case
    proof cases
      assume "i\<le>1" thus ?case using 0 1 by (auto simp add:le_Suc_eq)
    next
      assume "~i\<le>1"
      show ?case
      proof cases
        assume "i mod 2 = 0"
        hence "\<exists>k. i=2*k" by arith
        then obtain k where "i = 2*k" ..
        hence "0 < k" and "k<i" using \<open>~i\<le>1\<close> by arith+
        hence "f(k) = k" using less(1) by blast
        thus "f(i) = i" using \<open>i = 2*k\<close> by(simp add:f_times 2)
      next
        assume "i mod 2 \<noteq> 0"
        hence "\<exists>k. i=2*k+1" by arith
        then obtain k where "i = 2*k+1" ..
        hence "0<k" and "k+1<i" using \<open>~i\<le>1\<close> by arith+
        have "2*k < f(2*k+1)"
        proof -
          have "2*k = 2*f(k)" using less(1) \<open>i=2*k+1\<close> by simp
          also have "\<dots> = f(2*k)" by(simp add:f_times 2)
          also have "\<dots> < f(2*k+1)" using f_mono[of "2*k" "2*k+1"] by simp
          finally show ?thesis .
        qed
        moreover
        have "f(2*k+1) < 2*(k+1)"
        proof -
          have "f(2*k+1) < f(2*k+2)" using f_mono[of "2*k+1" "2*k+2"] by simp
          also have "\<dots> = f(2*(k+1))" by simp
          also have "\<dots> = 2*f(k+1)" by(simp only:f_times 2)
          also have "f(k+1) = k+1" using less(1) \<open>i=2*k+1\<close> \<open>~i\<le>1\<close> by simp
          finally show ?thesis .
        qed
        ultimately show "f(i) = i" using \<open>i = 2*k+1\<close> by arith
      qed
    qed
  qed
qed

text\<open>One more from Tao's booklet. If \<open>f\<close> is also assumed to be
continuous, @{term"f(x::real) = x+1"} holds for all reals, not only
rationals. Extend the proof!\<close>

theorem plus1:
fixes f :: "real \<Rightarrow> real"
assumes 0: "f 0 = 1" and f_add: "\<And>x y. f(x+y+1) = f x + f y"

assumes "r : \<rat>" shows "f(r) = r + 1"
proof -
  { fix i have "f(of_int i) = of_int i + 1"
    proof (induct i rule: int_induct [where k=0])
      case base show ?case using 0 by simp
    next
      case (step1 i)
      have "f(of_int (i+1)) = f(of_int i + 0 + 1)" by simp
      also have "\<dots> = f(of_int i) + f 0" by(rule f_add)
      also have "\<dots> = of_int (i+1) + 1" using step1 0 by simp
      finally show ?case .
    next
      case (step2 i)
      have "f(of_int i) = f(of_int (i - 1) + 0 + 1)" by simp
      also have "\<dots> = f(of_int (i - 1)) + f 0" by(rule f_add)
      also have "\<dots> = f(of_int (i - 1)) + 1 " using 0 by simp
      finally show ?case using step2 by simp
    qed }
  note f_int = this
  { fix n r have "f(of_int (Suc n)*r + of_int n) = of_int (Suc n) * f r"
    proof(induct n)
      case 0 show ?case by simp
    next
      case (Suc n)
      have "of_int (Suc(Suc n))*r + of_int (Suc n) =
            r + (of_int (Suc n)*r + of_int n) + 1" (is "?a = ?b")
        by(simp add: field_simps)
      hence "f ?a = f ?b"
        by presburger
      also have "\<dots> = f r + f(of_int (Suc n)*r + of_int n)" by(rule f_add)
      also have "\<dots> = f r + of_int (Suc n) * f r" by(simp only:Suc)
      finally show ?case by(simp add: field_simps)
    qed }
  note 1 = this
  { fix n::nat and r assume "n\<noteq>0"
    have "f(of_int (n)*r + of_int (n - 1)) = of_int (n) * f r"
    proof(cases n)
      case 0 thus ?thesis using \<open>n\<noteq>0\<close> by simp
    next
      case Suc thus ?thesis using \<open>n\<noteq>0\<close> using "1" by auto
    qed }
  note f_mult = this
  from \<open>r:\<rat>\<close> obtain i::int and n::nat where r: "r = of_int i/of_int n" and "n\<noteq>0"
    by(fastforce simp:Rats_eq_int_div_nat)
  have "of_int (n) * f(of_int i / of_int n) = f(of_int i + of_int (n - 1))"
    using \<open>n\<noteq>0\<close>
    by (metis (no_types, hide_lams) f_mult mult.commute nonzero_divide_eq_eq of_int_of_nat_eq of_nat_0_eq_iff)
  also have "\<dots> = f(of_int (i + int n - 1))" using \<open>n\<noteq>0\<close>[simplified]
    by (metis One_nat_def Suc_leI of_nat_1 add_diff_eq of_int_add of_nat_diff)
  also have "\<dots> = of_int (i + int n - 1) + 1" by(rule f_int)
  also have "\<dots> = of_int i + of_int n" by arith
  finally show ?thesis using \<open>n\<noteq>0\<close> unfolding r by (simp add:field_simps)
qed

text\<open>The only total model of a naive recursion equation of factorial on
integers is 0 for all negative arguments. Probably folklore.\<close>

theorem ifac_neg0: fixes ifac :: "int \<Rightarrow> int"
assumes ifac_rec: "\<And>i. ifac i = (if i=0 then 1 else i*ifac(i - 1))"
shows "i<0 \<Longrightarrow> ifac i = 0"
proof(rule ccontr)
  assume 0: "i<0" "ifac i \<noteq> 0"
  { fix j assume "j \<le> i"
    have "ifac j \<noteq> 0"
      apply(rule int_le_induct[OF \<open>j\<le>i\<close>])
       apply(rule \<open>ifac i \<noteq> 0\<close>)
      apply (metis \<open>i<0\<close> ifac_rec linorder_not_le mult_eq_0_iff)
      done
  } note below0 = this
  { fix j assume "j<i"
    have "1 < -j" using \<open>j<i\<close> \<open>i<0\<close> by arith
    have "ifac(j - 1) \<noteq> 0" using \<open>j<i\<close> by(simp add: below0)
    then have "\<bar>ifac (j - 1)\<bar> < (-j) * \<bar>ifac (j - 1)\<bar>" using \<open>j<i\<close>
      mult_le_less_imp_less[OF order_refl[of "abs(ifac(j - 1))"] \<open>1 < -j\<close>]
      by(simp add:mult.commute)
    hence "abs(ifac(j - 1)) < abs(ifac j)"
      using \<open>1 < -j\<close> by(simp add: ifac_rec[of "j"] abs_mult)
  } note not_wf = this
  let ?f = "%j. nat(abs(ifac(i - int(j+1))))"
  obtain k where "\<not> ?f (Suc k) < ?f k"
    using wf_no_infinite_down_chainE[OF wf_less, of "?f"] by blast
  moreover have "i - int (k + 1) - 1 = i - int (Suc k + 1)" by arith
  ultimately show False using not_wf[of "i - int(k+1)"]
    by (simp only:) arith
qed

end


(*  Title:      HOL/Metis_Examples/Trans_Closure.thy
    Author:     Lawrence C. Paulson, Cambridge University Computer Laboratory
    Author:     Jasmin Blanchette, TU Muenchen

Metis example featuring the transitive closure.
*)

section \<open>Metis Example Featuring the Transitive Closure\<close>

theory Trans_Closure
imports Main
begin

declare [[metis_new_skolem]]

type_synonym addr = nat

datatype val
  = Unit        \<comment> "dummy result value of void expressions"
  | Null        \<comment> "null reference"
  | Bool bool   \<comment> "Boolean value"
  | Intg int    \<comment> "integer value"
  | Addr addr   \<comment> "addresses of objects in the heap"

consts R :: "(addr \<times> addr) set"

consts f :: "addr \<Rightarrow> val"

lemma "\<lbrakk>f c = Intg x; \<forall>y. f b = Intg y \<longrightarrow> y \<noteq> x; (a, b) \<in> R\<^sup>*; (b, c) \<in> R\<^sup>*\<rbrakk>
       \<Longrightarrow> \<exists>c. (b, c) \<in> R \<and> (a, c) \<in> R\<^sup>*"
(* sledgehammer *)
proof -
  assume A1: "f c = Intg x"
  assume A2: "\<forall>y. f b = Intg y \<longrightarrow> y \<noteq> x"
  assume A3: "(a, b) \<in> R\<^sup>*"
  assume A4: "(b, c) \<in> R\<^sup>*"
  have F1: "f c \<noteq> f b" using A2 A1 by metis
  have F2: "\<forall>u. (b, u) \<in> R \<longrightarrow> (a, u) \<in> R\<^sup>*" using A3 by (metis transitive_closure_trans(6))
  have F3: "\<exists>x. (b, x b c R) \<in> R \<or> c = b" using A4 by (metis converse_rtranclE)
  have "c \<noteq> b" using F1 by metis
  hence "\<exists>u. (b, u) \<in> R" using F3 by metis
  thus "\<exists>c. (b, c) \<in> R \<and> (a, c) \<in> R\<^sup>*" using F2 by metis
qed

lemma "\<lbrakk>f c = Intg x; \<forall>y. f b = Intg y \<longrightarrow> y \<noteq> x; (a, b) \<in> R\<^sup>*; (b,c) \<in> R\<^sup>*\<rbrakk>
       \<Longrightarrow> \<exists>c. (b, c) \<in> R \<and> (a, c) \<in> R\<^sup>*"
(* sledgehammer [isar_proofs, compress = 2] *)
proof -
  assume A1: "f c = Intg x"
  assume A2: "\<forall>y. f b = Intg y \<longrightarrow> y \<noteq> x"
  assume A3: "(a, b) \<in> R\<^sup>*"
  assume A4: "(b, c) \<in> R\<^sup>*"
  have "b \<noteq> c" using A1 A2 by metis
  hence "\<exists>x\<^sub>1. (b, x\<^sub>1) \<in> R" using A4 by (metis converse_rtranclE)
  thus "\<exists>c. (b, c) \<in> R \<and> (a, c) \<in> R\<^sup>*" using A3 by (metis transitive_closure_trans(6))
qed

lemma "\<lbrakk>f c = Intg x; \<forall>y. f b = Intg y \<longrightarrow> y \<noteq> x; (a, b) \<in> R\<^sup>*; (b, c) \<in> R\<^sup>*\<rbrakk>
       \<Longrightarrow> \<exists>c. (b, c) \<in> R \<and> (a, c) \<in> R\<^sup>*"
apply (erule_tac x = b in converse_rtranclE)
 apply metis
by (metis transitive_closure_trans(6))

end


(* This Isabelle theory is produced using the TIP tool offered at the following website:
     https://github.com/tip-org/tools
   This file was originally provided as part of TIP benchmark at the following website:
     https://github.com/tip-org/benchmarks
   Yutaka Nagashima at CIIRC, CTU changed the TIP output theory file slightly
   to make it compatible with Isabelle2017.*)
  theory TIP_sort_MSortBU2Sorts
  imports "../../Test_Base"
begin

datatype 'a list = nil2 | cons2 "'a" "'a list"

fun risers :: "int list => (int list) list" where
  "risers (nil2) = nil2"
| "risers (cons2 y (nil2)) = cons2 (cons2 y (nil2)) (nil2)"
| "risers (cons2 y (cons2 y2 xs)) =
     (if y <= y2 then
        (case risers (cons2 y2 xs) of
           nil2 => nil2
           | cons2 ys yss => cons2 (cons2 y ys) yss)
        else
        cons2 (cons2 y (nil2)) (risers (cons2 y2 xs)))"

fun ordered :: "int list => bool" where
  "ordered (nil2) = True"
| "ordered (cons2 y (nil2)) = True"
| "ordered (cons2 y (cons2 y2 xs)) =
     ((y <= y2) & (ordered (cons2 y2 xs)))"

fun lmerge :: "int list => int list => int list" where
  "lmerge (nil2) y = y"
| "lmerge (cons2 z x2) (nil2) = cons2 z x2"
| "lmerge (cons2 z x2) (cons2 x3 x4) =
     (if z <= x3 then cons2 z (lmerge x2 (cons2 x3 x4)) else
        cons2 x3 (lmerge (cons2 z x2) x4))"

fun pairwise :: "(int list) list => (int list) list" where
  "pairwise (nil2) = nil2"
| "pairwise (cons2 xs (nil2)) = cons2 xs (nil2)"
| "pairwise (cons2 xs (cons2 ys xss)) =
     cons2 (lmerge xs ys) (pairwise xss)"

(*fun did not finish the proof*)
function mergingbu2 :: "(int list) list => int list" where
  "mergingbu2 (nil2) = nil2"
| "mergingbu2 (cons2 xs (nil2)) = xs"
| "mergingbu2 (cons2 xs (cons2 z x2)) =
     mergingbu2 (pairwise (cons2 xs (cons2 z x2)))"
  by pat_completeness auto

fun msortbu2 :: "int list => int list" where
  "msortbu2 x = mergingbu2 (risers x)"

theorem property0 :
  "ordered (msortbu2 xs)"
  oops

end


(*  Title:      HOL/Library/Permutation.thy
    Author:     Lawrence C Paulson and Thomas M Rasmussen and Norbert Voelker
*)

section \<open>Permutations\<close>

theory Permutation
imports Multiset
begin

inductive perm :: "'a list \<Rightarrow> 'a list \<Rightarrow> bool"  ("_ <~~> _"  [50, 50] 50)  (* FIXME proper infix, without ambiguity!? *)
where
  Nil [intro!]: "[] <~~> []"
| swap [intro!]: "y # x # l <~~> x # y # l"
| Cons [intro!]: "xs <~~> ys \<Longrightarrow> z # xs <~~> z # ys"
| trans [intro]: "xs <~~> ys \<Longrightarrow> ys <~~> zs \<Longrightarrow> xs <~~> zs"

proposition perm_refl [iff]: "l <~~> l"
  by (induct l) auto

subsection \<open>Some examples of rule induction on permutations\<close>

proposition xperm_empty_imp: "[] <~~> ys \<Longrightarrow> ys = []"
  by (induct xs == "[] :: 'a list" ys pred: perm) simp_all

text \<open>\medskip This more general theorem is easier to understand!\<close>

proposition perm_length: "xs <~~> ys \<Longrightarrow> length xs = length ys"
  by (induct pred: perm) simp_all

proposition perm_empty_imp: "[] <~~> xs \<Longrightarrow> xs = []"
  by (drule perm_length) auto

proposition perm_sym: "xs <~~> ys \<Longrightarrow> ys <~~> xs"
  by (induct pred: perm) auto

subsection \<open>Ways of making new permutations\<close>

text \<open>We can insert the head anywhere in the list.\<close>

proposition perm_append_Cons: "a # xs @ ys <~~> xs @ a # ys"
  by (induct xs) auto

proposition perm_append_swap: "xs @ ys <~~> ys @ xs"
  by (induct xs) (auto intro: perm_append_Cons)

proposition perm_append_single: "a # xs <~~> xs @ [a]"
  by (rule perm.trans [OF _ perm_append_swap]) simp

proposition perm_rev: "rev xs <~~> xs"
  by (induct xs) (auto intro!: perm_append_single intro: perm_sym)

proposition perm_append1: "xs <~~> ys \<Longrightarrow> l @ xs <~~> l @ ys"
  by (induct l) auto

proposition perm_append2: "xs <~~> ys \<Longrightarrow> xs @ l <~~> ys @ l"
  by (blast intro!: perm_append_swap perm_append1)

subsection \<open>Further results\<close>

proposition perm_empty [iff]: "[] <~~> xs \<longleftrightarrow> xs = []"
  by (blast intro: perm_empty_imp)

proposition perm_empty2 [iff]: "xs <~~> [] \<longleftrightarrow> xs = []"
  apply auto
  apply (erule perm_sym [THEN perm_empty_imp])
  done

proposition perm_sing_imp: "ys <~~> xs \<Longrightarrow> xs = [y] \<Longrightarrow> ys = [y]"
  by (induct pred: perm) auto

proposition perm_sing_eq [iff]: "ys <~~> [y] \<longleftrightarrow> ys = [y]"
  by (blast intro: perm_sing_imp)

proposition perm_sing_eq2 [iff]: "[y] <~~> ys \<longleftrightarrow> ys = [y]"
  by (blast dest: perm_sym)

subsection \<open>Removing elements\<close>

proposition perm_remove: "x \<in> set ys \<Longrightarrow> ys <~~> x # remove1 x ys"
  by (induct ys) auto

text \<open>\medskip Congruence rule\<close>

proposition perm_remove_perm: "xs <~~> ys \<Longrightarrow> remove1 z xs <~~> remove1 z ys"
  by (induct pred: perm) auto

proposition remove_hd [simp]: "remove1 z (z # xs) = xs"
  by auto

proposition cons_perm_imp_perm: "z # xs <~~> z # ys \<Longrightarrow> xs <~~> ys"
  by (drule perm_remove_perm [where z = z]) auto

proposition cons_perm_eq [iff]: "z#xs <~~> z#ys \<longleftrightarrow> xs <~~> ys"
  by (blast intro: cons_perm_imp_perm)

proposition append_perm_imp_perm: "zs @ xs <~~> zs @ ys \<Longrightarrow> xs <~~> ys"
  by (induct zs arbitrary: xs ys rule: rev_induct) auto

proposition perm_append1_eq [iff]: "zs @ xs <~~> zs @ ys \<longleftrightarrow> xs <~~> ys"
  by (blast intro: append_perm_imp_perm perm_append1)

proposition perm_append2_eq [iff]: "xs @ zs <~~> ys @ zs \<longleftrightarrow> xs <~~> ys"
  apply (safe intro!: perm_append2)
  apply (rule append_perm_imp_perm)
  apply (rule perm_append_swap [THEN perm.trans])
    \<comment> \<open>the previous step helps this \<open>blast\<close> call succeed quickly\<close>
  apply (blast intro: perm_append_swap)
  done

theorem mset_eq_perm: "mset xs = mset ys \<longleftrightarrow> xs <~~> ys"
  apply (rule iffI)
  apply (erule_tac [2] perm.induct)
  apply (simp_all add: union_ac)
  apply (erule rev_mp)
  apply (rule_tac x=ys in spec)
  apply (induct_tac xs)
  apply auto
  apply (erule_tac x = "remove1 a x" in allE)
  apply (drule sym)
  apply simp
  apply (subgoal_tac "a \<in> set x")
  apply (drule_tac z = a in perm.Cons)
  apply (erule perm.trans)
  apply (rule perm_sym)
  apply (erule perm_remove)
  apply (drule_tac f=set_mset in arg_cong)
  apply simp
  done

proposition mset_le_perm_append: "mset xs \<le># mset ys \<longleftrightarrow> (\<exists>zs. xs @ zs <~~> ys)"
  apply (auto simp: mset_eq_perm[THEN sym] mset_subset_eq_exists_conv)
  apply (insert surj_mset)
  apply (drule surjD)
  apply (blast intro: sym)+
  done

proposition perm_set_eq: "xs <~~> ys \<Longrightarrow> set xs = set ys"
  by (metis mset_eq_perm mset_eq_setD)

proposition perm_distinct_iff: "xs <~~> ys \<Longrightarrow> distinct xs = distinct ys"
  apply (induct pred: perm)
     apply simp_all
   apply fastforce
  apply (metis perm_set_eq)
  done

theorem eq_set_perm_remdups: "set xs = set ys \<Longrightarrow> remdups xs <~~> remdups ys"
  apply (induct xs arbitrary: ys rule: length_induct)
  apply (case_tac "remdups xs")
   apply simp_all
  apply (subgoal_tac "a \<in> set (remdups ys)")
   prefer 2 apply (metis list.set(2) insert_iff set_remdups)
  apply (drule split_list) apply (elim exE conjE)
  apply (drule_tac x = list in spec) apply (erule impE) prefer 2
   apply (drule_tac x = "ysa @ zs" in spec) apply (erule impE) prefer 2
    apply simp
    apply (subgoal_tac "a # list <~~> a # ysa @ zs")
     apply (metis Cons_eq_appendI perm_append_Cons trans)
    apply (metis Cons Cons_eq_appendI distinct.simps(2)
      distinct_remdups distinct_remdups_id perm_append_swap perm_distinct_iff)
   apply (subgoal_tac "set (a # list) =
      set (ysa @ a # zs) \<and> distinct (a # list) \<and> distinct (ysa @ a # zs)")
    apply (fastforce simp add: insert_ident)
   apply (metis distinct_remdups set_remdups)
   apply (subgoal_tac "length (remdups xs) < Suc (length xs)")
   apply simp
   apply (subgoal_tac "length (remdups xs) \<le> length xs")
   apply simp
   apply (rule length_remdups_leq)
  done

proposition perm_remdups_iff_eq_set: "remdups x <~~> remdups y \<longleftrightarrow> set x = set y"
  by (metis List.set_remdups perm_set_eq eq_set_perm_remdups)

theorem permutation_Ex_bij:
  assumes "xs <~~> ys"
  shows "\<exists>f. bij_betw f {..<length xs} {..<length ys} \<and> (\<forall>i<length xs. xs ! i = ys ! (f i))"
  using assms
proof induct
  case Nil
  then show ?case
    unfolding bij_betw_def by simp
next
  case (swap y x l)
  show ?case
  proof (intro exI[of _ "Fun.swap 0 1 id"] conjI allI impI)
    show "bij_betw (Fun.swap 0 1 id) {..<length (y # x # l)} {..<length (x # y # l)}"
      by (auto simp: bij_betw_def)
    fix i
    assume "i < length (y # x # l)"
    show "(y # x # l) ! i = (x # y # l) ! (Fun.swap 0 1 id) i"
      by (cases i) (auto simp: Fun.swap_def gr0_conv_Suc)
  qed
next
  case (Cons xs ys z)
  then obtain f where bij: "bij_betw f {..<length xs} {..<length ys}"
    and perm: "\<forall>i<length xs. xs ! i = ys ! (f i)"
    by blast
  let ?f = "\<lambda>i. case i of Suc n \<Rightarrow> Suc (f n) | 0 \<Rightarrow> 0"
  show ?case
  proof (intro exI[of _ ?f] allI conjI impI)
    have *: "{..<length (z#xs)} = {0} \<union> Suc ` {..<length xs}"
            "{..<length (z#ys)} = {0} \<union> Suc ` {..<length ys}"
      by (simp_all add: lessThan_Suc_eq_insert_0)
    show "bij_betw ?f {..<length (z#xs)} {..<length (z#ys)}"
      unfolding *
    proof (rule bij_betw_combine)
      show "bij_betw ?f (Suc ` {..<length xs}) (Suc ` {..<length ys})"
        using bij unfolding bij_betw_def
        by (auto intro!: inj_onI imageI dest: inj_onD simp: image_comp comp_def)
    qed (auto simp: bij_betw_def)
    fix i
    assume "i < length (z # xs)"
    then show "(z # xs) ! i = (z # ys) ! (?f i)"
      using perm by (cases i) auto
  qed
next
  case (trans xs ys zs)
  then obtain f g
    where bij: "bij_betw f {..<length xs} {..<length ys}" "bij_betw g {..<length ys} {..<length zs}"
    and perm: "\<forall>i<length xs. xs ! i = ys ! (f i)" "\<forall>i<length ys. ys ! i = zs ! (g i)"
    by blast
  show ?case
  proof (intro exI[of _ "g \<circ> f"] conjI allI impI)
    show "bij_betw (g \<circ> f) {..<length xs} {..<length zs}"
      using bij by (rule bij_betw_trans)
    fix i
    assume "i < length xs"
    with bij have "f i < length ys"
      unfolding bij_betw_def by force
    with \<open>i < length xs\<close> show "xs ! i = zs ! (g \<circ> f) i"
      using trans(1,3)[THEN perm_length] perm by auto
  qed
qed

proposition perm_finite: "finite {B. B <~~> A}"
proof (rule finite_subset[where B="{xs. set xs \<subseteq> set A \<and> length xs \<le> length A}"])
 show "finite {xs. set xs \<subseteq> set A \<and> length xs \<le> length A}"
   apply (cases A, simp)
   apply (rule card_ge_0_finite)
   apply (auto simp: card_lists_length_le)
   done
next
 show "{B. B <~~> A} \<subseteq> {xs. set xs \<subseteq> set A \<and> length xs \<le> length A}"
   by (clarsimp simp add: perm_length perm_set_eq)
qed

proposition perm_swap:
    assumes "i < length xs" "j < length xs"
    shows "xs[i := xs ! j, j := xs ! i] <~~> xs"
  using assms by (simp add: mset_eq_perm[symmetric] mset_swap)

end


theory OneThirdRuleDefs
imports "../HOModel"
begin

section \<open>Verification of the \emph{One-Third Rule} Consensus Algorithm\<close>

text \<open>
  We now apply the framework introduced so far to the verification of
  concrete algorithms, starting with algorithm \emph{One-Third Rule},
  which is one of the simplest algorithms presented in~\<^cite>\<open>"charron:heardof"\<close>.
  Nevertheless, the algorithm has some interesting characteristics:
  it ensures safety (i.e., the Integrity and Agreement) properties in the
  presence of arbitrary benign faults, and if everything works perfectly,
  it terminates in just two rounds. \emph{One-Third Rule} is an uncoordinated
  algorithm tolerating benign faults, hence SHO or coordinator sets do not
  play a role in its definition.
\<close>

subsection \<open>Model of the Algorithm\<close>

text \<open>
  We begin by introducing an anonymous type of processes of finite
  cardinality that will instantiate the type variable \<open>'proc\<close>
  of the generic HO model.
\<close>

typedecl Proc \<comment> \<open>the set of processes\<close>
axiomatization where Proc_finite: "OFCLASS(Proc, finite_class)"
instance Proc :: finite by (rule Proc_finite)

abbreviation
  "N \<equiv> card (UNIV::Proc set)"

text \<open>
  The state of each process consists of two fields: \<open>x\<close> holds
  the current value proposed by the process and \<open>decide\<close> the
  value (if any, hence the option type) it has decided.
\<close>

record 'val pstate =
  x :: "'val"
  decide :: "'val option"

text \<open>
  The initial value of field \<open>x\<close> is unconstrained, but no decision
  has been taken initially.
\<close>

definition OTR_initState where
  "OTR_initState p st \<equiv> decide st = None"

text \<open>
  Given a vector \<open>msgs\<close> of values (possibly null) received from
  each process, @{term "HOV msgs v"} denotes the set of processes from
  which value \<open>v\<close> was received.
\<close>

definition HOV :: "(Proc \<Rightarrow> 'val option) \<Rightarrow> 'val \<Rightarrow> Proc set" where
  "HOV msgs v \<equiv> { q . msgs q = Some v }"

text \<open>
  @{term "MFR msgs v"} (``most frequently received'') holds for
  vector \<open>msgs\<close> if no value has been received more frequently
  than \<open>v\<close>.

  Some such value always exists, since there is only a finite set of
  processes and thus a finite set of possible cardinalities of the
  sets @{term "HOV msgs v"}.
\<close>

definition MFR :: "(Proc \<Rightarrow> 'val option) \<Rightarrow> 'val \<Rightarrow> bool" where
  "MFR msgs v \<equiv> \<forall>w. card (HOV msgs w) \<le> card (HOV msgs v)"

lemma MFR_exists: "\<exists>v. MFR msgs v"
proof -
  let ?cards = "{ card (HOV msgs v) | v . True }"
  let ?mfr = "Max ?cards"
  have "\<forall>v. card (HOV msgs v) \<le> N" by (auto intro: card_mono)
  hence "?cards \<subseteq> { 0 .. N }" by auto
  hence fin: "finite ?cards" by (metis atLeast0AtMost finite_atMost finite_subset)
  hence "?mfr \<in> ?cards" by (rule Max_in) auto
  then obtain v where v: "?mfr = card (HOV msgs v)" by auto
  have "MFR msgs v"
  proof (auto simp: MFR_def)
    fix w
    from fin have "card (HOV msgs w) \<le> ?mfr" by (rule Max_ge) auto
    thus "card (HOV msgs w) \<le> card (HOV msgs v)" by (unfold v)
  qed
  thus ?thesis ..
qed

text \<open>
  Also, if a process has heard from at least one other process,
  the most frequently received values are among the received messages.
\<close>

lemma MFR_in_msgs:
  assumes HO:"HOs m p \<noteq> {}"
      and v: "MFR (HOrcvdMsgs OTR_M m p (HOs m p) (rho m)) v"
             (is "MFR ?msgs v")
  shows "\<exists>q \<in> HOs m p. v = the (?msgs q)"
proof -
  from HO obtain q where q: "q \<in> HOs m p"
    by auto
  with v have "HOV ?msgs (the (?msgs q)) \<noteq> {}"
    by (auto simp: HOV_def HOrcvdMsgs_def)
  hence HOp: "0 < card (HOV ?msgs (the (?msgs q)))"
    by auto
  also from v have "\<dots> \<le> card (HOV ?msgs v)"
    by (simp add: MFR_def)
  finally have "HOV ?msgs v \<noteq> {}"
    by auto
  thus ?thesis
    by (auto simp: HOV_def HOrcvdMsgs_def)
qed

text \<open>
  @{term "TwoThirds msgs v"} holds if value \<open>v\<close> has been
  received from more than $2/3$ of all processes.
\<close>

definition TwoThirds where
  "TwoThirds msgs v \<equiv> (2*N) div 3 < card (HOV msgs v)"

text \<open>
  The next-state relation of algorithm \emph{One-Third Rule} for every process
  is defined as follows:
  if the process has received values from more than $2/3$ of all processes,
  the \<open>x\<close> field is set to the smallest among the most frequently received
  values, and the process decides value $v$ if it received $v$ from more than
  $2/3$ of all processes. If \<open>p\<close> hasn't heard from more than $2/3$ of
  all processes, the state remains unchanged.
  (Note that \<open>Some\<close> is the constructor of the option datatype, whereas
  \<open>\<some>\<close> is Hilbert's choice operator.)
  We require the type of values to be linearly ordered so that the minimum
  is guaranteed to be well-defined.
\<close>

definition OTR_nextState where
  "OTR_nextState r p (st::('val::linorder) pstate) msgs st' \<equiv>
   if (2*N) div 3 < card {q. msgs q \<noteq> None}
   then st' = \<lparr> x = Min {v . MFR msgs v},
          decide = (if (\<exists>v. TwoThirds msgs v)
                    then Some (\<some>v. TwoThirds msgs v)
                    else decide st) \<rparr>
   else st' = st"

text \<open>
  The message sending function is very simple: at every round, every process
  sends its current proposal (field \<open>x\<close> of its local state) to all
  processes.
\<close>

definition OTR_sendMsg where
  "OTR_sendMsg r p q st \<equiv> x st"

subsection \<open>Communication Predicate for \emph{One-Third Rule}\<close>

text \<open>
  We now define the communication predicate for the \emph{One-Third Rule}
  algorithm to be correct.
  It requires that, infinitely often, there is a round where all processes
  receive messages from the same set \<open>\<Pi>\<close> of processes where \<open>\<Pi>\<close>
  contains more than two thirds of all processes.
  The ``per-round'' part of the communication predicate is trivial.
\<close>

definition OTR_commPerRd where
  "OTR_commPerRd HOrs \<equiv> True"

definition OTR_commGlobal where
  "OTR_commGlobal HOs \<equiv>
    \<forall>r. \<exists>r0 \<Pi>. r0 \<ge> r \<and> (\<forall>p. HOs r0 p = \<Pi>) \<and> card \<Pi> > (2*N) div 3"

subsection \<open>The \emph{One-Third Rule} Heard-Of Machine\<close>

text \<open>
  We now define the HO machine for the \emph{One-Third Rule} algorithm
  by assembling the algorithm definition and its communication-predicate.
  Because this is an uncoordinated algorithm, the \<open>crd\<close> arguments
  of the initial- and next-state predicates are unused.
\<close>

definition OTR_HOMachine where
  "OTR_HOMachine =
    \<lparr> CinitState =  (\<lambda> p st crd. OTR_initState p st),
     sendMsg =  OTR_sendMsg,
     CnextState = (\<lambda> r p st msgs crd st'. OTR_nextState r p st msgs st'),
     HOcommPerRd = OTR_commPerRd,
     HOcommGlobal = OTR_commGlobal \<rparr>"

abbreviation "OTR_M \<equiv> OTR_HOMachine::(Proc, 'val::linorder pstate, 'val) HOMachine"

end


theory tut3
imports
Main

begin

locale Geom =
  fixes on :: "'p \<Rightarrow> 'l \<Rightarrow> bool"
  assumes line_on_two_pts: "a \<noteq> b \<Longrightarrow> \<exists>l. on a l \<and> on b l"
  and line_on_two_pts_unique: "\<lbrakk> a \<noteq> b; on a l; on b l; on a m; on b m \<rbrakk> \<Longrightarrow> l = m"
  and two_points_on_line: "\<exists>a b. a \<noteq> b \<and> on a l \<and> on b l"
  and three_points_not_on_line: "\<exists>a b c. a \<noteq> b \<and> a \<noteq> c \<and> b \<noteq> c \<and>
                                    \<not> (\<exists>l. on a l \<and> on b l \<and> on c l)"
begin

(* Not asked for in tutorial: An alternative way of writing Axiom 4 *)
lemma three_points_not_on_line_alt:
  "\<exists>a b c. a \<noteq> b \<and> a \<noteq> c \<and> b \<noteq> c \<and> (\<forall>l. on a l \<and> on b l \<longrightarrow> \<not> on c l)"
proof -
  obtain a b c where distinct: "a \<noteq> b \<and> a \<noteq> c \<and> b \<noteq> c" "\<not> (\<exists>l. on a l \<and> on b l \<and> on c l)"
    using three_points_not_on_line by blast
  then have "\<forall>l. on a l \<and> on b l \<longrightarrow> \<not> on c l"
    by blast
  thus ?thesis using distinct by blast
qed

lemma exists_pt_not_on_line: "\<exists>x. \<not> on x l"
proof -
   obtain a b c where l3: "\<not> (on a l \<and> on b l \<and> on c l)" using three_points_not_on_line by blast
   thus ?thesis by blast
qed

lemma two_lines_through_each_point: "\<exists>l m. on x l \<and> on x m \<and> l \<noteq> m"
proof -
  have "\<exists>z. z \<noteq> x"
  proof (rule ccontr)
    from two_points_on_line obtain a b where ab: "(a::'p) \<noteq> b" by blast
    assume "\<nexists>z. z \<noteq> x" then have univ: "\<forall>z. z = x" by blast
    then have "a = x" "b = x" by auto
    then show False using ab by simp
  qed
  then obtain z where "z \<noteq> x" by blast
  then obtain l where xl: "on x l" and zl: "on z l" using line_on_two_pts by blast
  obtain w where n_wl: "\<not> on w l" using exists_pt_not_on_line by blast
  obtain m where wm: "on x m" and zm: "on w m" using line_on_two_pts xl by force
  then have "l \<noteq> m" using n_wl by blast
  thus ?thesis using wm xl by blast
qed

(* Alternative proof of the above that uses Metis *)
lemma two_lines_through_each_point2: "\<exists>l m. on x l \<and> on x m \<and> l \<noteq> m"
proof -
  obtain z where "z \<noteq> x" using two_points_on_line by metis
  then obtain l where xl: "on x l" and zl: "on z l" using line_on_two_pts by blast
  obtain w where n_wl: "\<not> on w l" using exists_pt_not_on_line by blast
  obtain m where wm: "on x m" and zm: "on w m" using line_on_two_pts xl by force
  then have "l \<noteq> m" using n_wl by blast
  thus ?thesis using wm xl by blast
qed

lemma two_lines_through_each_point2: "\<exists>l m. on x l \<and> on x m \<and> l \<noteq> m"
proof -
  obtain z where "z \<noteq> x" using two_points_on_line by metis
  then obtain l where xl: "on x l" and zl: "on z l" using line_on_two_pts by blast
  obtain w where n_wl: "\<not> on w l" using exists_pt_not_on_line by blast
  obtain m where wm: "on x m" and zm: "on w m" using line_on_two_pts xl by force
  then have "l \<noteq> m" using n_wl by blast
  thus ?thesis using wm xl by blast
qed

lemma two_lines_unique_intersect_pt:
   assumes lm: "l \<noteq> m" and "on x l" and "on x m" and "on y l" and "on y m" shows "x = y"
proof (rule ccontr)
   assume "x \<noteq> y" then have "l = m" using line_on_two_pts_unique assms by simp
   thus "False" using lm by simp
qed

end

(* Not asked for in tutorial: An extension of the locale with a new definition
   using the "in" keyword *)

definition (in Geom)
  collinear :: "'p \<Rightarrow> 'p \<Rightarrow> 'p \<Rightarrow> bool"
  where "collinear a b c \<equiv> \<exists>l. on a l \<and> on b l \<and> on c l"

end