Theory Hilbert_Basis

section ‹The Hilbert Basis theorem for Indexed Polynomials Rings›
theory Hilbert_Basis

imports "Weak_Hilbert_Basis" 

begin 

subsection ‹The isomorphism between ‹A[X0..Xn] and A[X0..Xn-1][Xn]››

text ‹This part until $var_factor_iso$ is due to Aaron Crighton›
lemma ring_iso_memI': 
  assumes "f ∈ ring_hom R S"
  assumes "g ∈ ring_hom S R"
  assumes "⋀ x. x ∈ carrier R ⟹ g (f x) = x"
  assumes "⋀ x. x ∈ carrier S ⟹ f (g x) = x"
  shows "f ∈ ring_iso R S"
    "g ∈ ring_iso S R"
proof- 
  show 0: "f ∈ ring_iso R S"
    unfolding ring_iso_def mem_Collect_eq
    apply(rule conjI, rule assms(1), rule bij_betwI[of _ _ _ g])
    using assms ring_hom_memE by auto 
  show "g ∈ ring_iso S R"
    unfolding ring_iso_def mem_Collect_eq
    apply(rule conjI, rule assms(2), rule bij_betwI[of _ _ _ f])
    using assms ring_hom_memE by auto 
qed


lemma(in cring) var_factor_inverse:
  assumes "I = J0 ∪ J1"
  assumes "J1 ⊆ I"
  assumes "J1 ∩ J0 = {}"
  assumes "ψ1 = (var_factor_inv I J0 J1)"
  assumes "ψ0 = (var_factor I J0 J1)"
  assumes "P ∈ carrier (Pring (Pring R J0) J1)"
  shows "ψ0 (ψ1 P) = P"
proof(induct rule: ring.Pring_car_induct''[of "Pring R J0" _ J1])
  case 1
  then show ?case 
    using Pring_is_ring by blast 
next
  case 2
  then show ?case 
    using assms(6) by force
next
  case (3 c)
  interpret pring_cring: cring "Pring R J0"
    using Pring_is_cring is_cring by auto 
  interpret Rcring: cring R
    using is_cring by auto 
  have 0: "ring_hom_ring (Pring (Pring R J0) J1) (Pring R I) ψ1"
    by (simp add: assms(1) assms(3) assms(4) var_factor_inv_morphism(1)) 
  have 1: "ring_hom_ring (Pring R I) (Pring (Pring R J0) J1) ψ0"
    by (simp add: assms(1) assms(3) assms(5) var_factor_morphism'(1))
  have 2: "ψ0 ∘ ψ1 ∈ ring_hom (Pring (Pring R J0) J1) (Pring (Pring R J0) J1) "
    using 0 1 ring_hom_trans[of ψ1 "Pring (Pring R J0) J1" "Pring R I" ψ0 "Pring (Pring R J0) J1"]
      ring_hom_ring.homh[of "Pring R I" "Pring (Pring R J0) J1" ψ0]
      ring_hom_ring.homh[of "Pring (Pring R J0) J1" "Pring R I" ψ1]
    by blast
  then show ?case using assms 
    by (simp add: 3 var_factor_inv_morphism(3) var_factor_morphism'(3))
next
  case (4 p q)
  interpret pring_cring: cring "Pring R J0"
    using Pring_is_cring is_cring by auto 
  interpret Rcring: cring R
    using is_cring by auto 
  have 0: "ring_hom_ring (Pring (Pring R J0) J1) (Pring R I) ψ1"
    by (simp add: assms(1) assms(3) assms(4) var_factor_inv_morphism(1)) 
  have 1: "ring_hom_ring (Pring R I) (Pring (Pring R J0) J1) ψ0"
    by (simp add: assms(1) assms(3) assms(5) var_factor_morphism'(1))
  have 2: "ψ0 ∘ ψ1 ∈ ring_hom (Pring (Pring R J0) J1) (Pring (Pring R J0) J1) "
    using 0 1 ring_hom_trans[of ψ1 "Pring (Pring R J0) J1" "Pring R I" ψ0 "Pring (Pring R J0) J1"]
      ring_hom_ring.homh[of "Pring R I" "Pring (Pring R J0) J1" ψ0]
      ring_hom_ring.homh[of "Pring (Pring R J0) J1" "Pring R I" ψ1]
    by blast
  from 4 show ?case  
  proof- 
    fix p q
    assume A: "p ∈ carrier (Pring (Pring R J0) J1)"
      "q ∈ carrier (Pring (Pring R J0) J1)"
      "ψ0 (ψ1 p) = p"
      "ψ0 (ψ1 q) = q"
    show "ψ0 (ψ1 (p ⊕⇘Pring (Pring R J0) J1⇙ q)) = p ⊕⇘Pring (Pring R J0) J1⇙ q"
      using A 2 ring_hom_add[of "ψ0 ∘ ψ1" "Pring (Pring R J0) J1" "Pring (Pring R J0) J1" p q]
        comp_apply[of ψ0 ψ1]
      by (simp add: pring_cring.Pring_add pring_cring.Pring_car)
  qed
next
  case (5 p i)
  interpret pring_cring: cring "Pring R J0"
    using Pring_is_cring is_cring by auto 
  interpret Rcring: cring R
    using is_cring by auto 
  have 0: "ring_hom_ring (Pring (Pring R J0) J1) (Pring R I) ψ1"
    by (simp add: assms(1) assms(3) assms(4) var_factor_inv_morphism(1)) 
  have 1: "ring_hom_ring (Pring R I) (Pring (Pring R J0) J1) ψ0"
    by (simp add: assms(1) assms(3) assms(5) var_factor_morphism'(1))
  have 2: "ψ0 ∘ ψ1 ∈ ring_hom (Pring (Pring R J0) J1) (Pring (Pring R J0) J1) "
    using 0 1 ring_hom_trans[of ψ1 "Pring (Pring R J0) J1" "Pring R I" ψ0 "Pring (Pring R J0) J1"]
      ring_hom_ring.homh[of "Pring R I" "Pring (Pring R J0) J1" ψ0]
      ring_hom_ring.homh[of "Pring (Pring R J0) J1" "Pring R I" ψ1]
    by blast
  from 5 show ?case 
  proof-
    fix p i assume A: "p ∈ carrier (Pring (Pring R J0) J1)"
      "ψ0 (ψ1 p) = p"
      "i ∈ J1"
    show " ψ0 (ψ1 (p ⊗⇘Pring (Pring R J0) J1⇙ pvar (Pring R J0) i)) =
         p ⊗⇘Pring (Pring R J0) J1⇙ pvar (Pring R J0) i"              
    proof- 
      have A1: "ψ0 (ψ1 (pvar (Pring R J0) i)) = pvar (Pring R J0) i"
        by (metis A(3) assms(1) assms(2) assms(3) assms(4) assms(5) 
            var_factor_inv_morphism(2) var_factor_morphism'(2)) 
      then show ?thesis
        using 2  A ring_hom_mult[of "ψ0 ∘ ψ1" "(Pring (Pring R J0) J1)"] 2
          Pring_car  comp_apply[of ψ0 ψ1] 
        by (metis pring_cring.Pring_car pring_cring.Pring_var_closed)
    qed
  qed
qed


lemma(in cring) var_factor_iso:
  assumes "I = J0 ∪ J1"
  assumes "J1 ⊆ I"
  assumes "J1 ∩ J0 = {}"
  assumes "ψ1 = (var_factor_inv I J0 J1)"
  assumes "ψ0 = (var_factor I J0 J1)"
  shows "ψ0 ∈ ring_iso (Pring R I) (Pring (Pring R J0) J1)"
    "ψ1 ∈ ring_iso (Pring (Pring R J0) J1)(Pring R I)"
proof- 
  have 1: "ψ0 ∈ ring_hom (Pring R I) (Pring (Pring R J0) J1)"
    "ψ1 ∈ ring_hom (Pring (Pring R J0) J1) (Pring R I)"
    "⋀x. x ∈ carrier (Pring R I) ⟹ ψ1 (ψ0 x) = x"
    "⋀x. x ∈ carrier (Pring (Pring R J0) J1) ⟹ ψ0 (ψ1 x) = x"
    using assms var_factor_inv_inverse[of I  J0 J1 ψ1] var_factor_inverse[of I  J0 J1 ψ1]
    by (auto simp add: var_factor_inv_morphism(1) cring.var_factor_morphism'(1) is_cring 
        ring_hom_ring.homh)
  show "ψ0 ∈ ring_iso (Pring R I) (Pring (Pring R J0) J1)"
    "ψ1 ∈ ring_iso (Pring (Pring R J0) J1) (Pring R I) "
    using 1 ring_iso_memI'[of ψ0 "Pring R I" "Pring (Pring R J0) J1"  ψ1  ] 
    by auto 
qed


lemma (in cring) is_iso_Prings:
  assumes h1:"I = J0 ∪ J1"
  assumes h2:"J1 ⊆ I"
  assumes h3:"J1 ∩ J0 = {}"
  shows "(Pring (Pring R J0) J1) ≃ (Pring R I)" and "(Pring R I) ≃ (Pring (Pring R J0) J1)"
proof -
  show ‹(Pring (Pring R J0) J1) ≃ (Pring R I)› 
    unfolding is_ring_iso_def 
    using h2 var_factor_iso[of I J0 J1 ‹var_factor_inv I J0 J1› ‹var_factor I J0 J1›]
    using h1 h3 by auto
  show ‹(Pring R I) ≃ (Pring (Pring R J0) J1)› 
    unfolding is_ring_iso_def 
    using h2 var_factor_iso[of I J0 J1 ‹var_factor_inv I J0 J1› ‹var_factor I J0 J1›]
    using h1 h3 by auto
qed

subsection ‹Preliminaries lemmas›
lemma (in cring) poly_no_var:
  assumes ‹x ∈ ((carrier R) [𝒳⇘{}⇙]) ∧ xa ≠ {#}›
  shows ‹x xa = 𝟬›
  apply(rule ring.Pring_car_induct''[of "R" x ‹{}›])
      apply (simp add: local.ring_axioms)
     apply (simp add: Pring_car assms)
  unfolding indexed_const_def using assms 
  by(auto simp add: Pring_add indexed_padd_def) 


lemma (in cring) R_isom_P_mt:‹R ≃ Pring R {}› 
proof -
  interpret cringP: cring "Pring R {}"
    by (simp add: Pring_is_cring is_cring)
  have f0:‹bij_betw indexed_const (carrier R) (carrier (Pring R {}))›
  proof(unfold bij_betw_def inj_on_def, safe)
    fix x y
    assume h1:‹x ∈ carrier R›‹y ∈ carrier R›‹indexed_const x = indexed_const y›
    show ‹indexed_const x = indexed_const y ⟹ x = y›
      by (metis indexed_const_def)
  next
    fix x xa
    assume h1:‹xa ∈ carrier R›
    show ‹indexed_const xa ∈ carrier (Pring R {})›
      by (simp add: h1 indexed_const_closed)
  next
    fix x::‹'f multiset ⇒ 'a›
    assume h1:‹x ∈ carrier (Pring R {})›
    then show ‹x ∈ indexed_const ` carrier R›
      unfolding image_def apply(safe)
      apply(rule bexI[where x=‹x {#}›])
      unfolding indexed_const_def
      by (auto simp:fun_eq_iff Pring_def poly_no_var)
  qed
  show ?thesis
    unfolding is_ring_iso_def ring_iso_def 
    apply(subst ex_in_conv[symmetric])
    unfolding ring_hom_def
    apply(rule exI[where  x="indexed_const"])
    apply(safe)
        apply (simp add: indexed_const_closed)
       apply (simp add: indexed_const_mult)
    using  cringP.indexed_padd_const 
      apply (simp add: Pring_add indexed_padd_const)
     apply (simp add: Pring_one)
    by(simp add:f0)
qed

subsection ‹Hilbert Basis theorem›
text ‹We show after this Hilbert basis theorem, based on Indexed Polynomials in HOL-Algebra
and its extension in $Padic_Fields$›

theorem (in domain) Hilbert_basis:
  assumes h1:‹noetherian_ring R› and h2:‹finite I›
  shows ‹noetherian_ring (Pring R I)›
proof(induct rule :finite.induct[OF h2])
  case 1
  interpret cringP: cring "Pring R {}"
    by (simp add: Pring_is_cring is_cring)
  show ?case 
    using R_isom_P_mt cringP.ring_axioms h1 noetherian_isom_imp_noetherian by auto
next
  case (2 A a)
  have f0:‹noetherian_ring (Pring R A)› 
    using 2 by blast
  have f1:‹cring (Pring R A)›
    using Pring_is_cring is_cring by auto
  interpret UPcring: UP_cring "Pring R A" "UP (Pring R A)"
    by (simp add: UP_cring.intro f1)+
  have f2:‹Pring (Pring R A) {a} ≃ UP (Pring R A)›
    using cring.Pring_one_index_isom_P UP_cring_def f1 
    by (simp add: UPcring.R.Pring_one_index_isom_P)
  then have f3:‹noetherian_ring (UP (Pring R A))› 
    using Pring_is_domain domain.noetherian_R_imp_noetherian_UP_R f0 by blast
  have f7:‹cring (Pring (Pring R A) {a})›
    by (simp add: UPcring.R.Pring_is_cring f1)
  then have ‹UP (Pring R A) ≃ Pring (Pring R A) {a}›
    by (simp add: cring_def f2 ring_iso_sym)
  have f6:‹noetherian_ring (Pring (Pring R A) {a})›
    using ‹UP (Pring R A) ≃ Pring (Pring R A) {a}› cring.axioms(1) f3 
      f7 noetherian_isom_imp_noetherian by auto
  have f10:‹a∉A ⟹ Pring (Pring R A) {a} ≃ (Pring R (insert a A))›
    apply(rule cring.is_iso_Prings(1))
    by (simp add: is_cring)+
  have f11:‹ring (Pring R (insert a A))›
    by (simp add: Pring_is_ring)
  then show ?case 
    apply(cases ‹a∈A›)
    using f0 
     apply (simp add: insert_absorb)
    using noetherian_isom_imp_noetherian[of ‹Pring (Pring R A) {a}› 
        ‹(Pring R (insert a A))›] f10 f11 f6 by(simp)
qed

lemma (in domain) R_noetherian_implies_IP_noetherian:
  assumes h1:‹noetherian_ring R› 
  shows ‹noetherian_ring (Pring R {0..N::nat})›
  using Hilbert_basis h1 by blast

lemma (in domain) IP_noetherian_implies_R_noetherian:
  assumes h1:‹noetherian_ring (Pring R I)› and h2:‹finite I›
  shows ‹noetherian_ring R›
proof(insert h1, induct rule:finite.induct[OF h2])
  case 1
  interpret cringP: cring "Pring R {}"
    by (simp add: Pring_is_cring is_cring)
  have ‹Pring R {} ≃ R›
    using local.ring_axioms R_isom_P_mt ring_iso_sym by blast
  then show ?case 
    using "1" local.ring_axioms noetherian_isom_imp_noetherian by blast
next
  case (2 A a)
  have f1:‹cring (Pring R A)›
    using Pring_is_cring is_cring by auto
  interpret UPcring: UP_cring "Pring R A" "UP (Pring R A)"
    by (simp add: UP_cring.intro f1)+
  interpret dom: domain "(Pring R (A))"
    using Pring_is_domain by blast
  have f2:‹Pring (Pring R A) {a} ≃ UP (Pring R A)›
    using cring.Pring_one_index_isom_P UP_cring_def f1 
    by (simp add: UPcring.R.Pring_one_index_isom_P)
  {assume h2:‹a∉A›
    then have ‹ (Pring (Pring R (A)) {a}) ≃ (Pring R (insert a A))›
      by (simp add: cring.is_iso_Prings(1) is_cring)
    then have ‹noetherian_ring (Pring (Pring R (A)) {a})› 
      using "2.prems" UPcring.R.Pring_is_ring 
        noetherian_isom_imp_noetherian ring_iso_sym by blast
    then have ‹noetherian_ring (Pring R (A))›
      by (simp add: dom.IP_noeth_imp_R_noeth)
    then have ‹noetherian_ring R› 
      using "2.hyps"(2) by blast}note a_not_in=this
  then show ?case apply(cases ‹a∈A›)
    using 2 
     apply (simp add: insert_absorb)
    using a_not_in by blast
qed



end