(*  Title:      HOL/Algebra/Subrings.thy
    Authors:    Martin Baillon and Paulo Emílio de Vilhena
*)

theory Subrings
  imports Ring RingHom QuotRing Multiplicative_Group
begin

section \<open>Subrings\<close>

subsection \<open>Definitions\<close>

locale subring =
  subgroup H "add_monoid R" + submonoid H R for H and R (structure)

locale subcring = subring +
  assumes sub_m_comm: "\<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<otimes> h2 = h2 \<otimes> h1"

locale subdomain = subcring +
  assumes sub_one_not_zero [simp]: "\<one> \<noteq> \<zero>"
  assumes subintegral: "\<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<otimes> h2 = \<zero> \<Longrightarrow> h1 = \<zero> \<or> h2 = \<zero>"

locale subfield = subdomain K R for K and R (structure) +
  assumes subfield_Units: "Units (R \<lparr> carrier := K \<rparr>) = K - { \<zero> }"

subsection \<open>Basic Properties\<close>

subsubsection \<open>Subrings\<close>

lemma (in ring) subringI:
  assumes "H \<subseteq> carrier R"
    and "\<one> \<in> H"
    and "\<And>h. h \<in> H \<Longrightarrow> \<ominus> h \<in> H"
    and "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<otimes> h2 \<in> H"
    and "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<oplus> h2 \<in> H"
  shows "subring H R"
  using add.subgroupI[OF assms(1) _ assms(3, 5)] assms(2)
        submonoid.intro[OF assms(1, 4, 2)]
  unfolding subring_def by auto

lemma subringE:
  assumes "subring H R"
  shows "H \<subseteq> carrier R"
    and "\<zero>\<^bsub>R\<^esub> \<in> H"
    and "\<one>\<^bsub>R\<^esub> \<in> H"
    and "H \<noteq> {}"
    and "\<And>h. h \<in> H \<Longrightarrow> \<ominus>\<^bsub>R\<^esub> h \<in> H"
    and "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<otimes>\<^bsub>R\<^esub> h2 \<in> H"
    and "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<oplus>\<^bsub>R\<^esub> h2 \<in> H"
  using subring.axioms[OF assms]
  unfolding submonoid_def subgroup_def a_inv_def by auto

lemma (in ring) carrier_is_subring: "subring (carrier R) R"
  by (simp add: subringI)

lemma (in ring) subring_inter:
  assumes "subring I R" and "subring J R"
  shows "subring (I \<inter> J) R"
  using subringE[OF assms(1)] subringE[OF assms(2)] subringI[of "I \<inter> J"] by auto

lemma (in ring) subring_Inter:
  assumes "\<And>I. I \<in> S \<Longrightarrow> subring I R" and "S \<noteq> {}"
  shows "subring (\<Inter>S) R"
proof (rule subringI, auto simp add: assms subringE[of _ R])
  fix x assume "\<forall>I \<in> S. x \<in> I" thus "x \<in> carrier R"
    using assms subringE(1)[of _ R] by blast
qed

lemma (in ring) subring_is_ring:
  assumes "subring H R" shows "ring (R \<lparr> carrier := H \<rparr>)"
proof -
  interpret group "add_monoid (R \<lparr> carrier := H \<rparr>)" + monoid "R \<lparr> carrier := H \<rparr>"
    using subgroup.subgroup_is_group[OF subring.axioms(1) add.is_group] assms
          submonoid.submonoid_is_monoid[OF subring.axioms(2) monoid_axioms] by auto
  show ?thesis
    using subringE(1)[OF assms]
    by (unfold_locales, simp_all add: subringE(1)[OF assms] add.m_comm subset_eq l_distr r_distr)
qed

lemma (in ring) ring_incl_imp_subring:
  assumes "H \<subseteq> carrier R"
    and "ring (R \<lparr> carrier := H \<rparr>)"
  shows "subring H R"
  using group.group_incl_imp_subgroup[OF add.group_axioms, of H] assms(1)
        monoid.monoid_incl_imp_submonoid[OF monoid_axioms assms(1)]
        ring.axioms(1, 2)[OF assms(2)] abelian_group.a_group[of "R \<lparr> carrier := H \<rparr>"]
  unfolding subring_def by auto

lemma (in ring) subring_iff:
  assumes "H \<subseteq> carrier R"
  shows "subring H R \<longleftrightarrow> ring (R \<lparr> carrier := H \<rparr>)"
  using subring_is_ring ring_incl_imp_subring[OF assms] by auto

subsubsection \<open>Subcrings\<close>

lemma (in ring) subcringI:
  assumes "subring H R"
    and "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<otimes> h2 = h2 \<otimes> h1"
  shows "subcring H R"
  unfolding subcring_def subcring_axioms_def using assms by simp+

lemma (in cring) subcringI':
  assumes "subring H R"
  shows "subcring H R"
  using subcringI[OF assms] subringE(1)[OF assms] m_comm by auto

lemma subcringE:
  assumes "subcring H R"
  shows "H \<subseteq> carrier R"
    and "\<zero>\<^bsub>R\<^esub> \<in> H"
    and "\<one>\<^bsub>R\<^esub> \<in> H"
    and "H \<noteq> {}"
    and "\<And>h. h \<in> H \<Longrightarrow> \<ominus>\<^bsub>R\<^esub> h \<in> H"
    and "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<otimes>\<^bsub>R\<^esub> h2 \<in> H"
    and "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<oplus>\<^bsub>R\<^esub> h2 \<in> H"
    and "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<otimes>\<^bsub>R\<^esub> h2 = h2 \<otimes>\<^bsub>R\<^esub> h1"
  using subringE[OF subcring.axioms(1)[OF assms]] subcring.sub_m_comm[OF assms] by simp+

lemma (in cring) carrier_is_subcring: "subcring (carrier R) R"
  by (simp add: subcringI' carrier_is_subring)

lemma (in ring) subcring_inter:
  assumes "subcring I R" and "subcring J R"
  shows "subcring (I \<inter> J) R"
  using subcringE[OF assms(1)] subcringE[OF assms(2)]
        subcringI[of "I \<inter> J"] subringI[of "I \<inter> J"] by auto

lemma (in ring) subcring_Inter:
  assumes "\<And>I. I \<in> S \<Longrightarrow> subcring I R" and "S \<noteq> {}"
  shows "subcring (\<Inter>S) R"
proof (rule subcringI)
  show "subring (\<Inter>S) R"
    using subcring.axioms(1)[of _ R] subring_Inter[of S] assms by auto
next
  fix h1 h2 assume h1: "h1 \<in> \<Inter>S" and h2: "h2 \<in> \<Inter>S"
  obtain S' where S': "S' \<in> S"
    using assms(2) by blast
  hence "h1 \<in> S'" "h2 \<in> S'"
    using h1 h2 by blast+
  thus "h1 \<otimes> h2 = h2 \<otimes> h1"
    using subcring.sub_m_comm[OF assms(1)[OF S']] by simp
qed

lemma (in ring) subcring_iff:
  assumes "H \<subseteq> carrier R"
  shows "subcring H R \<longleftrightarrow> cring (R \<lparr> carrier := H \<rparr>)"
proof
  assume A: "subcring H R"
  hence ring: "ring (R \<lparr> carrier := H \<rparr>)"
    using subring_iff[OF assms] subcring.axioms(1)[OF A] by simp
  moreover have "comm_monoid (R \<lparr> carrier := H \<rparr>)"
    using monoid.monoid_comm_monoidI[OF ring.is_monoid[OF ring]]
          subcring.sub_m_comm[OF A] by auto
  ultimately show "cring (R \<lparr> carrier := H \<rparr>)"
    using cring_def by blast
next
  assume A: "cring (R \<lparr> carrier := H \<rparr>)"
  hence "subring H R"
    using cring.axioms(1) subring_iff[OF assms] by simp
  moreover have "comm_monoid (R \<lparr> carrier := H \<rparr>)"
    using A unfolding cring_def by simp
  hence"\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<otimes> h2 = h2 \<otimes> h1"
    using comm_monoid.m_comm[of "R \<lparr> carrier := H \<rparr>"] by auto
  ultimately show "subcring H R"
    unfolding subcring_def subcring_axioms_def by auto
qed

subsubsection \<open>Subdomains\<close>

lemma (in ring) subdomainI:
  assumes "subcring H R"
    and "\<one> \<noteq> \<zero>"
    and "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<otimes> h2 = \<zero> \<Longrightarrow> h1 = \<zero> \<or> h2 = \<zero>"
  shows "subdomain H R"
  unfolding subdomain_def subdomain_axioms_def using assms by simp+

lemma (in domain) subdomainI':
  assumes "subring H R"
  shows "subdomain H R"
proof (rule subdomainI[OF subcringI[OF assms]], simp_all)
  show "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<otimes> h2 = h2 \<otimes> h1"
    using m_comm subringE(1)[OF assms] by auto
  show "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H; h1 \<otimes> h2 = \<zero> \<rbrakk> \<Longrightarrow> (h1 = \<zero>) \<or> (h2 = \<zero>)"
    using integral subringE(1)[OF assms] by auto
qed

lemma subdomainE:
  assumes "subdomain H R"
  shows "H \<subseteq> carrier R"
    and "\<zero>\<^bsub>R\<^esub> \<in> H"
    and "\<one>\<^bsub>R\<^esub> \<in> H"
    and "H \<noteq> {}"
    and "\<And>h. h \<in> H \<Longrightarrow> \<ominus>\<^bsub>R\<^esub> h \<in> H"
    and "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<otimes>\<^bsub>R\<^esub> h2 \<in> H"
    and "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<oplus>\<^bsub>R\<^esub> h2 \<in> H"
    and "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<otimes>\<^bsub>R\<^esub> h2 = h2 \<otimes>\<^bsub>R\<^esub> h1"
    and "\<And>h1 h2. \<lbrakk> h1 \<in> H; h2 \<in> H \<rbrakk> \<Longrightarrow> h1 \<otimes>\<^bsub>R\<^esub> h2 = \<zero>\<^bsub>R\<^esub> \<Longrightarrow> h1 = \<zero>\<^bsub>R\<^esub> \<or> h2 = \<zero>\<^bsub>R\<^esub>"
    and "\<one>\<^bsub>R\<^esub> \<noteq> \<zero>\<^bsub>R\<^esub>"
  using subcringE[OF subdomain.axioms(1)[OF assms]] assms
  unfolding subdomain_def subdomain_axioms_def by auto

lemma (in ring) subdomain_iff:
  assumes "H \<subseteq> carrier R"
  shows "subdomain H R \<longleftrightarrow> domain (R \<lparr> carrier := H \<rparr>)"
proof
  assume A: "subdomain H R"
  hence cring: "cring (R \<lparr> carrier := H \<rparr>)"
    using subcring_iff[OF assms] subdomain.axioms(1)[OF A] by simp
  thus "domain (R \<lparr> carrier := H \<rparr>)"
    using domain.intro[OF cring] subdomain.subintegral[OF A] subdomain.sub_one_not_zero[OF A]
    unfolding domain_axioms_def by auto
next
  assume A: "domain (R \<lparr> carrier := H \<rparr>)"
  hence subcring: "subcring H R"
    using subcring_iff[OF assms] unfolding domain_def by simp
  thus "subdomain H R"
    using subdomain.intro[OF subcring] domain.integral[OF A] domain.one_not_zero[OF A]
    unfolding subdomain_axioms_def by auto
qed

lemma (in domain) subring_is_domain:
  assumes "subring H R" shows "domain (R \<lparr> carrier := H \<rparr>)"
  using subdomainI'[OF assms] unfolding subdomain_iff[OF subringE(1)[OF assms]] .

(* NEW ====================== *)
lemma (in ring) subdomain_is_domain:
  assumes "subdomain H R" shows "domain (R \<lparr> carrier := H \<rparr>)"
  using assms unfolding subdomain_iff[OF subdomainE(1)[OF assms]] .

subsubsection \<open>Subfields\<close>

lemma (in ring) subfieldI:
  assumes "subcring K R" and "Units (R \<lparr> carrier := K \<rparr>) = K - { \<zero> }"
  shows "subfield K R"
proof (rule subfield.intro)
  show "subfield_axioms K R"
    using assms(2) unfolding subfield_axioms_def .
  show "subdomain K R"
  proof (rule subdomainI[OF assms(1)], auto)
    have subM: "submonoid K R"
      using subring.axioms(2)[OF subcring.axioms(1)[OF assms(1)]] .

    show contr: "\<one> = \<zero> \<Longrightarrow> False"
    proof -
      assume one_eq_zero: "\<one> = \<zero>"
      have "\<one> \<in> K" and "\<one> \<otimes> \<one> = \<one>"
        using submonoid.one_closed[OF subM] by simp+
      hence "\<one> \<in> Units (R \<lparr> carrier := K \<rparr>)"
        unfolding Units_def by (simp, blast)
      hence "\<one> \<noteq> \<zero>"
        using assms(2) by simp
      thus False
        using one_eq_zero by simp
    qed

    fix k1 k2 assume k1: "k1 \<in> K" and k2: "k2 \<in> K" "k2 \<noteq> \<zero>" and k12: "k1 \<otimes> k2 = \<zero>"
    obtain k2' where k2': "k2' \<in> K" "k2' \<otimes> k2 = \<one>" "k2 \<otimes> k2' = \<one>"
      using assms(2) k2 unfolding Units_def by auto
    have  "\<zero> = (k1 \<otimes> k2) \<otimes> k2'"
      using k12 k2'(1) submonoid.mem_carrier[OF subM] by fastforce
    also have  "... = k1"
      using k1 k2(1) k2'(1,3) submonoid.mem_carrier[OF subM] by (simp add: m_assoc)
    finally have "\<zero> = k1" .
    thus "k1 = \<zero>" by simp
  qed
qed

lemma (in field) subfieldI':
  assumes "subring K R" and "\<And>k. k \<in> K - { \<zero> } \<Longrightarrow> inv k \<in> K"
  shows "subfield K R"
proof (rule subfieldI)
  show "subcring K R"
    using subcringI[OF assms(1)] m_comm subringE(1)[OF assms(1)] by auto
  show "Units (R \<lparr> carrier := K \<rparr>) = K - { \<zero> }"
  proof
    show "K - { \<zero> } \<subseteq> Units (R \<lparr> carrier := K \<rparr>)"
    proof
      fix k assume k: "k \<in> K - { \<zero> }"
      hence inv_k: "inv k \<in> K"
        using assms(2) by simp
      moreover have "k \<in> carrier R - { \<zero> }"
        using subringE(1)[OF assms(1)] k by auto
      ultimately have "k \<otimes> inv k = \<one>" "inv k \<otimes> k = \<one>"
        by (simp add: field_Units)+
      thus "k \<in> Units (R \<lparr> carrier := K \<rparr>)"
        unfolding Units_def using k inv_k by auto
    qed
  next
    show "Units (R \<lparr> carrier := K \<rparr>) \<subseteq> K - { \<zero> }"
    proof
      fix k assume k: "k \<in> Units (R \<lparr> carrier := K \<rparr>)"
      then obtain k' where k': "k' \<in> K" "k \<otimes> k' = \<one>"
        unfolding Units_def by auto
      hence "k \<in> carrier R" and "k' \<in> carrier R"
        using k subringE(1)[OF assms(1)] unfolding Units_def by auto
      hence "\<zero> = \<one>" if "k = \<zero>"
        using that k'(2) by auto
      thus "k \<in> K - { \<zero> }"
        using k unfolding Units_def by auto
    qed
  qed
qed

lemma (in field) carrier_is_subfield: "subfield (carrier R) R"
  by (auto intro: subfieldI[OF carrier_is_subcring] simp add: field_Units)

lemma subfieldE:
  assumes "subfield K R"
  shows "subring K R" and "subcring K R"
    and "K \<subseteq> carrier R"
    and "\<And>k1 k2. \<lbrakk> k1 \<in> K; k2 \<in> K \<rbrakk> \<Longrightarrow> k1 \<otimes>\<^bsub>R\<^esub> k2 = k2 \<otimes>\<^bsub>R\<^esub> k1"
    and "\<And>k1 k2. \<lbrakk> k1 \<in> K; k2 \<in> K \<rbrakk> \<Longrightarrow> k1 \<otimes>\<^bsub>R\<^esub> k2 = \<zero>\<^bsub>R\<^esub> \<Longrightarrow> k1 = \<zero>\<^bsub>R\<^esub> \<or> k2 = \<zero>\<^bsub>R\<^esub>"
    and "\<one>\<^bsub>R\<^esub> \<noteq> \<zero>\<^bsub>R\<^esub>"
  using subdomain.axioms(1)[OF subfield.axioms(1)[OF assms]] subcring_def
        subdomainE(1, 8, 9, 10)[OF subfield.axioms(1)[OF assms]] by auto

lemma (in ring) subfield_m_inv:
  assumes "subfield K R" and "k \<in> K - { \<zero> }"
  shows "inv k \<in> K - { \<zero> }" and "k \<otimes> inv k = \<one>" and "inv k \<otimes> k = \<one>"
proof -
  have K: "subring K R" "submonoid K R"
    using subfieldE(1)[OF assms(1)] subring.axioms(2) by auto
  have monoid: "monoid (R \<lparr> carrier := K \<rparr>)"
    using submonoid.submonoid_is_monoid[OF subring.axioms(2)[OF K(1)] is_monoid] .

  have "monoid R"
    by (simp add: monoid_axioms)

  hence k: "k \<in> Units (R \<lparr> carrier := K \<rparr>)"
    using subfield.subfield_Units[OF assms(1)] assms(2) by blast
  hence unit_of_R: "k \<in> Units R"
    using assms(2) subringE(1)[OF subfieldE(1)[OF assms(1)]] unfolding Units_def by auto
  have "inv\<^bsub>(R \<lparr> carrier := K \<rparr>)\<^esub> k \<in> Units (R \<lparr> carrier := K \<rparr>)"
    by (simp add: k monoid monoid.Units_inv_Units)
  hence "inv\<^bsub>(R \<lparr> carrier := K \<rparr>)\<^esub> k \<in> K - { \<zero> }"
    using subfield.subfield_Units[OF assms(1)] by blast
  thus "inv k \<in> K - { \<zero> }" and "k \<otimes> inv k = \<one>" and "inv k \<otimes> k = \<one>"
    using Units_l_inv[OF unit_of_R] Units_r_inv[OF unit_of_R]
    using monoid.m_inv_monoid_consistent[OF monoid_axioms k K(2)] by auto
qed

lemma (in ring) subfield_m_inv_simprule:
  assumes "subfield K R"
  shows "\<lbrakk> k \<in> K - { \<zero> }; a \<in> carrier R \<rbrakk> \<Longrightarrow> k \<otimes> a \<in> K \<Longrightarrow> a \<in> K"
proof -
  note subring_props = subringE[OF subfieldE(1)[OF assms]]

  assume A: "k \<in> K - { \<zero> }" "a \<in> carrier R" "k \<otimes> a \<in> K"
  then obtain k' where k': "k' \<in> K" "k \<otimes> a = k'" by blast
  have inv_k: "inv k \<in> K" "inv k \<otimes> k = \<one>"
    using subfield_m_inv[OF assms A(1)] by auto
  hence "inv k \<otimes> (k \<otimes> a) \<in> K"
    using k' A(3) subring_props(6) by auto
  thus "a \<in> K"
    using m_assoc[of "inv k" k a] A(2) inv_k subring_props(1)
    by (metis (no_types, opaque_lifting) A(1) Diff_iff l_one subsetCE)
qed

lemma (in ring) subfield_iff:
  shows "\<lbrakk> field (R \<lparr> carrier := K \<rparr>); K \<subseteq> carrier R \<rbrakk> \<Longrightarrow> subfield K R"
    and "subfield K R \<Longrightarrow> field (R \<lparr> carrier := K \<rparr>)"
proof-
  assume A: "field (R \<lparr> carrier := K \<rparr>)" "K \<subseteq> carrier R"
  have "\<And>k1 k2. \<lbrakk> k1 \<in> K; k2 \<in> K \<rbrakk> \<Longrightarrow> k1 \<otimes> k2 = k2 \<otimes> k1"
    using comm_monoid.m_comm[OF cring.axioms(2)[OF fieldE(1)[OF A(1)]]]  by simp
  moreover have "subring K R"
    using ring_incl_imp_subring[OF A(2) cring.axioms(1)[OF fieldE(1)[OF A(1)]]] .
  ultimately have "subcring K R"
    using subcringI by simp
  thus "subfield K R"
    using field.field_Units[OF A(1)] subfieldI by auto
next
  assume A: "subfield K R"
  have cring: "cring (R \<lparr> carrier := K \<rparr>)"
    using subcring_iff[OF subringE(1)[OF subfieldE(1)[OF A]]] subfieldE(2)[OF A] by simp
  thus "field (R \<lparr> carrier := K \<rparr>)"
    using cring.cring_fieldI[OF cring] subfield.subfield_Units[OF A] by simp
qed

lemma (in field) subgroup_mult_of :
  assumes "subfield K R"
  shows "subgroup (K - {\<zero>}) (mult_of R)"
proof (intro group.group_incl_imp_subgroup[OF field_mult_group])
  show "K - {\<zero>} \<subseteq> carrier (mult_of R)"
    by (simp add: Diff_mono assms carrier_mult_of subfieldE(3))
  show "group ((mult_of R) \<lparr> carrier := K - {\<zero>} \<rparr>)"
    using field.field_mult_group[OF subfield_iff(2)[OF assms]]
    unfolding mult_of_def by simp
qed

subsection \<open>Subring Homomorphisms\<close>

lemma (in ring) hom_imp_img_subring:
  assumes "h \<in> ring_hom R S" and "subring K R"
  shows "ring (S \<lparr> carrier := h ` K, one := h \<one>, zero := h \<zero> \<rparr>)"
proof -
  have [simp]: "h \<one> = \<one>\<^bsub>S\<^esub>"
    using assms ring_hom_one by blast
  have "ring (R \<lparr> carrier := K \<rparr>)"
    by (simp add: assms(2) subring_is_ring)
  moreover have "h \<in> ring_hom (R \<lparr> carrier := K \<rparr>) S"
    using assms subringE(1)[OF assms (2)] unfolding ring_hom_def
    apply simp
    apply blast
    done
  ultimately show ?thesis
    using ring.ring_hom_imp_img_ring[of "R \<lparr> carrier := K \<rparr>" h S] by simp
qed

lemma (in ring_hom_ring) img_is_subring:
  assumes "subring K R" shows "subring (h ` K) S"
proof -
  have "ring (S \<lparr> carrier := h ` K \<rparr>)"
    using R.hom_imp_img_subring[OF homh assms] hom_zero hom_one by simp
  moreover have "h ` K \<subseteq> carrier S"
    using ring_hom_memE(1)[OF homh] subringE(1)[OF assms] by auto
  ultimately show ?thesis
    using ring_incl_imp_subring by simp
qed

lemma (in ring_hom_ring) img_is_subfield:
  assumes "subfield K R" and "\<one>\<^bsub>S\<^esub> \<noteq> \<zero>\<^bsub>S\<^esub>"
  shows "inj_on h K" and "subfield (h ` K) S"
proof -
  have K: "K \<subseteq> carrier R" "subring K R" "subring (h ` K) S"
    using subfieldE(1)[OF assms(1)] subringE(1) img_is_subring by auto
  have field: "field (R \<lparr> carrier := K \<rparr>)"
    using R.subfield_iff(2) \<open>subfield K R\<close> by blast
  moreover have ring: "ring (R \<lparr> carrier := K \<rparr>)"
    using K R.ring_axioms R.subring_is_ring by blast
  moreover have ringS: "ring (S \<lparr> carrier := h ` K \<rparr>)"
    using subring_is_ring K by simp
  ultimately have h: "h \<in> ring_hom (R \<lparr> carrier := K \<rparr>) (S \<lparr> carrier := h ` K \<rparr>)"
    unfolding ring_hom_def apply auto
    using ring_hom_memE[OF homh] K
    by (meson contra_subsetD)+
  hence ring_hom: "ring_hom_ring (R \<lparr> carrier := K \<rparr>) (S \<lparr> carrier := h ` K \<rparr>) h"
    using ring_axioms ring ringS ring_hom_ringI2 by blast
  have "h ` K \<noteq> { \<zero>\<^bsub>S\<^esub> }"
    using subfieldE(1, 5)[OF assms(1)] subringE(3) assms(2)
    by (metis hom_one image_eqI singletonD)
  thus "inj_on h K"
    using ring_hom_ring.non_trivial_field_hom_imp_inj[OF ring_hom field] by auto

  hence "h \<in> ring_iso (R \<lparr> carrier := K \<rparr>) (S \<lparr> carrier := h ` K \<rparr>)"
    using h unfolding ring_iso_def bij_betw_def by auto
  hence "field (S \<lparr> carrier := h ` K \<rparr>)"
    using field.ring_iso_imp_img_field[OF field, of h "S \<lparr> carrier := h ` K \<rparr>"] by auto
  thus "subfield (h ` K) S"
    using S.subfield_iff[of "h ` K"] K(1) ring_hom_memE(1)[OF homh] by blast
qed

(* NEW ========================================================================== *)
lemma (in ring_hom_ring) induced_ring_hom:
  assumes "subring K R" shows "ring_hom_ring (R \<lparr> carrier := K \<rparr>) S h"
proof -
  have "h \<in> ring_hom (R \<lparr> carrier := K \<rparr>) S"
    using homh subringE(1)[OF assms] unfolding ring_hom_def
    by (auto, meson hom_mult hom_add subsetCE)+
  thus ?thesis
    using R.subring_is_ring[OF assms] ring_axioms
    unfolding ring_hom_ring_def ring_hom_ring_axioms_def by auto
qed

(* NEW ========================================================================== *)
lemma (in ring_hom_ring) inj_on_subgroup_iff_trivial_ker:
  assumes "subring K R"
  shows "inj_on h K \<longleftrightarrow> a_kernel (R \<lparr> carrier := K \<rparr>) S h = { \<zero> }"
  using ring_hom_ring.inj_iff_trivial_ker[OF induced_ring_hom[OF assms]] by simp

lemma (in ring_hom_ring) inv_ring_hom:
  assumes "inj_on h K" and "subring K R"
  shows "ring_hom_ring (S \<lparr> carrier := h ` K \<rparr>) R (inv_into K h)"
proof (intro ring_hom_ringI[OF _ R.ring_axioms], auto)
  show "ring (S \<lparr> carrier := h ` K \<rparr>)"
    using subring_is_ring[OF img_is_subring[OF assms(2)]] .
next
  show "inv_into K h \<one>\<^bsub>S\<^esub> = \<one>\<^bsub>R\<^esub>"
    using assms(1) subringE(3)[OF assms(2)] hom_one by (simp add: inv_into_f_eq)
next
  fix k1 k2
  assume k1: "k1 \<in> K" and k2: "k2 \<in> K"
  with \<open>k1 \<in> K\<close> show "inv_into K h (h k1) \<in> carrier R"
    using assms(1) subringE(1)[OF assms(2)] by (simp add: subset_iff)

  from \<open>k1 \<in> K\<close> and \<open>k2 \<in> K\<close>
  have "h k1 \<oplus>\<^bsub>S\<^esub> h k2 = h (k1 \<oplus>\<^bsub>R\<^esub> k2)" and "k1 \<oplus>\<^bsub>R\<^esub> k2 \<in> K"
   and "h k1 \<otimes>\<^bsub>S\<^esub> h k2 = h (k1 \<otimes>\<^bsub>R\<^esub> k2)" and "k1 \<otimes>\<^bsub>R\<^esub> k2 \<in> K"
    using subringE(1,6,7)[OF assms(2)] by (simp add: subset_iff)+
  thus "inv_into K h (h k1 \<oplus>\<^bsub>S\<^esub> h k2) = inv_into K h (h k1) \<oplus>\<^bsub>R\<^esub> inv_into K h (h k2)"
   and "inv_into K h (h k1 \<otimes>\<^bsub>S\<^esub> h k2) = inv_into K h (h k1) \<otimes>\<^bsub>R\<^esub> inv_into K h (h k2)"
    using assms(1) k1 k2 by simp+
qed

end


(* Property from Case-Analysis for Rippling and Inductive Proof,
   Moa Johansson, Lucas Dixon and Alan Bundy, ITP 2010.
   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.
   Some proofs were added by Yutaka Nagashima.*)
  theory TIP_prop_78
imports "../../Test_Base"
begin

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

datatype Nat = Z | S "Nat"

fun x :: "bool => bool => bool" where
"x True z = z"
| "x False z = False"

fun t2 :: "Nat => Nat => bool" where
"t2 (Z) z = True"
| "t2 (S z2) (Z) = False"
| "t2 (S z2) (S x2) = t2 z2 x2"

fun insort :: "Nat => Nat list => Nat list" where
"insort y (nil2) = cons2 y (nil2)"
| "insort y (cons2 z2 xs) =
     (if t2 y z2 then cons2 y (cons2 z2 xs) else cons2 z2 (insort y xs))"

fun sort :: "Nat list => Nat list" where
"sort (nil2) = nil2"
| "sort (cons2 z xs) = insort z (sort xs)"

fun sorted :: "Nat list => bool" where
"sorted (nil2) = True"
| "sorted (cons2 z (nil2)) = True"
| "sorted (cons2 z (cons2 y2 ys)) =
     x (t2 z y2) (sorted (cons2 y2 ys))"

theorem property0 :
  "sorted (sort xs)"
  oops

end


(*  Author:     Tobias Nipkow
    Copyright   1998 TUM
*)

section "Maximal prefix"

theory MaxPrefix
imports "HOL-Library.Sublist"
begin

definition
 is_maxpref :: "('a list \<Rightarrow> bool) \<Rightarrow> 'a list \<Rightarrow> 'a list \<Rightarrow> bool" where
"is_maxpref P xs ys =
 (prefix xs ys \<and> (xs=[] \<or> P xs) \<and> (\<forall>zs. prefix zs ys \<and> P zs \<longrightarrow> prefix zs xs))"

type_synonym 'a splitter = "'a list \<Rightarrow> 'a list * 'a list"

definition
 is_maxsplitter :: "('a list \<Rightarrow> bool) \<Rightarrow> 'a splitter \<Rightarrow> bool" where
"is_maxsplitter P f =
 (\<forall>xs ps qs. f xs = (ps,qs) = (xs=ps@qs \<and> is_maxpref P ps xs))"

fun maxsplit :: "('a list \<Rightarrow> bool) \<Rightarrow> 'a list * 'a list \<Rightarrow> 'a list \<Rightarrow> 'a splitter" where
"maxsplit P res ps []     = (if P ps then (ps,[]) else res)" |
"maxsplit P res ps (q#qs) = maxsplit P (if P ps then (ps,q#qs) else res)
                                     (ps@[q]) qs"

declare if_split[split del]

lemma maxsplit_lemma: "(maxsplit P res ps qs = (xs,ys)) =
  (if \<exists>us. prefix us qs \<and> P(ps@us) then xs@ys=ps@qs \<and> is_maxpref P xs (ps@qs)
   else (xs,ys)=res)"
proof (induction P res ps qs rule: maxsplit.induct)
  case 1
  thus ?case by (auto simp: is_maxpref_def split: if_splits)
next
  case (2 P res ps q qs)
  show ?case
  proof (cases "\<exists>us. prefix us qs \<and> P ((ps @ [q]) @ us)")
    case True
    note ex1 = this
    then guess us by (elim exE conjE) note us = this
    hence ex2: "\<exists>us. prefix us (q # qs) \<and> P (ps @ us)"
      by (intro exI[of _ "q#us"]) auto
    with ex1 and 2 show ?thesis by simp
  next
    case False
    note ex1 = this
    show ?thesis
    proof (cases "\<exists>us. prefix us (q#qs) \<and> P (ps @ us)")
      case False
      from 2 show ?thesis
        by (simp only: ex1 False) (insert ex1 False, auto simp: prefix_Cons)
    next
      case True
      note ex2 = this
      show ?thesis
      proof (cases "P ps")
        case True
        with 2 have "(maxsplit P (ps, q # qs) (ps @ [q]) qs = (xs, ys)) \<longleftrightarrow> (xs = ps \<and> ys = q # qs)"
          by (simp only: ex1 ex2) simp_all
        also have "\<dots> \<longleftrightarrow> (xs @ ys = ps @ q # qs \<and> is_maxpref P xs (ps @ q # qs))"
          using ex1 True
          by (auto simp: is_maxpref_def prefix_append prefix_Cons append_eq_append_conv2)
        finally show ?thesis using True by (simp only: ex1 ex2) simp_all
      next
        case False
        with 2 have "(maxsplit P res (ps @ [q]) qs = (xs, ys)) \<longleftrightarrow> ((xs, ys) = res)"
          by (simp only: ex1 ex2) simp
        also have "\<dots> \<longleftrightarrow> (xs @ ys = ps @ q # qs \<and> is_maxpref P xs (ps @ q # qs))"
          using ex1 ex2 False
          by (auto simp: append_eq_append_conv2 is_maxpref_def prefix_Cons)
        finally show ?thesis
          using False by (simp only: ex1 ex2) simp
      qed
    qed
  qed
qed

declare if_split[split]

lemma is_maxpref_Nil[simp]:
 "\<not>(\<exists>us. prefix us xs \<and> P us) \<Longrightarrow> is_maxpref P ps xs = (ps = [])"
  by (auto simp: is_maxpref_def)

lemma is_maxsplitter_maxsplit:
 "is_maxsplitter P (\<lambda>xs. maxsplit P ([],xs) [] xs)"
  by (auto simp: maxsplit_lemma is_maxsplitter_def)

lemmas maxsplit_eq = is_maxsplitter_maxsplit[simplified is_maxsplitter_def]

end


(*
   Authors: Asta Halkjær From, Agnes Moesgård Eschen & Jørgen Villadsen, DTU Compute
*)

theory System_R1 imports System_L1 begin

text \<open>System R from Alfred Whitehead, Bertrand Russell: Principia Mathematica
                                                        (Second Ed. 1925-1927)\<close>

text \<open>Derivations are taken from: On Axiom Systems of Propositional Calculi. V
                                  by Kiyoshi Iseki and Shotaro Tanaka (1965)\<close>

inductive R (\<open>\<RR>\<close>) where
  R_MP: \<open>\<RR> q\<close> if \<open>\<RR> p\<close> and \<open>\<RR> (p \<rightarrow> q)\<close> |
  R_1:  \<open>\<RR> (p \<rightarrow> (q \<rightarrow> p))\<close> |
  R_2:  \<open>\<RR> ((p \<rightarrow> q) \<rightarrow> ((q \<rightarrow> r) \<rightarrow> (p \<rightarrow> r)))\<close> |
  R_3:  \<open>\<RR> ((p \<rightarrow> (q \<rightarrow> r)) \<rightarrow> (q \<rightarrow> (p \<rightarrow> r)))\<close> |
  R_4:  \<open>\<RR> ((\<sim> (\<sim> p)) \<rightarrow> p)\<close> |
  R_5:  \<open>\<RR> ((p \<rightarrow> (\<sim> p)) \<rightarrow> (\<sim> p))\<close> |
  R_6:  \<open>\<RR> ((p \<rightarrow> (\<sim> q)) \<rightarrow> (q \<rightarrow> (\<sim> p)))\<close>

lemma R_7: \<open>\<RR> (q \<rightarrow> (p \<rightarrow> p))\<close>
  using R_1 R_3 R_MP by metis

lemma R_8: \<open>\<RR> (p \<rightarrow> p)\<close>
  using R_1 R_7 R_MP by metis

lemma R_9: \<open>\<RR> (p \<rightarrow> (\<sim> (\<sim> p)))\<close>
  using R_6 R_8 R_MP by metis

lemma R_10: \<open>\<RR> ((q \<rightarrow> r) \<rightarrow> ((p \<rightarrow> q) \<rightarrow> (p \<rightarrow> r)))\<close>
  using R_2 R_3 R_MP by metis

lemma R_11: \<open>\<RR> ((q \<rightarrow> (\<sim> (\<sim> p))) \<rightarrow> (q \<rightarrow> p))\<close>
  using R_4 R_10 R_MP by metis

lemma R_12: \<open>\<RR> (((\<sim> p) \<rightarrow> (\<sim> q)) \<rightarrow> (q \<rightarrow> p))\<close>
  using R_2 R_6 R_11 R_MP by metis

lemma R_13: \<open>\<RR> ((\<sim> p) \<rightarrow> (p \<rightarrow> q))\<close>
  using R_1 R_2 R_12 R_MP by metis

lemma R_14: \<open>\<RR> (p \<rightarrow> ((\<sim> p) \<rightarrow> q))\<close>
  using R_3 R_13 R_MP by metis

lemma R_15: \<open>\<RR> ((p \<rightarrow> (\<sim> (\<sim> q))) \<rightarrow> (p \<rightarrow> q))\<close>
  using R_4 R_10 R_MP by metis (* under substitution this lemma is the same as R_11 *)

lemma R_16: \<open>\<RR> (((\<sim> p) \<rightarrow> q) \<rightarrow> ((\<sim> p) \<rightarrow> (\<sim> (\<sim> q))))\<close>
  using R_9 R_10 R_MP by metis

lemma R_17: \<open>\<RR> (((\<sim> p) \<rightarrow> q) \<rightarrow> ((\<sim> q) \<rightarrow> p))\<close>
  using R_2 R_12 R_16 R_MP by metis

lemma R_18: \<open>\<RR> ((p \<rightarrow> q) \<rightarrow> ((\<sim> (\<sim> p)) \<rightarrow> q))\<close>
  using R_2 R_4 R_MP by metis

lemma R_19: \<open>\<RR> ((((\<sim> (\<sim> p)) \<rightarrow> q) \<rightarrow> r) \<rightarrow> ((p \<rightarrow> q) \<rightarrow> r))\<close>
  using R_2 R_18 R_MP by metis

lemma R_20: \<open>\<RR> ((((q \<rightarrow> r) \<rightarrow> (p \<rightarrow> r)) \<rightarrow> s) \<rightarrow> ((p \<rightarrow> q) \<rightarrow> s))\<close>
  using R_2 R_MP by metis

lemma R_21: \<open>\<RR> ((p \<rightarrow> q) \<rightarrow> (((p \<rightarrow> r) \<rightarrow> s) \<rightarrow> ((q \<rightarrow> r) \<rightarrow> s)))\<close>
  using R_2 R_20 R_MP by metis

lemma R_22: \<open>\<RR> (((p \<rightarrow> r) \<rightarrow> s) \<rightarrow> ((p \<rightarrow> q) \<rightarrow> ((q \<rightarrow> r) \<rightarrow> s)))\<close>
  using R_3 R_21 R_MP by metis

lemma R_23: \<open>\<RR> ((((\<sim> q) \<rightarrow> (\<sim> p)) \<rightarrow> r) \<rightarrow> ((p \<rightarrow> q) \<rightarrow> r))\<close>
  using R_17 R_19 R_22 R_MP by metis

lemma R_24: \<open>\<RR> (((\<sim> p) \<rightarrow> p) \<rightarrow> (\<sim> (\<sim> p)))\<close>
  using R_5 R_23 R_MP by metis

lemma R_25: \<open>\<RR> (((\<sim> p) \<rightarrow> p) \<rightarrow> p)\<close>
  using R_15 R_24 R_MP by metis

theorem R_iff_L1: \<open>\<RR> p \<longleftrightarrow> \<turnstile> p\<close>
proof
  have L1_R_1: \<open>\<turnstile> (p \<rightarrow> (q \<rightarrow> p))\<close> for p q
    using L1_completeness by simp
  have L1_R_2: \<open>\<turnstile> ((p \<rightarrow> q) \<rightarrow> ((q \<rightarrow> r) \<rightarrow> (p \<rightarrow> r)))\<close> for p q r
    using L1_completeness by simp
  have L1_R_3: \<open>\<turnstile> ((p \<rightarrow> (q \<rightarrow> r)) \<rightarrow> (q \<rightarrow> (p \<rightarrow> r)))\<close> for p q r
    using L1_completeness by simp
  have L1_R_4: \<open>\<turnstile> ((\<sim> (\<sim> p)) \<rightarrow> p)\<close> for p
    using L1_completeness by simp
  have L1_R_5: \<open>\<turnstile> ((p \<rightarrow> (\<sim> p)) \<rightarrow> (\<sim> p))\<close> for p
    using L1_completeness by simp
  have L1_R_6: \<open>\<turnstile> ((p \<rightarrow> (\<sim> q)) \<rightarrow> (q \<rightarrow> (\<sim> p)))\<close> for p q
    using L1_completeness by simp
  show \<open>\<turnstile> p\<close> if \<open>\<RR> p\<close>
    using that by (induct) (metis MP, metis L1_R_1, metis L1_R_2, metis L1_R_3,
        metis L1_R_4, metis L1_R_5, metis L1_R_6)
  show \<open>\<RR> p\<close> if \<open>\<turnstile> p\<close>
    using that by (induct) (metis R_MP, metis R_2, metis R_25, metis R_14)
qed

theorem R_soundness: \<open>\<RR> p \<Longrightarrow> I \<Turnstile> p\<close>
  by (induct rule: R.induct) auto

theorem R_completeness: \<open>\<forall>I. (I \<Turnstile> p) \<Longrightarrow> \<RR> p\<close>
  using R_iff_L1 by (simp add: L1_completeness)

section \<open>Soundness and Completeness\<close>

theorem main: \<open>valid p = \<RR> p\<close>
  unfolding valid_def using R_soundness R_completeness by blast

lemmas R1 = R.intros main

end


chapter \<open>Inductive inference of recursive functions\label{c:iirf}\<close>

theory Inductive_Inference_Basics
  imports Standard_Results
begin

text \<open>Inductive inference originates from work by
Solomonoff~\cite{s-ftiip1-64,s-ftiip2-64} and Gold~\cite{g-lil-67,g-lr-65}
and comes in many variations. The common theme is to infer additional
information about objects, such as formal languages or functions, from incomplete
data, such as finitely many words contained in the language or argument-value
pairs of the function. Oftentimes ``additional information'' means complete
information, such that the task becomes identification of the object.

The basic setting in inductive inference of recursive functions is as follows.
Let us denote, for a total function $f$, by $f^n$ the code of the list
$[f(0), ..., f(n)]$. Let $U$ be a set (called \emph{class}) of total
recursive functions, and $\psi$ a binary partial recursive function
(called \emph{hypothesis space}).
A partial recursive function $S$ (called \emph{strategy})
is said to \emph{learn $U$ in the limit with respect to $\psi$} if
for all $f \in U$,
\begin{itemize}
  \item the value $S(f^n)$ is defined for all $n\in\mathbb{N}$,
  \item the sequence $S(f^0), S(f^1), \ldots$ converges to an
    $i\in\mathbb{N}$ with $\psi_i = f$.
\end{itemize}

Both the output $S(f^n)$ of the strategy and its interpretation
as a function $\psi_{S(f^n)}$ are called \emph{hypothesis}. The set
of all classes learnable in the limit by $S$ with respect to $\psi$ is
denoted by $\mathrm{LIM}_\psi(S)$. Moreover we set $\mathrm{LIM}_\psi =
\bigcup_{S\in\mathcal{P}} \mathrm{LIM}_\psi(S)$ and $\mathrm{LIM} =
\bigcup_{\psi\in\mathcal{P}^2} \mathrm{LIM}_\psi$. We call the latter set the
\emph{inference type} $\mathrm{LIM}$.

Many aspects of this setting can be varied. We shall consider:
\begin{itemize}
  \item Intermediate hypotheses: $\psi_{S(f^n)}$ can be required to be total or
    to be in the class $U$, or to coincide with $f$ on arguments up to $n$, or
    a myriad of other conditions or combinations thereof.
  \item Convergence of hypotheses:
  \begin{itemize}
    \item The strategy can be required to output not a sequence but a single
      hypothesis, which must be correct.
    \item The strategy can be required to converge to a \emph{function} rather
      than an index.
  \end{itemize}
\end{itemize}

We formalize five kinds of results (\<open>\<I>\<close> and \<open>\<I>'\<close> stand for
inference types):
\begin{itemize}
  \item Comparison of learning power: results of the form @{prop "\<I>
    \<subset> \<I>'"}, in particular showing that the inclusion is proper
    (Sections~\ref{s:fin_cp}, \ref{s:num_fin}, \ref{s:num_cp},
    \ref{s:num_total}, \ref{s:cons_lim}, \ref{s:lim_bc}, \ref{s:total_cons},
    \ref{s:r1_bc}).
  \item Whether \<open>\<I>\<close> is closed under the subset relation: @{prop "U
    \<in> \<I> \<and> V \<subseteq> U \<Longrightarrow> V \<in> \<I>"}.
  \item Whether \<open>\<I>\<close> is closed under union: @{prop "U \<in> \<I> \<and>
    V \<in> \<I> \<Longrightarrow> U \<union> V \<in> \<I>"} (Section~\ref{s:union}).
  \item Whether every class in \<open>\<I>\<close> can be learned with respect to a
    Gödel numbering as hypothesis space (Section~\ref{s:inference_types}).
  \item Whether every class in \<open>\<I>\<close> can be learned by a \emph{total}
    recursive strategy (Section~\ref{s:lemma_r}).
\end{itemize}

The bulk of this chapter is devoted to the first category of results. Most
results that we are going to formalize have been called ``classical'' by
Jantke and Beick~\cite{jb-cpnii-81}, who compare a large number of inference
types. Another comparison is by Case and Smith~\cite{cs-cicmii-83}. Angluin
and Smith~\cite{as-ii-87} give an overview of various forms of inductive
inference.

All (interesting) proofs herein are based on my lecture notes of the
\emph{Induktive Inferenz} lectures by Rolf Wiehagen from 1999/2000 and
2000/2001 at the University of Kaiserslautern. I have given references to the
original proofs whenever I was able to find them. For the other proofs, as
well as for those that I had to contort beyond recognition, I provide proof
sketches.\<close>

section \<open>Preliminaries\<close>

text \<open>Throughout the chapter, in particular in proof sketches, we use
the following notation.

Let $b\in\mathbb{N}^*$ be a list of numbers. We write $|b|$ for its length
and $b_i$ for the $i$-th element ($i=0,\dots, |b| - 1$). Concatenation of
numbers and lists works in the obvious way; for instance, $jbk$ with
$j,k\in\mathbb{N}$, $b\in\mathbb{N}^*$ refers to the list $jb_0\dots
b_{|b|-1}k$. For $0 \leq i < |b|$, the term $b_{i:=v}$ denotes the list
$b_0\dots b_{i-1}vb_{i+1}\dots b_{|b|-1}$. The notation $b_{<i}$ refers to
$b_0\dots b_{i-1}$ for $0 < i \leq |b|$. Moreover, $v^n$ is short for the
list consisting of $n$ times the value $v \in \mathbb{N}$.

Unary partial functions can be regarded as infinite sequences consisting of
numbers and the symbol~$\uparrow$ denoting undefinedness. We abbreviate the
empty function by $\uparrow^\infty$ and the constant zero function by
$0^\infty$. A function can be written as a list concatenated with a partial
function. For example, $jb\uparrow^\infty$ is the function
\[
x \mapsto \left\{\begin{array}{ll}
  j        & \mbox{if } x = 0,\\
  b_{x-1}  & \mbox{if } 0 < x \leq |b|,\\
  \uparrow & \mbox{otherwise,}
\end{array}\right.
\]
and $jp$, where $p$ is a function, means
\[
x \mapsto \left\{\begin{array}{ll}
  j      & \mbox{if } x = 0,\\
  p(x-1) & \mbox{otherwise.}
\end{array}\right.
\]

A \emph{numbering} is a function $\psi \in \mathcal{P}^2$.\<close>

subsection \<open>The prefixes of a function\<close>

text \<open>A \emph{prefix}, also called \emph{initial segment}, is a list of
initial values of a function.\<close>

definition prefix :: "partial1 \<Rightarrow> nat \<Rightarrow> nat list" where
  "prefix f n \<equiv> map (\<lambda>x. the (f x)) [0..<Suc n]"

lemma length_prefix [simp]: "length (prefix f n) = Suc n"
  unfolding prefix_def by simp

lemma prefix_nth [simp]:
  assumes "k < Suc n"
  shows "prefix f n ! k = the (f k)"
  unfolding prefix_def using assms nth_map_upt[of k "Suc n" 0 "\<lambda>x. the (f x)"] by simp

lemma prefixI:
  assumes "length vs > 0" and "\<And>x. x < length vs \<Longrightarrow> f x \<down>= vs ! x"
  shows "prefix f (length vs - 1) = vs"
  using assms nth_equalityI[of "prefix f (length vs - 1)" vs] by simp

lemma prefixI':
  assumes "length vs = Suc n" and "\<And>x. x < Suc n \<Longrightarrow> f x \<down>= vs ! x"
  shows "prefix f n = vs"
  using assms nth_equalityI[of "prefix f (length vs - 1)" vs] by simp

lemma prefixE:
  assumes "prefix f (length vs - 1) = vs"
    and "f \<in> \<R>"
    and "length vs > 0"
    and "x < length vs"
  shows "f x \<down>= vs ! x"
  using assms length_prefix prefix_nth[of x "length vs - 1" f] by simp

lemma prefix_eqI:
  assumes "\<And>x. x \<le> n \<Longrightarrow> f x = g x"
  shows "prefix f n = prefix g n"
  using assms prefix_def by simp

lemma prefix_0: "prefix f 0 = [the (f 0)]"
  using prefix_def by simp

lemma prefix_Suc: "prefix f (Suc n) = prefix f n @ [the (f (Suc n))]"
  unfolding prefix_def by simp

lemma take_prefix:
  assumes "f \<in> \<R>" and "k \<le> n"
  shows "prefix f k = take (Suc k) (prefix f n)"
proof -
  let ?vs = "take (Suc k) (prefix f n)"
  have "length ?vs = Suc k"
    using assms(2) by simp
  then have "\<And>x. x < length ?vs \<Longrightarrow> f x \<down>= ?vs ! x"
    using assms by auto
  then show ?thesis
    using prefixI[where ?vs="?vs"] \<open>length ?vs = Suc k\<close> by simp
qed

text \<open>Strategies receive prefixes in the form of encoded lists. The
term ``prefix'' refers to both encoded and unencoded lists. We use the
notation @{text "f \<triangleright> n"} for the prefix $f^n$.\<close>

definition init :: "partial1 \<Rightarrow> nat \<Rightarrow> nat" (infix "\<triangleright>" 110) where
  "f \<triangleright> n \<equiv> list_encode (prefix f n)"

lemma init_neq_zero: "f \<triangleright> n \<noteq> 0"
  unfolding init_def prefix_def using list_encode_0 by fastforce

lemma init_prefixE [elim]: "prefix f n = prefix g n \<Longrightarrow> f \<triangleright> n = g \<triangleright> n"
  unfolding init_def by simp

lemma init_eqI:
  assumes "\<And>x. x \<le> n \<Longrightarrow> f x = g x"
  shows "f \<triangleright> n = g \<triangleright> n"
  unfolding init_def using prefix_eqI[OF assms] by simp

lemma initI:
  assumes "e_length e > 0" and "\<And>x. x < e_length e \<Longrightarrow> f x \<down>= e_nth e x"
  shows "f \<triangleright> (e_length e - 1) = e"
  unfolding init_def using assms prefixI by simp

lemma initI':
  assumes "e_length e = Suc n" and "\<And>x. x <  Suc n \<Longrightarrow> f x \<down>= e_nth e x"
  shows "f \<triangleright> n = e"
  unfolding init_def using assms prefixI' by simp

lemma init_iff_list_eq_upto:
  assumes "f \<in> \<R>" and "e_length vs > 0"
  shows "(\<forall>x<e_length vs. f x \<down>= e_nth vs x) \<longleftrightarrow> prefix f (e_length vs - 1) = list_decode vs"
  using prefixI[OF assms(2)] prefixE[OF _ assms] by auto

lemma length_init [simp]: "e_length (f \<triangleright> n) = Suc n"
  unfolding init_def by simp

lemma init_Suc_snoc: "f \<triangleright> (Suc n) = e_snoc (f \<triangleright> n) (the (f (Suc n)))"
  unfolding init_def by (simp add: prefix_Suc)

lemma nth_init: "i < Suc n \<Longrightarrow> e_nth (f \<triangleright> n) i = the (f i)"
  unfolding init_def using prefix_nth by auto

lemma hd_init [simp]: "e_hd (f \<triangleright> n) = the (f 0)"
  unfolding init_def using init_neq_zero by (simp add: e_hd_nth0)

lemma list_decode_init [simp]: "list_decode (f \<triangleright> n) = prefix f n"
  unfolding init_def by simp

lemma init_eq_iff_eq_upto:
  assumes "g \<in> \<R>" and "f \<in> \<R>"
  shows "(\<forall>j<Suc n. g j = f j) \<longleftrightarrow> g \<triangleright> n = f \<triangleright> n"
  using assms initI' init_iff_list_eq_upto length_init list_decode_init
  by (metis diff_Suc_1 zero_less_Suc)

definition is_init_of :: "nat \<Rightarrow> partial1 \<Rightarrow> bool" where
  "is_init_of t f \<equiv> \<forall>i<e_length t. f i \<down>= e_nth t i"

lemma not_initial_imp_not_eq:
  assumes "\<And>x. x < Suc n \<Longrightarrow> f x \<down>" and "\<not> (is_init_of (f \<triangleright> n) g)"
  shows "f \<noteq> g"
  using is_init_of_def assms by auto

lemma all_init_eq_imp_fun_eq:
  assumes "f \<in> \<R>" and "g \<in> \<R>" and "\<And>n. f \<triangleright> n = g \<triangleright> n"
  shows "f = g"
proof
  fix n
  from assms have "prefix f n = prefix g n"
    by (metis init_def list_decode_encode)
  then have "the (f n) = the (g n)"
    unfolding init_def prefix_def by simp
  then show "f n = g n"
    using assms(1,2) by (meson R1_imp_total1 option.expand total1E)
qed

corollary neq_fun_neq_init:
  assumes "f \<in> \<R>" and "g \<in> \<R>" and "f \<noteq> g"
  shows "\<exists>n. f \<triangleright> n \<noteq> g \<triangleright> n"
  using assms all_init_eq_imp_fun_eq by auto

lemma eq_init_forall_le:
  assumes "f \<triangleright> n = g \<triangleright> n" and "m \<le> n"
  shows "f \<triangleright> m = g \<triangleright> m"
proof -
  from assms(1) have "prefix f n = prefix g n"
    by (metis init_def list_decode_encode)
  then have "the (f k) = the (g k)" if "k \<le> n" for k
    using prefix_def that by auto
  then have "the (f k) = the (g k)" if "k \<le> m" for k
    using assms(2) that by simp
  then have "prefix f m = prefix g m"
    using prefix_def by simp
  then show ?thesis by (simp add: init_def)
qed

corollary neq_init_forall_ge:
  assumes "f \<triangleright> n \<noteq> g \<triangleright> n" and "m \<ge> n"
  shows "f \<triangleright> m \<noteq> g \<triangleright> m"
  using eq_init_forall_le assms by blast

lemma e_take_init:
  assumes "f \<in> \<R>" and "k < Suc n"
  shows "e_take (Suc k) (f \<triangleright> n) = f \<triangleright> k"
  using assms take_prefix by (simp add: init_def less_Suc_eq_le)

lemma init_butlast_init:
  assumes "total1 f" and "f \<triangleright> n = e" and "n > 0"
  shows "f \<triangleright> (n - 1) = e_butlast e"
proof -
  let ?e = "e_butlast e"
  have "e_length e = Suc n"
    using assms(2) by auto
  then have len: "e_length ?e = n"
    by simp
  have "f \<triangleright> (e_length ?e - 1) = ?e"
  proof (rule initI)
    show "0 < e_length ?e"
      using assms(3) len by simp
    have "\<And>x. x < e_length e \<Longrightarrow> f x \<down>= e_nth e x"
      using assms(1,2) total1_def \<open>e_length e = Suc n\<close> by auto
    then show "\<And>x. x < e_length ?e \<Longrightarrow> f x \<down>= e_nth ?e x"
      by (simp add: butlast_conv_take)
  qed
  with len show ?thesis by simp
qed

text \<open>Some definitions make use of recursive predicates, that is,
$01$-valued functions.\<close>

definition RPred1 :: "partial1 set" ("\<R>\<^sub>0\<^sub>1") where
  "\<R>\<^sub>0\<^sub>1 \<equiv> {f. f \<in> \<R> \<and> (\<forall>x. f x \<down>= 0 \<or> f x \<down>= 1)}"

lemma RPred1_subseteq_R1: "\<R>\<^sub>0\<^sub>1 \<subseteq> \<R>"
  unfolding RPred1_def by auto

lemma const0_in_RPred1: "(\<lambda>_. Some 0) \<in> \<R>\<^sub>0\<^sub>1"
  using RPred1_def const_in_Prim1 by fast

lemma RPred1_altdef: "\<R>\<^sub>0\<^sub>1 = {f. f \<in> \<R> \<and> (\<forall>x. the (f x) \<le> 1)}"
  (is "\<R>\<^sub>0\<^sub>1 = ?S")
proof
  show "\<R>\<^sub>0\<^sub>1 \<subseteq> ?S"
  proof
    fix f
    assume f: "f \<in> \<R>\<^sub>0\<^sub>1"
    with RPred1_def have "f \<in> \<R>" by auto
    from f have "\<forall>x. f x \<down>= 0 \<or> f x \<down>= 1"
      by (simp add: RPred1_def)
    then have "\<forall>x. the (f x) \<le> 1"
      by (metis eq_refl less_Suc_eq_le zero_less_Suc option.sel)
    with \<open>f \<in> \<R>\<close> show "f \<in> ?S" by simp
  qed
  show "?S \<subseteq> \<R>\<^sub>0\<^sub>1"
  proof
    fix f
    assume f: "f \<in> ?S"
    then have "f \<in> \<R>" by simp
    then have total: "\<And>x. f x \<down>" by auto
    from f have "\<forall>x. the (f x) = 0 \<or> the (f x) = 1"
      by (simp add: le_eq_less_or_eq)
    with total have "\<forall>x. f x \<down>= 0 \<or> f x \<down>= 1"
      by (metis option.collapse)
    then show "f \<in> \<R>\<^sub>0\<^sub>1"
      using \<open>f \<in> \<R>\<close> RPred1_def by auto
  qed
qed

subsection \<open>NUM\<close>

text \<open>A class of recursive functions is in NUM if it can be
embedded in a total numbering. Thus, for learning such classes there is
always a total hypothesis space available.\<close>

definition NUM :: "partial1 set set" where
  "NUM \<equiv> {U. \<exists>\<psi>\<in>\<R>\<^sup>2. \<forall>f\<in>U. \<exists>i. \<psi> i = f}"

definition NUM_wrt :: "partial2 \<Rightarrow> partial1 set set" where
  "\<psi> \<in> \<R>\<^sup>2 \<Longrightarrow> NUM_wrt \<psi> \<equiv> {U. \<forall>f\<in>U. \<exists>i. \<psi> i = f}"

lemma NUM_I [intro]:
  assumes "\<psi> \<in> \<R>\<^sup>2" and "\<And>f. f \<in> U \<Longrightarrow> \<exists>i. \<psi> i = f"
  shows "U \<in> NUM"
  using assms NUM_def by blast

lemma NUM_E [dest]:
  assumes "U \<in> NUM"
  shows "U \<subseteq> \<R>"
    and "\<exists>\<psi>\<in>\<R>\<^sup>2. \<forall>f\<in>U. \<exists>i. \<psi> i = f"
  using NUM_def assms by (force, auto)

lemma NUM_closed_subseteq:
  assumes "U \<in> NUM" and "V \<subseteq> U"
  shows "V \<in> NUM"
  using assms subset_eq[of V U] NUM_I by auto

text \<open>This is the classical diagonalization proof showing that there is
no total numbering containing all total recursive functions.\<close>

lemma R1_not_in_NUM: "\<R> \<notin> NUM"
proof
  assume "\<R> \<in> NUM"
  then obtain \<psi> where num: "\<psi> \<in> \<R>\<^sup>2" "\<forall>f\<in>\<R>. \<exists>i. \<psi> i = f"
    by auto
  then obtain psi where psi: "recfn 2 psi" "total psi" "eval psi [i, x] = \<psi> i x" for i x
    by auto
  define d where "d = Cn 1 S [Cn 1 psi [Id 1 0, Id 1 0]]"
  then have "recfn 1 d"
    using psi(1) by simp
  moreover have d: "eval d [x] \<down>= Suc (the (\<psi> x x))" for x
    unfolding d_def using num psi by simp
  ultimately have "(\<lambda>x. eval d [x]) \<in> \<R>"
    using R1I by blast
  then obtain i where "\<psi> i = (\<lambda>x. eval d [x])"
    using num(2) by auto
  then have "\<psi> i i = eval d [i]" by simp
  with d have "\<psi> i i \<down>= Suc (the (\<psi> i i))" by simp
  then show False
    using option.sel[of "Suc (the (\<psi> i i))"] by simp
qed

text \<open>A hypothesis space that contains a function for every prefix will
come in handy. The following is a total numbering with this property.\<close>

definition "r_prenum \<equiv>
  Cn 2 r_ifless [Id 2 1, Cn 2 r_length [Id 2 0], Cn 2 r_nth [Id 2 0, Id 2 1], r_constn 1 0]"

lemma r_prenum_prim [simp]: "prim_recfn 2 r_prenum"
  unfolding r_prenum_def by simp_all

definition prenum :: partial2 where
  "prenum e x \<equiv> Some (if x < e_length e then e_nth e x else 0)"

lemma prenum_in_R2: "prenum \<in> \<R>\<^sup>2"
  using prenum_def Prim2I[OF r_prenum_prim, of prenum] by simp

lemma prenum [simp]: "prenum e x \<down>= (if x < e_length e then e_nth e x else 0)"
  unfolding prenum_def ..

text \<open>Prepending a list of numbers to a function:\<close>

definition prepend :: "nat list \<Rightarrow> partial1 \<Rightarrow> partial1" (infixr "\<odot>" 64) where
  "vs \<odot> f \<equiv> \<lambda>x. if x < length vs then Some (vs ! x) else f (x - length vs)"

lemma prepend [simp]:
  "(vs \<odot> f) x = (if x < length vs then Some (vs ! x) else f (x - length vs))"
  unfolding prepend_def ..

lemma prepend_total: "total1 f \<Longrightarrow> total1 (vs \<odot> f)"
  unfolding total1_def by simp

lemma prepend_at_less:
  assumes "n < length vs"
  shows "(vs \<odot> f) n \<down>= vs ! n"
  using assms by simp

lemma prepend_at_ge:
  assumes "n \<ge> length vs"
  shows "(vs \<odot> f) n = f (n - length vs)"
  using assms by simp

lemma prefix_prepend_less:
  assumes "n < length vs"
  shows "prefix (vs \<odot> f) n = take (Suc n) vs"
  using assms length_prefix by (intro nth_equalityI) simp_all

lemma prepend_eqI:
  assumes "\<And>x. x < length vs \<Longrightarrow> g x \<down>= vs ! x"
    and "\<And>x. g (length vs + x) = f x"
  shows "g = vs \<odot> f"
proof
  fix x
  show "g x = (vs \<odot> f) x"
  proof (cases "x < length vs")
    case True
    then show ?thesis using assms by simp
  next
    case False
    then show ?thesis
      using assms prepend by (metis add_diff_inverse_nat)
  qed
qed

fun r_prepend :: "nat list \<Rightarrow> recf \<Rightarrow> recf" where
  "r_prepend [] r = r"
| "r_prepend (v # vs) r =
     Cn 1 (r_lifz (r_const v) (Cn 1 (r_prepend vs r) [r_dec])) [Id 1 0, Id 1 0]"

lemma r_prepend_recfn:
  assumes "recfn 1 r"
  shows "recfn 1 (r_prepend vs r)"
  using assms by (induction vs) simp_all

lemma r_prepend:
  assumes "recfn 1 r"
  shows "eval (r_prepend vs r) [x] =
    (if x < length vs then Some (vs ! x) else eval r [x - length vs])"
proof (induction vs arbitrary: x)
  case Nil
  then show ?case using assms by simp
next
  case (Cons v vs)
  show ?case
    using assms Cons by (cases "x = 0") (auto simp add: r_prepend_recfn)
qed

lemma r_prepend_total:
  assumes "recfn 1 r" and "total r"
  shows "eval (r_prepend vs r) [x] \<down>=
    (if x < length vs then vs ! x else the (eval r [x - length vs]))"
proof (induction vs arbitrary: x)
  case Nil
  then show ?case using assms by simp
next
  case (Cons v vs)
  show ?case
    using assms Cons by (cases "x = 0") (auto simp add: r_prepend_recfn)
qed

lemma prepend_in_P1:
  assumes "f \<in> \<P>"
  shows "vs \<odot> f \<in> \<P>"
proof -
  obtain r where r: "recfn 1 r"  "\<And>x. eval r [x] = f x"
    using assms by auto
  moreover have "recfn 1 (r_prepend vs r)"
    using r r_prepend_recfn by simp
  moreover have "eval (r_prepend vs r) [x] = (vs \<odot> f) x" for x
    using r r_prepend by simp
  ultimately show ?thesis by blast
qed

lemma prepend_in_R1:
  assumes "f \<in> \<R>"
  shows "vs \<odot> f \<in> \<R>"
proof -
  obtain r where r: "recfn 1 r" "total r" "\<And>x. eval r [x] = f x"
    using assms by auto
  then have "total1 f"
    using R1_imp_total1[OF assms] by simp
  have "total (r_prepend vs r)"
    using r r_prepend_total r_prepend_recfn totalI1[of "r_prepend vs r"] by simp
  with r have "total (r_prepend vs r)" by simp
  moreover have "recfn 1 (r_prepend vs r)"
    using r r_prepend_recfn by simp
  moreover have "eval (r_prepend vs r) [x] = (vs \<odot> f) x" for x
    using r r_prepend \<open>total1 f\<close> total1E by simp
  ultimately show ?thesis by auto
qed

lemma prepend_associative: "(us @ vs) \<odot> f = us \<odot> vs \<odot> f" (is "?lhs = ?rhs")
proof
  fix x
  consider
      "x < length us"
    | "x \<ge> length us \<and> x < length (us @ vs)"
    | "x \<ge> length (us @ vs)"
    by linarith
  then show "?lhs x = ?rhs x"
  proof (cases)
    case 1
    then show ?thesis
      by (metis le_add1 length_append less_le_trans nth_append prepend_at_less)
  next
    case 2
    then show ?thesis
      by (smt add_diff_inverse_nat add_less_cancel_left length_append nth_append prepend)
  next
    case 3
    then show ?thesis
      using prepend_at_ge by auto
  qed
qed

abbreviation constant_divergent :: partial1 ("\<up>\<^sup>\<infinity>") where
  "\<up>\<^sup>\<infinity> \<equiv> \<lambda>_. None"

abbreviation constant_zero :: partial1 ("0\<^sup>\<infinity>") where
  "0\<^sup>\<infinity> \<equiv> \<lambda>_. Some 0"

lemma almost0_in_R1: "vs \<odot> 0\<^sup>\<infinity> \<in> \<R>"
  using RPred1_subseteq_R1 const0_in_RPred1 prepend_in_R1 by auto

text \<open>The class $U_0$ of all total recursive functions that are almost
everywhere zero will be used several times to construct
(counter-)examples.\<close>

definition U0 :: "partial1 set" ("U\<^sub>0") where
  "U\<^sub>0 \<equiv> {vs \<odot> 0\<^sup>\<infinity> |vs. vs \<in> UNIV}"

text \<open>The class @{term U0} contains exactly the functions in the
numbering @{term prenum}.\<close>

lemma U0_altdef: "U\<^sub>0 = {prenum e| e. e \<in> UNIV}" (is "U\<^sub>0 = ?W")
proof
  show "U\<^sub>0 \<subseteq> ?W"
  proof
    fix f
    assume "f \<in> U\<^sub>0"
    with U0_def obtain vs where "f = vs \<odot> 0\<^sup>\<infinity>"
      by auto
    then have "f = prenum (list_encode vs)"
      using prenum_encode by auto
    then show "f \<in> ?W" by auto
  qed
  show "?W \<subseteq> U\<^sub>0"
    unfolding U0_def by fastforce
qed

lemma U0_in_NUM: "U\<^sub>0 \<in> NUM"
  using prenum_in_R2 U0_altdef by (intro NUM_I[of prenum]; force)

text \<open>Every almost-zero function can be represented by $v0^\infty$ for
a list $v$ not ending in zero.\<close>

lemma almost0_canonical:
  assumes "f = vs \<odot> 0\<^sup>\<infinity>" and "f \<noteq> 0\<^sup>\<infinity>"
  obtains ws where "length ws > 0" and "last ws \<noteq> 0" and "f = ws \<odot> 0\<^sup>\<infinity>"
proof -
  let ?P = "\<lambda>k. k < length vs \<and> vs ! k \<noteq> 0"
  from assms have "vs \<noteq> []"
    by auto
  then have ex: "\<exists>k<length vs. vs ! k \<noteq> 0"
    using assms by auto
  define m where "m = Greatest ?P"
  moreover have le: "\<forall>y. ?P y \<longrightarrow> y \<le> length vs"
    by simp
  ultimately have "?P m"
    using ex GreatestI_ex_nat[of ?P "length vs"] by simp
  have not_gr: "\<not> ?P k" if "k > m" for k
    using Greatest_le_nat[of ?P _ "length vs"] m_def ex le not_less that by blast
  let ?ws = "take (Suc m) vs"
  have "vs \<odot> 0\<^sup>\<infinity> = ?ws \<odot> 0\<^sup>\<infinity>"
  proof
    fix x
    show "(vs \<odot> 0\<^sup>\<infinity>) x = (?ws \<odot> 0\<^sup>\<infinity>) x"
    proof (cases "x < Suc m")
      case True
      then show ?thesis using \<open>?P m\<close> by simp
    next
      case False
      moreover from this have "(?ws \<odot> 0\<^sup>\<infinity>) x \<down>= 0"
        by simp
      ultimately show ?thesis
        using not_gr by (cases "x < length vs") simp_all
    qed
  qed
  then have "f = ?ws \<odot> 0\<^sup>\<infinity>"
    using assms(1) by simp
  moreover have "length ?ws > 0"
    by (simp add: \<open>vs \<noteq> []\<close>)
  moreover have "last ?ws \<noteq> 0"
    by (simp add: \<open>?P m\<close> take_Suc_conv_app_nth)
  ultimately show ?thesis using that by blast
qed

section \<open>Types of inference\label{s:inference_types}\<close>

text \<open>This section introduces all inference types that we are going to
consider together with some of their simple properties. All these inference
types share the following condition, which essentially says that everything
must be computable:\<close>

abbreviation environment :: "partial2 \<Rightarrow> (partial1 set) \<Rightarrow> partial1 \<Rightarrow> bool" where
  "environment \<psi> U s \<equiv> \<psi> \<in> \<P>\<^sup>2 \<and> U \<subseteq> \<R> \<and> s \<in> \<P> \<and> (\<forall>f\<in>U. \<forall>n. s (f \<triangleright> n) \<down>)"

subsection \<open>LIM: Learning in the limit\<close>

text \<open>A strategy $S$ learns a class $U$ in the limit with respect to a
hypothesis space @{term "\<psi> \<in> \<P>\<^sup>2"} if for all $f\in U$, the
sequence $(S(f^n))_{n\in\mathbb{N}}$ converges to an $i$ with $\psi_i = f$.
Convergence for a sequence of natural numbers means that almost all elements
are the same. We express this with the following notation.\<close>

abbreviation Almost_All :: "(nat \<Rightarrow> bool) \<Rightarrow> bool" (binder "\<forall>\<^sup>\<infinity>" 10) where
  "\<forall>\<^sup>\<infinity>n. P n \<equiv> \<exists>n\<^sub>0. \<forall>n\<ge>n\<^sub>0. P n"

definition learn_lim :: "partial2 \<Rightarrow> (partial1 set) \<Rightarrow> partial1 \<Rightarrow> bool" where
  "learn_lim \<psi> U s \<equiv>
     environment \<psi> U s \<and>
     (\<forall>f\<in>U. \<exists>i. \<psi> i = f \<and> (\<forall>\<^sup>\<infinity>n. s (f \<triangleright> n) \<down>= i))"

lemma learn_limE:
  assumes "learn_lim \<psi> U s"
  shows "environment \<psi> U s"
    and "\<And>f. f \<in> U \<Longrightarrow> \<exists>i. \<psi> i = f \<and> (\<forall>\<^sup>\<infinity>n. s (f \<triangleright> n) \<down>= i)"
  using assms learn_lim_def by auto

lemma learn_limI:
  assumes "environment \<psi> U s"
    and "\<And>f. f \<in> U \<Longrightarrow> \<exists>i. \<psi> i = f \<and> (\<forall>\<^sup>\<infinity>n. s (f \<triangleright> n) \<down>= i)"
  shows "learn_lim \<psi> U s"
  using assms learn_lim_def by auto

definition LIM_wrt :: "partial2 \<Rightarrow> partial1 set set" where
  "LIM_wrt \<psi> \<equiv> {U. \<exists>s. learn_lim \<psi> U s}"

definition Lim :: "partial1 set set" ("LIM") where
  "LIM \<equiv> {U. \<exists>\<psi> s. learn_lim \<psi> U s}"

text \<open>LIM is closed under the the subset relation.\<close>

lemma learn_lim_closed_subseteq:
  assumes "learn_lim \<psi> U s" and "V \<subseteq> U"
  shows "learn_lim \<psi> V s"
  using assms learn_lim_def by auto

corollary LIM_closed_subseteq:
  assumes "U \<in> LIM" and "V \<subseteq> U"
  shows "V \<in> LIM"
  using assms learn_lim_closed_subseteq by (smt Lim_def mem_Collect_eq)

text \<open>Changing the hypothesis infinitely often precludes learning in
the limit.\<close>

lemma infinite_hyp_changes_not_Lim:
  assumes "f \<in> U" and "\<forall>n. \<exists>m\<^sub>1>n. \<exists>m\<^sub>2>n. s (f \<triangleright> m\<^sub>1) \<noteq> s (f \<triangleright> m\<^sub>2)"
  shows "\<not> learn_lim \<psi> U s"
  using assms learn_lim_def by (metis less_imp_le)

lemma always_hyp_change_not_Lim:
  assumes "\<And>x. s (f \<triangleright> (Suc x)) \<noteq> s (f \<triangleright> x)"
  shows "\<not> learn_lim \<psi> {f} s"
  using assms learn_limE by (metis le_SucI order_refl singletonI)

text \<open>Guessing a wrong hypothesis infinitely often precludes learning
in the limit.\<close>

lemma infinite_hyp_wrong_not_Lim:
  assumes "f \<in> U" and "\<forall>n. \<exists>m>n. \<psi> (the (s (f \<triangleright> m))) \<noteq> f"
  shows "\<not> learn_lim \<psi> U s"
  using assms learn_limE by (metis less_imp_le option.sel)

text \<open>Converging to the same hypothesis on two functions precludes
learning in the limit.\<close>

lemma same_hyp_for_two_not_Lim:
  assumes "f\<^sub>1 \<in> U"
    and "f\<^sub>2 \<in> U"
    and "f\<^sub>1 \<noteq> f\<^sub>2"
    and "\<forall>n\<ge>n\<^sub>1. s (f\<^sub>1 \<triangleright> n) = h"
    and "\<forall>n\<ge>n\<^sub>2. s (f\<^sub>2 \<triangleright> n) = h"
  shows "\<not> learn_lim \<psi> U s"
  using assms learn_limE by (metis le_cases option.sel)

text \<open>Every class that can be learned in the limit can be learned in
the limit with respect to any Gödel numbering. We prove a generalization in
which hypotheses may have to satisfy an extra condition, so we can re-use it
for other inference types later.\<close>

lemma learn_lim_extra_wrt_goedel:
  fixes extra :: "(partial1 set) \<Rightarrow> partial1 \<Rightarrow> nat \<Rightarrow> partial1 \<Rightarrow> bool"
  assumes "goedel_numbering \<chi>"
    and "learn_lim \<psi> U s"
    and "\<And>f n. f \<in> U \<Longrightarrow> extra U f n (\<psi> (the (s (f \<triangleright> n))))"
  shows "\<exists>t. learn_lim \<chi> U t \<and> (\<forall>f\<in>U. \<forall>n. extra U f n (\<chi> (the (t (f \<triangleright> n)))))"
proof -
  have env: "environment \<psi> U s"
    and lim: "learn_lim \<psi> U s"
    and extra: "\<forall>f\<in>U. \<forall>n. extra U f n (\<psi> (the (s (f \<triangleright> n))))"
    using assms learn_limE by auto
  obtain c where c: "c \<in> \<R>" "\<forall>i. \<psi> i = \<chi> (the (c i))"
    using env goedel_numberingE[OF assms(1), of \<psi>] by auto
  define t where "t \<equiv>
    (\<lambda>x. if s x \<down> \<and> c (the (s x)) \<down> then Some (the (c (the (s x)))) else None)"
  have "t \<in> \<P>"
    unfolding t_def using env c concat_P1_P1[of c s] by auto
  have "t x = (if s x \<down> then Some (the (c (the (s x)))) else None)" for x
    using t_def c(1) R1_imp_total1 by auto
  then have t: "t (f \<triangleright> n) \<down>= the (c (the (s (f \<triangleright> n))))" if "f \<in> U" for f n
    using lim learn_limE that by simp
  have "learn_lim \<chi> U t"
  proof (rule learn_limI)
    show "environment \<chi> U t"
      using t by (simp add: \<open>t \<in> \<P>\<close> env goedel_numbering_P2[OF assms(1)])
    show "\<exists>i. \<chi> i = f \<and> (\<forall>\<^sup>\<infinity>n. t (f \<triangleright> n) \<down>= i)" if "f \<in> U" for f
    proof -
      from lim learn_limE(2) obtain i n\<^sub>0 where
        i: "\<psi> i = f \<and> (\<forall>n\<ge>n\<^sub>0. s (f \<triangleright> n) \<down>= i)"
        using \<open>f \<in> U\<close> by blast
      let ?j = "the (c i)"
      have "\<chi> ?j = f"
        using c(2) i by simp
      moreover have "t (f \<triangleright> n) \<down>= ?j" if "n \<ge> n\<^sub>0" for n
        by (simp add: \<open>f \<in> U\<close> i t that)
      ultimately show ?thesis by auto
    qed
  qed
  moreover have "extra U f n (\<chi> (the (t (f \<triangleright> n))))" if "f \<in> U" for f n
  proof -
    from t have "the (t (f \<triangleright> n)) = the (c (the (s (f \<triangleright> n))))"
      by (simp add: that)
    then have "\<chi> (the (t (f \<triangleright> n))) = \<psi> (the (s (f \<triangleright> n)))"
      using c(2) by simp
    with extra show ?thesis using that by simp
  qed
  ultimately show ?thesis by auto
qed

lemma learn_lim_wrt_goedel:
  assumes "goedel_numbering \<chi>" and "learn_lim \<psi> U s"
  shows "\<exists>t. learn_lim \<chi> U t"
  using assms learn_lim_extra_wrt_goedel[where ?extra="\<lambda>U f n h. True"]
  by simp

lemma LIM_wrt_phi_eq_Lim: "LIM_wrt \<phi> = LIM"
  using LIM_wrt_def Lim_def learn_lim_wrt_goedel[OF goedel_numbering_phi]
  by blast

subsection \<open>BC: Behaviorally correct learning in the limit\<close>

text \<open>Behaviorally correct learning in the limit relaxes LIM by
requiring that the strategy almost always output an index for the target
function, but not necessarily the same index. In other words convergence of
$(S(f^n))_{n\in\mathbb{N}}$ is replaced by convergence of
$(\psi_{S(f^n)})_{n\in\mathbb{N}}$.\<close>

definition learn_bc :: "partial2 \<Rightarrow> (partial1 set) \<Rightarrow> partial1 \<Rightarrow> bool" where
  "learn_bc \<psi> U s \<equiv>
     environment \<psi> U s \<and>
     (\<forall>f\<in>U. \<forall>\<^sup>\<infinity>n. \<psi> (the (s (f \<triangleright> n))) = f)"

lemma learn_bcE:
  assumes "learn_bc \<psi> U s"
  shows "environment \<psi> U s"
    and "\<And>f. f \<in> U \<Longrightarrow> \<forall>\<^sup>\<infinity>n. \<psi> (the (s (f \<triangleright> n))) = f"
  using assms learn_bc_def by auto

lemma learn_bcI:
  assumes "environment \<psi> U s"
    and "\<And>f. f \<in> U \<Longrightarrow> \<forall>\<^sup>\<infinity>n. \<psi> (the (s (f \<triangleright> n))) = f"
  shows "learn_bc \<psi> U s"
  using assms learn_bc_def by auto

definition BC_wrt :: "partial2 \<Rightarrow> partial1 set set" where
  "BC_wrt \<psi> \<equiv> {U. \<exists>s. learn_bc \<psi> U s}"

definition BC :: "partial1 set set" where
  "BC \<equiv> {U. \<exists>\<psi> s. learn_bc \<psi> U s}"

text \<open>BC is a superset of LIM and closed under the subset relation.\<close>

lemma learn_lim_imp_BC: "learn_lim \<psi> U s \<Longrightarrow> learn_bc \<psi> U s"
  using learn_limE learn_bcI[of \<psi> U s] by fastforce

lemma Lim_subseteq_BC: "LIM \<subseteq> BC"
  using learn_lim_imp_BC Lim_def BC_def by blast

lemma learn_bc_closed_subseteq:
  assumes "learn_bc \<psi> U s" and "V \<subseteq> U"
  shows "learn_bc \<psi> V s"
  using assms learn_bc_def by auto

corollary BC_closed_subseteq:
  assumes "U \<in> BC" and "V \<subseteq> U"
  shows "V \<in> BC"
  using assms by (smt BC_def learn_bc_closed_subseteq mem_Collect_eq)

text \<open>Just like with LIM, guessing a wrong hypothesis infinitely often
precludes BC-style learning.\<close>

lemma infinite_hyp_wrong_not_BC:
  assumes "f \<in> U" and "\<forall>n. \<exists>m>n. \<psi> (the (s (f \<triangleright> m))) \<noteq> f"
  shows "\<not> learn_bc \<psi> U s"
proof
  assume "learn_bc \<psi> U s"
  then obtain n\<^sub>0 where "\<forall>n\<ge>n\<^sub>0. \<psi> (the (s (f \<triangleright> n))) = f"
    using learn_bcE assms(1) by metis
  with assms(2) show False using less_imp_le by blast
qed

text \<open>The proof that Gödel numberings suffice as hypothesis spaces for
BC is similar to the one for @{thm[source] learn_lim_extra_wrt_goedel}. We do
not need the @{term extra} part for BC, but we get it for free.\<close>

lemma learn_bc_extra_wrt_goedel:
  fixes extra :: "(partial1 set) \<Rightarrow> partial1 \<Rightarrow> nat \<Rightarrow> partial1 \<Rightarrow> bool"
  assumes "goedel_numbering \<chi>"
    and "learn_bc \<psi> U s"
    and "\<And>f n. f \<in> U \<Longrightarrow> extra U f n (\<psi> (the (s (f \<triangleright> n))))"
  shows "\<exists>t. learn_bc \<chi> U t \<and> (\<forall>f\<in>U. \<forall>n. extra U f n (\<chi> (the (t (f \<triangleright> n)))))"
proof -
  have env: "environment \<psi> U s"
    and lim: "learn_bc \<psi> U s"
    and extra: "\<forall>f\<in>U. \<forall>n. extra U f n (\<psi> (the (s (f \<triangleright> n))))"
    using assms learn_bc_def by auto
  obtain c where c: "c \<in> \<R>" "\<forall>i. \<psi> i = \<chi> (the (c i))"
    using env goedel_numberingE[OF assms(1), of \<psi>] by auto
  define t where
    "t = (\<lambda>x. if s x \<down> \<and> c (the (s x)) \<down> then Some (the (c (the (s x)))) else None)"
  have "t \<in> \<P>"
    unfolding t_def using env c concat_P1_P1[of c s] by auto
  have "t x = (if s x \<down> then Some (the (c (the (s x)))) else None)" for x
    using t_def c(1) R1_imp_total1 by auto
  then have t: "t (f \<triangleright> n) \<down>= the (c (the (s (f \<triangleright> n))))" if "f \<in> U" for f n
    using lim learn_bcE(1) that by simp
  have "learn_bc \<chi> U t"
  proof (rule learn_bcI)
    show "environment \<chi> U t"
      using t by (simp add: \<open>t \<in> \<P>\<close> env goedel_numbering_P2[OF assms(1)])
    show "\<forall>\<^sup>\<infinity>n. \<chi> (the (t (f \<triangleright> n))) = f" if "f \<in> U" for f
    proof -
      obtain n\<^sub>0 where "\<forall>n\<ge>n\<^sub>0. \<psi> (the (s (f \<triangleright> n))) = f"
        using lim learn_bcE(2) \<open>f \<in> U\<close> by blast
      then show ?thesis using that t c(2) by auto
    qed
  qed
  moreover have "extra U f n (\<chi> (the (t (f \<triangleright> n))))" if "f \<in> U" for f n
  proof -
    from t have "the (t (f \<triangleright> n)) = the (c (the (s (f \<triangleright> n))))"
      by (simp add: that)
    then have "\<chi> (the (t (f \<triangleright> n))) = \<psi> (the (s (f \<triangleright> n)))"
      using c(2) by simp
    with extra show ?thesis using that by simp
  qed
  ultimately show ?thesis by auto
qed

corollary learn_bc_wrt_goedel:
  assumes "goedel_numbering \<chi>" and "learn_bc \<psi> U s"
  shows "\<exists>t. learn_bc \<chi> U t"
  using assms learn_bc_extra_wrt_goedel[where ?extra="\<lambda>_ _ _ _. True"] by simp

corollary BC_wrt_phi_eq_BC: "BC_wrt \<phi> = BC"
  using learn_bc_wrt_goedel goedel_numbering_phi BC_def BC_wrt_def by blast

subsection \<open>CONS: Learning in the limit with consistent hypotheses\<close>

text \<open>A hypothesis is \emph{consistent} if it matches all values in the
prefix given to the strategy. Consistent learning in the limit requires the
strategy to output only consistent hypotheses for prefixes from the class.\<close>

definition learn_cons :: "partial2 \<Rightarrow> (partial1 set) \<Rightarrow> partial1 \<Rightarrow> bool" where
  "learn_cons \<psi> U s \<equiv>
     learn_lim \<psi> U s \<and>
     (\<forall>f\<in>U. \<forall>n. \<forall>k\<le>n. \<psi> (the (s (f \<triangleright> n))) k = f k)"

definition CONS_wrt :: "partial2 \<Rightarrow> partial1 set set" where
  "CONS_wrt \<psi> \<equiv> {U. \<exists>s. learn_cons \<psi> U s}"

definition CONS :: "partial1 set set" where
  "CONS \<equiv> {U. \<exists>\<psi> s. learn_cons \<psi> U s}"

lemma CONS_subseteq_Lim: "CONS \<subseteq> LIM"
  using CONS_def Lim_def learn_cons_def by blast

lemma learn_consI:
  assumes "environment \<psi> U s"
    and "\<And>f. f \<in> U \<Longrightarrow> \<exists>i. \<psi> i = f \<and> (\<forall>\<^sup>\<infinity>n. s (f \<triangleright> n) \<down>= i)"
    and "\<And>f n. f \<in> U \<Longrightarrow> \<forall>k\<le>n. \<psi> (the (s (f \<triangleright> n))) k = f k"
  shows "learn_cons \<psi> U s"
  using assms learn_lim_def learn_cons_def by simp

text \<open>If a consistent strategy converges, it automatically converges to
a correct hypothesis. Thus we can remove @{term "\<psi> i = f"} from the second
assumption in the previous lemma.\<close>

lemma learn_consI2:
  assumes "environment \<psi> U s"
    and "\<And>f. f \<in> U \<Longrightarrow> \<exists>i. \<forall>\<^sup>\<infinity>n. s (f \<triangleright> n) \<down>= i"
    and "\<And>f n. f \<in> U \<Longrightarrow> \<forall>k\<le>n. \<psi> (the (s (f \<triangleright> n))) k = f k"
  shows "learn_cons \<psi> U s"
proof (rule learn_consI)
  show "environment \<psi> U s"
    and cons: "\<And>f n. f \<in> U \<Longrightarrow> \<forall>k\<le>n. \<psi> (the (s (f \<triangleright> n))) k = f k"
    using assms by simp_all
  show "\<exists>i. \<psi> i = f \<and> (\<forall>\<^sup>\<infinity>n. s (f \<triangleright> n) \<down>= i)" if "f \<in> U" for f
  proof -
    from that assms(2) obtain i n\<^sub>0 where i_n0: "\<forall>n\<ge>n\<^sub>0. s (f \<triangleright> n) \<down>= i"
      by blast
    have "\<psi> i x = f x" for x
    proof (cases "x \<le> n\<^sub>0")
      case True
      then show ?thesis
        using i_n0 cons that by fastforce
    next
      case False
      moreover have "\<forall>k\<le>x. \<psi> (the (s (f \<triangleright> x))) k = f k"
        using cons that by simp
      ultimately show ?thesis using i_n0 by simp
    qed
    with i_n0 show ?thesis by auto
  qed
qed

lemma learn_consE:
  assumes "learn_cons \<psi> U s"
  shows "environment \<psi> U s"
    and "\<And>f. f \<in> U \<Longrightarrow> \<exists>i n\<^sub>0. \<psi> i = f \<and> (\<forall>n\<ge>n\<^sub>0. s (f \<triangleright> n) \<down>= i)"
    and "\<And>f n. f \<in> U \<Longrightarrow> \<forall>k\<le>n. \<psi> (the (s (f \<triangleright> n))) k = f k"
  using assms learn_cons_def learn_lim_def by auto

lemma learn_cons_wrt_goedel:
  assumes "goedel_numbering \<chi>" and "learn_cons \<psi> U s"
  shows "\<exists>t. learn_cons \<chi> U t"
  using learn_cons_def assms
    learn_lim_extra_wrt_goedel[where ?extra="\<lambda>U f n h. \<forall>k\<le>n. h k = f k"]
  by auto

lemma CONS_wrt_phi_eq_CONS: "CONS_wrt \<phi> = CONS"
  using CONS_wrt_def CONS_def learn_cons_wrt_goedel goedel_numbering_phi
  by blast

lemma learn_cons_closed_subseteq:
  assumes "learn_cons \<psi> U s" and "V \<subseteq> U"
  shows "learn_cons \<psi> V s"
  using assms learn_cons_def learn_lim_closed_subseteq by auto

lemma CONS_closed_subseteq:
  assumes "U \<in> CONS" and "V \<subseteq> U"
  shows "V \<in> CONS"
  using assms learn_cons_closed_subseteq by (smt CONS_def mem_Collect_eq)

text \<open>A consistent strategy cannot output the same hypothesis for two
different prefixes from the class to be learned.\<close>

lemma same_hyp_different_init_not_cons:
  assumes "f \<in> U"
    and "g \<in> U"
    and "f \<triangleright> n \<noteq> g \<triangleright> n"
    and "s (f \<triangleright> n) = s (g \<triangleright> n)"
  shows "\<not> learn_cons \<phi> U s"
  unfolding learn_cons_def by (auto, metis assms init_eqI)

subsection \<open>TOTAL: Learning in the limit with total hypotheses\<close>

text \<open>Total learning in the limit requires the strategy to hypothesize
only total functions for prefixes from the class.\<close>

definition learn_total :: "partial2 \<Rightarrow> (partial1 set) \<Rightarrow> partial1 \<Rightarrow> bool" where
  "learn_total \<psi> U s \<equiv>
     learn_lim \<psi> U s \<and>
     (\<forall>f\<in>U. \<forall>n. \<psi> (the (s (f \<triangleright> n))) \<in> \<R>)"

definition TOTAL_wrt :: "partial2 \<Rightarrow> partial1 set set" where
  "TOTAL_wrt \<psi> \<equiv> {U. \<exists>s. learn_total \<psi> U s}"

definition TOTAL :: "partial1 set set" where
  "TOTAL \<equiv> {U. \<exists>\<psi> s. learn_total \<psi> U s}"

lemma TOTAL_subseteq_LIM: "TOTAL \<subseteq> LIM"
  unfolding TOTAL_def Lim_def using learn_total_def by auto

lemma learn_totalI:
  assumes "environment \<psi> U s"
    and "\<And>f. f \<in> U \<Longrightarrow> \<exists>i. \<psi> i = f \<and> (\<forall>\<^sup>\<infinity>n. s (f \<triangleright> n) \<down>= i)"
    and "\<And>f n. f \<in> U \<Longrightarrow> \<psi> (the (s (f \<triangleright> n))) \<in> \<R>"
  shows "learn_total \<psi> U s"
  using assms learn_lim_def learn_total_def by auto

lemma learn_totalE:
  assumes "learn_total \<psi> U s"
  shows "environment \<psi> U s"
    and "\<And>f. f \<in> U \<Longrightarrow> \<exists>i n\<^sub>0. \<psi> i = f \<and> (\<forall>n\<ge>n\<^sub>0. s (f \<triangleright> n) \<down>= i)"
    and "\<And>f n. f \<in> U \<Longrightarrow> \<psi> (the (s (f \<triangleright> n))) \<in> \<R>"
  using assms learn_lim_def learn_total_def by auto

lemma learn_total_wrt_goedel:
  assumes "goedel_numbering \<chi>" and "learn_total \<psi> U s"
  shows "\<exists>t. learn_total \<chi> U t"
  using learn_total_def assms learn_lim_extra_wrt_goedel[where ?extra="\<lambda>U f n h. h \<in> \<R>"]
  by auto

lemma TOTAL_wrt_phi_eq_TOTAL: "TOTAL_wrt \<phi> = TOTAL"
  using TOTAL_wrt_def TOTAL_def learn_total_wrt_goedel goedel_numbering_phi
  by blast

lemma learn_total_closed_subseteq:
  assumes "learn_total \<psi> U s" and "V \<subseteq> U"
  shows "learn_total \<psi> V s"
  using assms learn_total_def learn_lim_closed_subseteq by auto

lemma TOTAL_closed_subseteq:
  assumes "U \<in> TOTAL" and "V \<subseteq> U"
  shows "V \<in> TOTAL"
  using assms learn_total_closed_subseteq by (smt TOTAL_def mem_Collect_eq)

subsection \<open>CP: Learning in the limit with class-preserving hypotheses\<close>

text \<open>Class-preserving learning in the limit requires all hypotheses
for prefixes from the class to be functions from the class.\<close>

definition learn_cp :: "partial2 \<Rightarrow> (partial1 set) \<Rightarrow> partial1 \<Rightarrow> bool" where
  "learn_cp \<psi> U s \<equiv>
     learn_lim \<psi> U s \<and>
     (\<forall>f\<in>U. \<forall>n. \<psi> (the (s (f \<triangleright> n))) \<in> U)"

definition CP_wrt :: "partial2 \<Rightarrow> partial1 set set" where
  "CP_wrt \<psi> \<equiv> {U. \<exists>s. learn_cp \<psi> U s}"

definition CP :: "partial1 set set" where
  "CP \<equiv> {U. \<exists>\<psi> s. learn_cp \<psi> U s}"

lemma learn_cp_wrt_goedel:
  assumes "goedel_numbering \<chi>" and "learn_cp \<psi> U s"
  shows "\<exists>t. learn_cp \<chi> U t"
  using learn_cp_def assms learn_lim_extra_wrt_goedel[where ?extra="\<lambda>U f n h. h \<in> U"]
  by auto

corollary CP_wrt_phi: "CP = CP_wrt \<phi>"
  using learn_cp_wrt_goedel[OF goedel_numbering_phi]
  by (smt CP_def CP_wrt_def Collect_cong)

lemma learn_cpI:
  assumes "environment \<psi> U s"
    and "\<And>f. f \<in> U \<Longrightarrow> \<exists>i. \<psi> i = f \<and> (\<forall>\<^sup>\<infinity>n. s (f \<triangleright> n) \<down>= i)"
    and "\<And>f n. f \<in> U \<Longrightarrow> \<psi> (the (s (f \<triangleright> n))) \<in> U"
  shows "learn_cp \<psi> U s"
  using assms learn_cp_def learn_lim_def by auto

lemma learn_cpE:
  assumes "learn_cp \<psi> U s"
  shows "environment \<psi> U s"
    and "\<And>f. f \<in>  U \<Longrightarrow> \<exists>i n\<^sub>0. \<psi> i = f \<and> (\<forall>n\<ge>n\<^sub>0. s (f \<triangleright> n) \<down>= i)"
    and "\<And>f n. f \<in> U \<Longrightarrow> \<psi> (the (s (f \<triangleright> n))) \<in> U"
  using assms learn_lim_def learn_cp_def by auto

text \<open>Since classes contain only total functions, a CP strategy is also
a TOTAL strategy.\<close>

lemma learn_cp_imp_total: "learn_cp \<psi> U s \<Longrightarrow> learn_total \<psi> U s"
  using learn_cp_def learn_total_def learn_lim_def by auto

lemma CP_subseteq_TOTAL: "CP \<subseteq> TOTAL"
  using learn_cp_imp_total CP_def TOTAL_def by blast

subsection \<open>FIN: Finite learning\<close>

text \<open>In general it is undecidable whether a LIM strategy has reached
its final hypothesis. By contrast, in finite learning (also called ``one-shot
learning'') the strategy signals when it is ready to output a hypothesis. Up
until then it outputs a ``don't know yet'' value. This value is represented
by zero and the actual hypothesis $i$ by $i + 1$.\<close>

definition learn_fin :: "partial2 \<Rightarrow> partial1 set \<Rightarrow> partial1 \<Rightarrow> bool" where
  "learn_fin \<psi> U s \<equiv>
     environment \<psi> U s \<and>
     (\<forall>f \<in> U. \<exists>i n\<^sub>0. \<psi> i = f \<and> (\<forall>n<n\<^sub>0. s (f \<triangleright> n) \<down>= 0) \<and> (\<forall>n\<ge>n\<^sub>0. s (f \<triangleright> n) \<down>= Suc i))"

definition FIN_wrt :: "partial2 \<Rightarrow> partial1 set set" where
  "FIN_wrt \<psi> \<equiv> {U. \<exists>s. learn_fin \<psi> U s}"

definition FIN :: "partial1 set set" where
  "FIN \<equiv> {U. \<exists>\<psi> s. learn_fin \<psi> U s}"

lemma learn_finI:
  assumes "environment \<psi> U s"
    and "\<And>f. f \<in> U \<Longrightarrow>
      \<exists>i n\<^sub>0. \<psi> i = f \<and> (\<forall>n<n\<^sub>0. s (f \<triangleright> n) \<down>= 0) \<and> (\<forall>n\<ge>n\<^sub>0. s (f \<triangleright> n) \<down>= Suc i)"
  shows "learn_fin \<psi> U s"
  using assms learn_fin_def by auto

lemma learn_finE:
  assumes "learn_fin \<psi> U s"
  shows "environment \<psi> U s"
    and "\<And>f. f \<in> U \<Longrightarrow>
      \<exists>i n\<^sub>0. \<psi> i = f \<and> (\<forall>n<n\<^sub>0. s (f \<triangleright> n) \<down>= 0) \<and> (\<forall>n\<ge>n\<^sub>0. s (f \<triangleright> n) \<down>= Suc i)"
  using assms learn_fin_def by auto

lemma learn_fin_closed_subseteq:
  assumes "learn_fin \<psi> U s" and "V \<subseteq> U"
  shows "learn_fin \<psi> V s"
  using assms learn_fin_def by auto

lemma learn_fin_wrt_goedel:
  assumes "goedel_numbering \<chi>" and "learn_fin \<psi> U s"
  shows "\<exists>t. learn_fin \<chi> U t"
proof -
  have env: "environment \<psi> U s"
    and fin: "\<And>f. f \<in> U \<Longrightarrow>
      \<exists>i n\<^sub>0. \<psi> i = f \<and> (\<forall>n<n\<^sub>0. s (f \<triangleright> n) \<down>= 0) \<and> (\<forall>n\<ge>n\<^sub>0. s (f \<triangleright> n) \<down>= Suc i)"
    using assms(2) learn_finE by auto
  obtain c where c: "c \<in> \<R>" "\<forall>i. \<psi> i = \<chi> (the (c i))"
    using env goedel_numberingE[OF assms(1), of \<psi>] by auto
  define t where "t \<equiv>
    \<lambda>x. if s x \<up> then None
         else if s x = Some 0 then Some 0
              else Some (Suc (the (c (the (s x) - 1))))"
  have "t \<in> \<P>"
  proof -
    from c obtain rc where rc:
      "recfn 1 rc"
      "total rc"
      "\<forall>x. c x = eval rc [x]"
      by auto
    from env obtain rs where rs: "recfn 1 rs" "\<forall>x. s x = eval rs [x]"
      by auto
    then have "eval rs [f \<triangleright> n] \<down>" if "f \<in> U" for f n
      using env that by simp
    define rt where "rt = Cn 1 r_ifz [rs, Z, Cn 1 S [Cn 1 rc [Cn 1 r_dec [rs]]]]"
    then have "recfn 1 rt"
      using rc(1) rs(1) by simp
    have "eval rt [x] \<up>" if "eval rs [x] \<up>" for x
      using rc(1) rs(1) rt_def that by auto
    moreover have "eval rt [x] \<down>= 0" if "eval rs [x] \<down>= 0" for x
      using rt_def that rc(1,2) rs(1) by simp
    moreover have "eval rt [x] \<down>= Suc (the (c (the (s x) - 1)))" if "eval rs [x] \<down>\<noteq> 0" for x
      using rt_def that rc rs by auto
    ultimately have "eval rt [x] = t x" for x
      by (simp add: rs(2) t_def)
    with \<open>recfn 1 rt\<close> show ?thesis by auto
  qed
  have t: "t (f \<triangleright> n) \<down>=
      (if s (f \<triangleright> n) = Some 0 then 0 else Suc (the (c (the (s (f \<triangleright> n)) - 1))))"
    if "f \<in> U" for f n
    using that env by (simp add: t_def)
  have "learn_fin \<chi> U t"
  proof (rule learn_finI)
    show "environment \<chi> U t"
      using t by (simp add: \<open>t \<in> \<P>\<close> env goedel_numbering_P2[OF assms(1)])
    show "\<exists>i n\<^sub>0. \<chi> i = f \<and> (\<forall>n<n\<^sub>0. t (f \<triangleright> n) \<down>= 0) \<and> (\<forall>n\<ge>n\<^sub>0. t (f \<triangleright> n) \<down>= Suc i)"
      if "f \<in> U" for f
    proof -
      from fin obtain i n\<^sub>0 where
        i: "\<psi> i = f \<and> (\<forall>n<n\<^sub>0. s (f \<triangleright> n) \<down>= 0) \<and> (\<forall>n\<ge>n\<^sub>0. s (f \<triangleright> n) \<down>= Suc i)"
        using \<open>f \<in> U\<close> by blast
      let ?j = "the (c i)"
      have "\<chi> ?j = f"
        using c(2) i by simp
      moreover have "\<forall>n<n\<^sub>0. t (f \<triangleright> n) \<down>= 0"
        using t[OF that] i by simp
      moreover have "t (f \<triangleright> n) \<down>= Suc ?j" if "n \<ge> n\<^sub>0" for n
        using that i t[OF \<open>f \<in> U\<close>] by simp
      ultimately show ?thesis by auto
    qed
  qed
  then show ?thesis by auto
qed

end