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) J1q)) = p Pring (Pring R J0) J1q"
      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) J1pvar (Pring R J0) i)) =
         p Pring (Pring R J0) J1pvar (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 Ry  carrier Rindexed_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:aA  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 aA)
    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:aA
    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 aA)
    using 2 
     apply (simp add: insert_absorb)
    using a_not_in by blast
qed



end