/- Copyright (c) 2025 Junyu Guo and Hao Shen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Junyu Guo, Hao Shen -/ module public import Mathlib public import Groebner.Remainder public import Groebner.ToMathlib.Finsupp /-! # Gröbner Basis Definition: * `MonomialOrder.IsGroebnerBasis m G I`: Given a monomial order `m`, a subset `G` of an ideal `I` is said to be a Gröbner basis if: (1) `G` is contained in `I` (i.e., all polynomials in `G` belong to the ideal `I`). (2) The ideal generated by the leading terms of all polynomials in `I` is equal to the ideal generated by the leading terms of the polynomials in `G`. Buchberger criterion is proved with the following sequence of theorems, where each one is proved (directly or indirectly) with some of theorems before it: * `MonomialOrder.IsGroebnerBasis.remainder_eq_zero_iff_mem_ideal`: Given a remainder of a polynomial on division by a Gröbner basis of an ideal, the remainder is 0 if and only if the polynomial is in the ideal. * `MonomialOrder.IsGroebnerBasis.isRemainder_zero_iff_mem_ideal`: Given a Gröbner basis of an ideal, 0 is a remainder of a polynomial on division by the Gröbner basis if and only if the polynomial is in the ideal `I`. * `MonomialOrder.IsGroebnerBasis.ideal_eq_span`: Gröbner basis of any ideal spans the ideal. * `MonomialOrder.IsGroebnerBasis.isGroebnerBasis_iff_subset_ideal_and_isRemainder_zero`: A set of polynomials is a Gröbner basis of an ideal if and only if it is a subset of this ideal and 0 is a remainder of each member of this ideal on division by this set. * `MonomialOrder.IsGroebnerBasis.isGroebnerBasis_iff_isRemainder_sPolynomial_zero` (Buchberger Criterion): a basis of an ideal is a Gröbner basis of it if and only if 0 is a remainder of echo sPolynomial between two polynomials on the basis. Other main theroems: * `MonomialOrder.IsGroebnerBasis.existsUnique_isRemainder`: Remainder of any polynomial on division by a Gröbner basis exists and is unique. * `MonomialOrder.IsGroebnerBasis.exists_isGroebnerBasis_finite`: Finite Gröbner basis exists for any ideal of a noetherian multivariate polynomial ring. ## Naming convention Some theorems with an argument in type `Set (MvPolynomial σ R)` and a hypothesis that leading coefficients of all polynomials in the set are invertible have 2 variants, named as following respectively: * without suffix `'` or `₀`: any polynomial `b` in the set has an invertible leading coefficient (`IsUnit (m.leadingCoeff p)`); * with suffix `₀`: any polynomial `b` in the set either has an invertible leading coefficient or is equal to 0 (`IsUnit (m.leadingCoeff p) ∨ b = 0`); * with suffix `'`: no hypotheses on leading coefficients, while requiring `R` to be a field (`Field k`, where the ring is denoted as `k` instead). ## Reference : [Cox2015] -/ @[expose] public section namespace MonomialOrder open MvPolynomial IsRemainder /-- A subset `G` of an ideal `I` is said to be a Gröbner basis if: 1. `G` is contained in `I` (i.e., all polynomials in `G` belong to the ideal `I`). 2. The ideal generated by the leading terms of all polynomials in `I` is equal to the ideal generated by the leading terms of the polynomials in `G`. -/ def IsGroebnerBasis {σ : Type*} {m : MonomialOrder σ} {R : Type*} [CommSemiring R] (G : Set (MvPolynomial σ R)) (I : Ideal (MvPolynomial σ R)) := G ⊆ I ∧ Ideal.span (m.leadingTerm '' ↑I) = Ideal.span (m.leadingTerm '' G) namespace IsGroebnerBasis open scoped MonomialOrder section CommSemiring variable {σ : Type*} {m : MonomialOrder σ} {R : Type*} [CommSemiring R] variable (f p : MvPolynomial σ R) (r : MvPolynomial σ R) lemma subset {G : Set (MvPolynomial σ R)} {I} (h : m.IsGroebnerBasis G I) : G ⊆ I := h.1 lemma span_leadingTerm_image {G : Set (MvPolynomial σ R)} {I} (h : m.IsGroebnerBasis G I) : Ideal.span (m.leadingTerm '' ↑I) = Ideal.span (m.leadingTerm '' G) := h.2 lemma isGroebnerBasis_iff (G : Set (MvPolynomial σ R)) (I : Ideal (MvPolynomial σ R)) : m.IsGroebnerBasis G I ↔ G ⊆ I ∧ m.leadingTerm '' ↑I ⊆ (Ideal.span (m.leadingTerm '' G) : Set (MvPolynomial σ R)) := by constructor · intro h rw [← h.span_leadingTerm_image] exact ⟨h.subset, Ideal.subset_span⟩ intro ⟨h₁, h₂⟩ refine ⟨h₁, ?_⟩ apply le_antisymm · rwa [Ideal.span_le] apply Ideal.span_mono exact Set.image_mono h₁ lemma of_subset {G G' : Set (MvPolynomial σ R)} {I} (h : m.IsGroebnerBasis G I) (hG : G ⊆ G') (hI : G' ⊆ I) : m.IsGroebnerBasis G' I := by rw [isGroebnerBasis_iff] at * exact ⟨hI, subset_trans h.2 (Ideal.span_mono <| Set.image_mono hG)⟩ @[simp] lemma isGroebnerBasis_self (I : Ideal (MvPolynomial σ R)) : m.IsGroebnerBasis I I := by simp [IsGroebnerBasis] @[simp] lemma isGroebnerBasis_sdiff_singleton_zero (G : Set (MvPolynomial σ R)) (I : Ideal (MvPolynomial σ R)) : m.IsGroebnerBasis (G \ {0}) I ↔ m.IsGroebnerBasis G I := by simp [IsGroebnerBasis, m.span_leadingTerm_sdiff_singleton_zero] @[simp] lemma isGroebnerBasis_insert_zero (G : Set (MvPolynomial σ R)) (I : Ideal (MvPolynomial σ R)) : m.IsGroebnerBasis (insert 0 G) I ↔ m.IsGroebnerBasis G I := by unfold IsGroebnerBasis congr! 1 · constructor · intro h x hx apply h simp [hx] · simp [Set.insert_subset_iff] · simp [m.span_leadingTerm_insert_zero] /-- Finite Gröbner basis exists for any ideal of a noetherian multivariate polynomial ring. -/ theorem exists_isGroebnerBasis_finite [inst : IsNoetherianRing (MvPolynomial σ R)] (I : Ideal (MvPolynomial σ R)) : ∃ G : Set (MvPolynomial σ R), m.IsGroebnerBasis G I ∧ G.Finite := by -- todo: Ideal.fg_span_iff_fg_span_finset_subset have key := (Submodule.fg_span_iff_fg_span_finset_subset _).mp <| inst.noetherian <| Ideal.span <| m.leadingTerm '' ↑I simp only [Set.subset_image_iff] at key rcases key with ⟨s, ⟨G', hG'I, hG's⟩, hIs⟩ have ⟨G, hG, hG₁⟩ := hG's ▸ Set.exists_subset_bijOn G' m.leadingTerm use G split_ands · exact subset_trans hG hG'I · rwa [hG₁.image_eq] · simp [Set.BijOn.finite_iff_finite hG₁] lemma singleton_zero_bot : m.IsGroebnerBasis {(0 : MvPolynomial σ R)} ⊥ := by simp [IsGroebnerBasis] lemma empty_bot : m.IsGroebnerBasis (∅ : Set <| MvPolynomial σ R) ⊥ := by simp [IsGroebnerBasis] @[simp] lemma singleton_zero_iff (I : Ideal (MvPolynomial σ R)) : m.IsGroebnerBasis {(0 : MvPolynomial σ R)} I ↔ I = ⊥ := by constructor · simp [IsGroebnerBasis, Ideal.span_eq_bot] aesop · simp_intro .. [singleton_zero_bot] @[simp] lemma empty_iff (I : Ideal (MvPolynomial σ R)) : m.IsGroebnerBasis (∅ : Set <| MvPolynomial σ R) I ↔ I = ⊥ := by constructor · simp [IsGroebnerBasis, Ideal.span_eq_bot] aesop · simp_intro .. [empty_bot] @[simp, nontriviality] lemma of_subsingleton [Subsingleton (MvPolynomial σ R)] {s : Set (MvPolynomial σ R)} {I : Ideal (MvPolynomial σ R)} : m.IsGroebnerBasis s I := by classical simp [IsGroebnerBasis, Subsingleton.eq_zero (α := MvPolynomial σ R), Subsingleton.eq_zero (α := Ideal <| MvPolynomial σ R) I, Subsingleton.eq_zero (α := Ideal <| MvPolynomial σ R) (Ideal.span _)] theorem isGroebnerBasis_iff_subset_and_degree_le_eq_and_degree_le {G : Set (MvPolynomial σ R)} (I : Ideal (MvPolynomial σ R)) (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g)) : m.IsGroebnerBasis G I ↔ G ⊆ I ∧ ∀ p ∈ I, p ≠ 0 → ∃ g ∈ G, m.degree g ≤ m.degree p := by classical constructor · intro h exists h.subset intro p hp hp0 apply Set.mem_image_of_mem m.leadingTerm at hp apply Ideal.subset_span at hp rw [h.span_leadingTerm_image, SetLike.mem_coe, m.span_leadingTerm_eq_span_monomial (by simp_intro .. [hG]), ← Set.image_image (monomial · 1) _ _, mem_ideal_span_monomial_image, m.support_leadingTerm' hp0] at hp simpa using hp rintro ⟨hG', h_degree⟩ rw [isGroebnerBasis_iff] constructor · exact hG' intro p' hp rcases hp with ⟨p, hp', hp'₁⟩ rw [←hp'₁, leadingTerm, SetLike.mem_coe, m.span_leadingTerm_eq_span_monomial (by simp_intro .. [hG]), ← Set.image_image (monomial · 1) _ _, mem_ideal_span_monomial_image] intro j hj specialize h_degree p simp_all [MonomialOrder.leadingCoeff_eq_zero_iff] lemma isGroebnerBasis_iff_subset_and_degree_le_eq_and_degree_le₀ {G : Set (MvPolynomial σ R)} (I : Ideal (MvPolynomial σ R)) (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g) ∨ g = 0) : m.IsGroebnerBasis G I ↔ G ⊆ I ∧ ∀ p ∈ I, p ≠ 0 → ∃ g ∈ G, g ≠ 0 ∧ m.degree g ≤ m.degree p := by rw [← isGroebnerBasis_sdiff_singleton_zero, isGroebnerBasis_iff_subset_and_degree_le_eq_and_degree_le] · simp [and_assoc] simp_intro .. [or_iff_not_imp_right.mp (hG _ _)] lemma span_leadingTerm_eq_span_monomial {G : Set (MvPolynomial σ R)} {I : Ideal (MvPolynomial σ R)} (h : m.IsGroebnerBasis G I) (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g)) : Ideal.span (m.leadingTerm '' ↑G) = Ideal.span ((fun p ↦ monomial (m.degree p) (1 : R)) '' (I \ {(0 : MvPolynomial σ R)})) := by classical wlog hR : Nontrivial R · rw [not_nontrivial_iff_subsingleton] at hR exact ((Submodule.subsingleton_iff _).mpr inferInstance).elim _ _ rw [m.span_leadingTerm_eq_span_monomial (B := (↑G : Set (MvPolynomial σ R))) hG] apply le_antisymm · rw [Ideal.span_le] refine subset_trans ?_ Submodule.subset_span apply Set.image_mono apply Set.subset_diff_singleton h.subset contrapose! hG use 0 simpa · rw [Ideal.span_le] intro x simp? says simp only [Set.mem_image, Set.mem_diff, SetLike.mem_coe, Set.mem_singleton_iff, ne_eq, forall_exists_index, and_imp] intro y hy hy0 hxy rw [← hxy, ← Set.image_image (monomial · 1) _ _, mem_ideal_span_monomial_image] simpa using ((isGroebnerBasis_iff_subset_and_degree_le_eq_and_degree_le _ hG).mp h).2 y hy hy0 theorem span_leadingTerm_eq_span_monomial₀ {G : Set (MvPolynomial σ R)} {I : Ideal (MvPolynomial σ R)} (h : m.IsGroebnerBasis G I) (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g) ∨ g = 0) : Ideal.span (m.leadingTerm '' ↑G) = Ideal.span ((fun p ↦ monomial (m.degree p) (1 : R)) '' (I \ {(0 : MvPolynomial σ R)})) := by rw [← isGroebnerBasis_sdiff_singleton_zero] at h convert span_leadingTerm_eq_span_monomial h _ using 1 · simp [m.image_leadingTerm_sdiff_singleton_zero] · simp_intro .. [or_iff_not_imp_right.mp (hG _ _)] lemma isGroebnerBasis_of_forall_finite_isGroebnerBasis₀ {G : Set (MvPolynomial σ R)} (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g) ∨ g = 0) {I : Ideal (MvPolynomial σ R)} (h : ∀ s : Finset σ, ∃ (σ' : Type*), ∃ m' : MonomialOrder σ', ∃ e : m'.Embedding m, ↑s ⊆ Set.range e ∧ m'.IsGroebnerBasis (rename e ⁻¹' G) (I.comap (rename e))) : m.IsGroebnerBasis G I := by rw [isGroebnerBasis_iff_subset_and_degree_le_eq_and_degree_le₀ (hG := hG)] constructor · intro p hp obtain ⟨σ', m', e, h, h', -⟩ := h p.vars -- todo: `Injective` is not necessary for `MvPolynomial.exists_rename_eq_of_vars_subset_range` obtain ⟨p', rfl⟩ := MvPolynomial.exists_rename_eq_of_vars_subset_range _ _ e.coe_injective h -- why are they defeq? apply Set.mem_of_mem_of_subset (Set.mem_preimage.mpr <| hp) h' rintro p hp hp0 obtain ⟨σ', m', e, h, h'⟩ := h p.vars obtain ⟨p', rfl⟩ := MvPolynomial.exists_rename_eq_of_vars_subset_range _ _ e.coe_injective h rw [isGroebnerBasis_iff_subset_and_degree_le_eq_and_degree_le₀] at h' case hG => intro g simpa using hG (g.rename e) simp? at hp0 says simp only [ne_eq, Embedding.coe_injective, rename_eq_zero_iff_of_injective] at hp0 -- again: why is `hp` defeq with the hypothesis replace ⟨g', h⟩ := h'.2 p' hp hp0 -- todo: why is here a extra space? simp? at h says simp only [Set.mem_preimage, ne_eq] at h refine ⟨g'.rename e, h.1, by simpa using h.2⟩ theorem isGroebnerBasis_union_of_forall_finite_isGroebnerBasis₀ {I : Ideal (MvPolynomial σ R)} {σ' : Finset σ → Type*} {m' : (s : Finset σ) → MonomialOrder (σ' s)} {e : (s : Finset σ) → (m' s).Embedding m} {G' : (s : Finset σ) → Set (MvPolynomial (σ' s) R)} (hG' : ∀ s, ∀ g ∈ G' s, IsUnit ((m' s).leadingCoeff g) ∨ g = 0) (h : ∀ s, ↑s ⊆ Set.range (e s)) (h' : ∀ s, (m' s).IsGroebnerBasis (G' s) (I.comap <| rename (e s))) : m.IsGroebnerBasis (⋃ s : Finset σ, rename (e s) '' G' s) I := by apply isGroebnerBasis_of_forall_finite_isGroebnerBasis₀ · simp intro g s g' hg' rfl simpa using hG' s g' hg' intro s use σ' s, m' s, e s exists h s simp only [Set.preimage_iUnion] apply of_subset (h' s) · apply Set.subset_iUnion_of_subset s simp [Set.preimage_image_eq _ (rename_injective _ (e s).coe_injective)] simp intro s' apply Set.preimage_mono simpa using (h' s').subset lemma isGroebnerBasis_of_forall_finite_isGroebnerBasis {G : Set (MvPolynomial σ R)} (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g)) {I : Ideal (MvPolynomial σ R)} (h : ∀ s : Finset σ, ∃ (σ' : Type*), ∃ m' : MonomialOrder σ', ∃ e : m'.Embedding m, ↑s ⊆ Set.range e ∧ m'.IsGroebnerBasis (rename e ⁻¹' G) (I.comap (rename e))) : m.IsGroebnerBasis G I := isGroebnerBasis_of_forall_finite_isGroebnerBasis₀ (fun g hg ↦ Or.inl (hG g hg)) h theorem isGroebnerBasis_union_of_forall_finite_isGroebnerBasis {I : Ideal (MvPolynomial σ R)} {σ' : Finset σ → Type*} {m' : (s : Finset σ) → MonomialOrder (σ' s)} {e : (s : Finset σ) → (m' s).Embedding m} {G' : (s : Finset σ) → Set (MvPolynomial (σ' s) R)} (hG' : ∀ s, ∀ g ∈ G' s, IsUnit ((m' s).leadingCoeff g)) (h : ∀ s, ↑s ⊆ Set.range (e s)) (h' : ∀ s, (m' s).IsGroebnerBasis (G' s) (I.comap <| rename (e s))) : m.IsGroebnerBasis (⋃ s : Finset σ, rename (e s) '' G' s) I := isGroebnerBasis_union_of_forall_finite_isGroebnerBasis₀ (fun s g hg ↦ Or.inl (hG' s g hg)) h h' end CommSemiring section CommRing variable {σ : Type*} {m : MonomialOrder σ} {R : Type*} [CommRing R] /-- Given a remainder `r` of a polynomial `p` on division by a Gröbner basis `G` of an ideal `I`, the remainder `r` is 0 if and only if `p` is in the ideal `I`. Any leading coefficient of polynomial in the Gröbner basis `G` is required to be a unit. -/ theorem remainder_eq_zero_iff_mem_ideal {p : MvPolynomial σ R} {G : Set (MvPolynomial σ R)} {I : Ideal (MvPolynomial σ R)} {r : MvPolynomial σ R} (h : m.IsGroebnerBasis G I) (hr : m.IsRemainder p G r) : r = 0 ↔ p ∈ I := by constructor · rw [← mem_ideal_iff h.subset hr] simp_intro .. intro h_p_mem rcases h with ⟨h_G', h_span⟩ have ⟨⟨q, h_p_eq_sum_r, h_r_reduced⟩, h_degree⟩ := hr rw [h_p_eq_sum_r, Ideal.add_mem_iff_right] at h_p_mem on_goal 2 => exact Ideal.span_le.mpr h_G' <| (Finsupp.mem_span_iff_linearCombination ..).mpr ⟨_, rfl⟩ apply Set.mem_image_of_mem m.leadingTerm at h_p_mem -- todo: Ideal.mem_span_of_mem apply Submodule.mem_span_of_mem (R := MvPolynomial σ R) at h_p_mem contrapose! h_p_mem with h_r_ne_zero simpa [← h_span] using term_notMem_span_leadingTerm hr (m.degree r) (by simp [h_r_ne_zero]) /-- Given a Gröbner basis `G` of an ideal `I`, 0 is a remainder on division by `G` if and only if `p` is in the ideal `I`. -/ theorem isRemainder_zero_iff_mem_ideal {p : MvPolynomial σ R} {G : Set (MvPolynomial σ R)} {I : Ideal (MvPolynomial σ R)} (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g)) (h : m.IsGroebnerBasis G I) : m.IsRemainder p G 0 ↔ p ∈ I := by constructor · intro hr apply (remainder_eq_zero_iff_mem_ideal h hr).mp rfl · intro hp obtain ⟨r, hr⟩ := exists_isRemainder₀ (fun g a ↦ Or.symm (Or.inr (hG g a))) p rwa [(remainder_eq_zero_iff_mem_ideal h hr).mpr hp] at hr lemma isRemainder_zero_iff_mem_ideal₀ {p : MvPolynomial σ R} {G : Set (MvPolynomial σ R)} {I : Ideal (MvPolynomial σ R)} (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g) ∨ g = 0) (h : m.IsGroebnerBasis G I) : m.IsRemainder p G 0 ↔ p ∈ I := by rw [← isGroebnerBasis_sdiff_singleton_zero] at h rw [← isRemainder_sdiff_singleton_zero_iff_isRemainder] refine isRemainder_zero_iff_mem_ideal ?_ h simp_intro a b [or_iff_not_imp_right.mp (hG _ _)] /-- Gröbner basis of any ideal spans the ideal. -/ theorem ideal_eq_span {G : Set (MvPolynomial σ R)} {I : Ideal (MvPolynomial σ R)} (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g)) (h : m.IsGroebnerBasis G I) : I = Ideal.span G := by apply le_antisymm · intro p hp rw [← isRemainder_zero_iff_mem_ideal hG h] at hp obtain ⟨⟨f, h_eq, h_deg⟩, h_remain⟩ := hp rw [h_eq, Finsupp.linearCombination_apply, add_zero] apply Ideal.sum_mem intro g hg rcases g with ⟨g, gG'⟩ exact Ideal.mul_mem_left _ _ (Ideal.subset_span gG') · intro p hp suffices Ideal.span ↑G ≤ I from this hp apply Ideal.span_le.mpr intro p hp' exact h.subset hp' theorem ideal_eq_span₀ {G : Set (MvPolynomial σ R)} {I : Ideal (MvPolynomial σ R)} (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g) ∨ g = 0) (h : m.IsGroebnerBasis G I) : I = Ideal.span G := by rw [← isGroebnerBasis_sdiff_singleton_zero] at h rw [h.ideal_eq_span, Ideal.span_sdiff_singleton_zero] simp_intro .. [or_iff_not_imp_right.mp (hG _ _)] theorem isGroebnerBasis_iff_ideal_eq_span_and_isGroebnerBasis_span (G : Set (MvPolynomial σ R)) (I : Ideal (MvPolynomial σ R)) (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g)) : m.IsGroebnerBasis G I ↔ (I = Ideal.span G ∧ m.IsGroebnerBasis G (Ideal.span G)) := by constructor · intro this simpa [ideal_eq_span hG this] · simp_intro .. theorem isGroebnerBasis_iff_ideal_eq_span_and_isGroebnerBasis_span₀ (G : Set (MvPolynomial σ R)) (I : Ideal (MvPolynomial σ R)) (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g) ∨ g = 0) : m.IsGroebnerBasis G I ↔ (I = Ideal.span G ∧ m.IsGroebnerBasis G (Ideal.span G)) := by simp_rw [← isGroebnerBasis_sdiff_singleton_zero (G := G), ← Ideal.span_sdiff_singleton_zero (s := G)] apply isGroebnerBasis_iff_ideal_eq_span_and_isGroebnerBasis_span simp_intro .. [or_iff_not_imp_right.mp (hG _ _)] /-- A set of polynomials is a Gröbner basis of an ideal if and only if it is a subset of this ideal and 0 is a remainder of each member of this ideal on division by this set. Any leading coefficient of polynomial in the set is required to be a unit. -/ theorem isGroebnerBasis_iff_subset_ideal_and_isRemainder_zero (G : Set (MvPolynomial σ R)) (I : Ideal (MvPolynomial σ R)) (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g)) : m.IsGroebnerBasis G I ↔ G ⊆ I ∧ ∀ p ∈ I, m.IsRemainder p G 0 := by constructor · intro h exists h.subset intro p h_p_in_I rwa [isRemainder_zero_iff_mem_ideal hG h] · intro h rcases h with ⟨h_G, h_remainder⟩ rw [isGroebnerBasis_iff_subset_and_degree_le_eq_and_degree_le I hG] constructor · apply h_G · intro p hp hp0 exact exists_degree_le_degree_of_zero hp0 (h_remainder p hp) /-- A set of polynomials is a Gröbner basis of an ideal if and only if it is a subset of this ideal and 0 is a remainder of each member of this ideal on division by this set. It is a variant of `MonomialOrder.IsGroebnerBasis.isGroebnerBasis_iff_subset_ideal_and_isRemainder_zero`, allowing the set to contain also 0, besides polynomials with invertible leading coefficients. -/ theorem isGroebnerBasis_iff_subset_ideal_and_isRemainder_zero₀ (G : Set (MvPolynomial σ R)) (I : Ideal (MvPolynomial σ R)) (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g) ∨ g = 0) : m.IsGroebnerBasis G I ↔ G ⊆ I ∧ ∀ p ∈ I, m.IsRemainder p G 0 := by rw [← isGroebnerBasis_sdiff_singleton_zero] convert isGroebnerBasis_iff_subset_ideal_and_isRemainder_zero (G \ {0}) I _ using 2 · simp · simp [isRemainder_sdiff_singleton_zero_iff_isRemainder] · simp_intro .. [or_iff_not_imp_right.mp (hG _ _)] /-- Remainder of any polynomial on division by a Gröbner basis exists and is unique. Any leading coefficient of polynomial in the Gröbner basis is required to be a unit. -/ theorem existsUnique_isRemainder {G : Set (MvPolynomial σ R)} {I : Ideal (MvPolynomial σ R)} (h : m.IsGroebnerBasis G I) (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g)) (p : MvPolynomial σ R) : ∃! (r : MvPolynomial σ R), m.IsRemainder p G r := by apply existsUnique_of_exists_of_unique (exists_isRemainder hG p) intro r₁ r₂ hr₁ hr₂ rw [← sub_eq_zero] by_contra! hrne0 have hr := (m.degree_mem_support_iff _).mpr hrne0 apply sub_monomial_notMem_span_leadingTerm (B := ↑G) hr₁ hr₂ at hr rw [span_leadingTerm_eq_span_monomial h hG] at hr apply hr apply Submodule.mem_span_of_mem apply Set.mem_image_of_mem simpa [hrne0] using sub_mem_ideal_of_isRemainder_of_subset_ideal h.subset hr₁ hr₂ /-- Remainder of any polynomial on division by a Gröbner basis exists and is unique. It is a variant of `MonomialOrder.IsGroebnerBasis.existsUnique_isRemainder`, allowing the Gröbner basis to contain also 0, besides polynomials with invertible leading coefficients. -/ theorem existsUnique_isRemainder₀ {G : Set (MvPolynomial σ R)} {I : Ideal (MvPolynomial σ R)} (h : m.IsGroebnerBasis G I) (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g) ∨ g = 0) (p : MvPolynomial σ R) : ∃! (r : MvPolynomial σ R), m.IsRemainder p G r := by rw [← isGroebnerBasis_sdiff_singleton_zero] at h simp_rw [← isRemainder_sdiff_singleton_zero_iff_isRemainder p G] convert existsUnique_isRemainder h _ p simp_intro .. [or_iff_not_imp_right.mp (hG _ _)] private lemma degree_lt_of_left_ne_zero_of_degree_mul_lt_of_mem_nonZeroDivisors {R} [CommSemiring R] {p p' q : MvPolynomial σ R} (hp : p ≠ 0) (hq : m.leadingCoeff q ∈ nonZeroDivisors _) (h : m.degree (p * q) ≺[m] m.degree (p' * q)) : m.degree p ≺[m] m.degree p' := by apply lt_of_le_of_lt' m.degree_mul_le at h simpa [m.degree_mul_of_right_mem_nonZeroDivisors hp hq] using h private lemma degree_mul_lt_iff_left_lt_of_ne_zero_of_mem_nonZeroDivisors {R} [CommSemiring R] {p p' q : MvPolynomial σ R} (hp : p ≠ 0) (hq : m.leadingCoeff q ∈ nonZeroDivisors _) : m.degree (p * q) ≺[m] m.degree (p' * q) ↔ m.degree p ≺[m] m.degree p' := by refine ⟨degree_lt_of_left_ne_zero_of_degree_mul_lt_of_mem_nonZeroDivisors hp hq, ?_⟩ intro h simpa [m.degree_mul_of_right_mem_nonZeroDivisors hp hq, m.degree_mul_of_right_mem_nonZeroDivisors (show p' ≠ 0 by contrapose! h; simp [h]) hq] using h set_option maxHeartbeats 400000 in -- It reaches the default max heart beats with option `says.verify` set to `true`, without which the -- proof can pass with default max heart beats. /-- Buchberger Criterion: a basis of an ideal is a Gröbner basis of it if and only if 0 is a remainder of echo sPolynomial between two polynomials on the basis. -/ theorem isGroebnerBasis_iff_isRemainder_sPolynomial_zero {G : Set (MvPolynomial σ R)} (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g)) : m.IsGroebnerBasis G (Ideal.span G) ↔ ∀ (g₁ g₂ : G), m.IsRemainder (m.sPolynomial g₁ g₂ : MvPolynomial σ R) G 0 := by /- The informal proof is attached in comment blocks (`/- -/`), where math expressions are written in `$ $` or `$$ $$` like in LaTeX or Markdown, while we tend to use unicode symbols like Lean code instead of LaTeX commands are used for readability. And every block roughly corresponds with a block of code below it and above the next comment block (if it exists). And inline comments (`--`) are about technical details in formalization. -/ -- TODO: (maybe) simplify this proof with `withBotDegree`? (The current proof was made before -- `withBotDegree` was defined and used to refactore `IsRemainder`, so it deals with some edge -- cases about degree of zero polynomial.) classical constructor · /- (→) Easy to prove. -/ intro h _ _ rw [isGroebnerBasis_iff_subset_ideal_and_isRemainder_zero (hG := hG)] at h apply h.2 apply m.sPolynomial_mem_ideal <;> exact Set.mem_of_mem_of_subset (by simp) h.1 /- (←) We only need to prove for all $p ∈ ⟨G⟩$ (`p ∈ Ideal.span G`), (with loss of generality, assuming $p ≠ 0$) $0$ is a remainder of $p$ on division by $G$ (`m.IsRemainder p G 0`), i.e. to prove that these exists finite subset $G'$ of $G$ and $f$ s.t. $p = ∑_{g ∈ G'} f(g) * g$ and $∀ g ∈ G', degree(f(g) * g) ≤ degree(p)$. -/ wlog! _ : Nontrivial R · simp have hG₁ {g : G} := hG g g.prop have hG₀ {g} := (@hG₁ g).mem_nonZeroDivisors -- `rfl` doens't rewrite the goal? intro hsPoly rw [isGroebnerBasis_iff_subset_ideal_and_isRemainder_zero (hG := hG)] exists Ideal.subset_span intro p hp wlog! hpne0 : p ≠ 0 · simp [hpne0] simp_rw [isRemainder_def, add_zero, ← map_add, ← m.withBotDegree_mul_of_left_mem_nonZeroDivisors hG₀, m.withBotDegree_le_withBotDegree_iff_of_ne_zero _ hpne0] refine ⟨?_, by simp⟩ /- From $p ∈ ⟨G⟩$, we get immediately that all condition we needed above except for $∀ g ∈ G', degree(f(g) * g) ≤ degree(p)$. We assume it doesn't hold, i.e. $max_{g ∈ G'} degree(f(g) * g) > degree(p)$. -/ -- todo: `Ideal.mem_span_iff_exists_finset_subset`? obtain ⟨f₀_, G'₀_, hG'_, ⟨-, hsumf⟩⟩ := Submodule.mem_span_iff_exists_finset_subset.mp hp -- we need variants of `f₀` abd `G'₀` that use coercion `↥G` instead of `MvPolynomial σ R`, to -- pass the information of set membership and make use of `hG` and S-polynomial decomposition. let G'₀ := G'₀_.attach.image (β := G) (fun p ↦ ⟨p.val, hG'_ p.prop⟩) let f₀ (p : G) := f₀_ p convert_to ∑ a ∈ G'₀, f₀ a * a = p at hsumf · unfold G'₀ rw [Finset.sum_image (by simp [Function.Injective])] exact Finset.sum_attach .. |>.symm clear_value G'₀ f₀ clear hG'_ G'₀_ f₀_ by_cases! h : G'₀.sup (fun g ↦ (m.toSyn <| m.degree <| g.val * (f₀ g))) ≤ m.toSyn (m.degree p) · exact ⟨f₀, G'₀, hsumf.symm, by simpa using h⟩ /- We have now $P(max_{g ∈ G'} degree(f(g) * g))$ where $P(a) : ∃ finite G' ⊆ G and f, p = ∑ g ∈ G', f(g) * g ∧ ∀ g ∈ G', degree(f(g) * g) ≤ a$, and we will prove an assertion that, for each $a > degree(p)$, if $P(a)$, then there exists $degree(g) ≤ a' < a$ s.t. $P(a')$ also holds. With this assertion, we can get $P(degree(p))$ by well-founded induction on $a$. (Formalization note: here we don't directly prove $degree(p)$ satisfies predicate $P$ by induction. We prove with predicate $a ↦ degree(p) ≤ a ∧ P(a)$ instead.) -/ -- todo: lemmas for induction in this form. refine WellFounded.induction_bot WellFoundedLT.toWellFoundedRelation.wf (a := G'₀.sup fun g ↦ (m.toSyn <| m.degree <| g.val * (f₀ g))) (bot := m.toSyn (m.degree p)) (C := fun a ↦ m.toSyn (m.degree p) ≤ a ∧ ∃ (f : G → MvPolynomial σ R) (G' : Finset G), p = ∑ g ∈ G', (f g) * g ∧ ∀ g ∈ G', (m.toSyn <| m.degree <| g.val * f g) ≤ a) (fun a ha ⟨ha', ⟨f, G', hsumf, h_deg_le⟩⟩ ↦ ?_) ⟨le_of_lt h, ⟨f₀, G'₀, hsumf.symm, by apply Finset.le_sup⟩⟩ |>.2 /- We start to prove the assertion. Assume $a > degree(p)$ (`ha`), $G' ⊆ G$ (`hG'subsetG`), $f$ (`f`) s.t. $p = ∑ g ∈ G', f(g) * g$ (`hsumf`), and $∀ g ∈ G', degree(f(g) * g) ≤ a$ (`h_deg_le`). Without loss of generality, we can assume $f(g)$ vanishes when $g ∉ G'$. -/ clear! f₀ G'₀ wlog hf₀support : ∀ g, g ∉ G' → f g = 0 generalizing f · specialize this (fun g ↦ if g ∈ G' then f g else 0); simp_all apply lt_of_le_of_ne' ha' at ha /- Let $lt'(g) := leadingTerm(g) if degree(f(g) * g) = a, or else 0$ (`lt'`). $$ p = ∑ g ∈ G', f(g) * g = ∑ g ∈ G' with (degree(f(g) * g) = a), leadingTerm(f(g)) * g + ∑ g ∈ G', (f(g) - lt'(g)) * g.$$ (`hp`) -/ let degFgEqA g := (m.toSyn <| m.degree <| f g * g.val) = a let lt' g := if degFgEqA g then m.leadingTerm (f g) else 0 have hp := calc p = ∑ g ∈ G', f g * g := hsumf _ = ∑ g ∈ G' with degFgEqA g, m.leadingTerm (f g) * g + ∑ g ∈ G', (f g - lt' g) * g := by simp [← Finset.sum_add_distrib, ← add_mul, ← ite_zero_mul, Finset.sum_filter, -ite_mul, lt'] /- For any $g ∈ G'$, it can be easily seen that $degree (f(g) - lt'(g)) g$ is either less than $a$ or equal to $0$, so $degree( (f(g) - lt'(g)) * g ) < a$, and $∑ g ∈ G', (f(g) - lt'(g)) * g < a$. Since $$degree( ∑ g ∈ G' with (degree(f(g) * g) = a), leadingTerm(f(g)) * g + ∑ g ∈ G', (f(g) - lt'(g)) * g ) = degree(p) < a,$$ we can obtain $degree( ∑ g ∈ G' with (degree(f(g) * g) = a), leadingTerm(f(g)) * g ) < a$. Obviously, $degree(leadingTerm(f(g)) g)) = a$, for all $g ∈ G'$ s.t. $degree(f(g) g) = a$. So this sum can be decomposed into a sum of S-polynomials: there exists $c(g₁, g₂) ∈ R$ (`c`) for each $g₁, g₂ ∈ \{g ∈ G' | degree(f(g) * g) = a\}$, s.t. $$∑ g ∈ G' with (degree(f(g) * g) = a), leadingTerm(f(g)) * g = ∑ g ∈ G' with (degree(f(g) * g) = a), leadingCoeff(f(g)) • lm(f(g)) * g = ∑ g₁, g₂ ∈ \{g ∈ G' | degree(f(g) * g) = a\}, c(g₁, g₂) * sPoly(lm(f(g₁)) * g₁, lm(f(g₂)) * g₂) = ∑ g₁, g₂ ∈ \{g ∈ G' | degree(f(g) * g) = a\}, c(g₁, g₂) * (lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂)) / lcm(lm(g₁), lm(g₂))) * sPoly(g₁, g₂),$$ (`h_sum_sPoly`) where $lm(p)$ is leading monomial of $p$ ($x^degree(p)$ if we ignore edge case that $p = 0$), and $lcm(lm(g₁), lm(g₂))$ is least common multiple of $lm(g₁)$ and $lm(g₂)$. (Formalization note: formalization of $lcm$ is based on operations on `Finsupp` instead of `MvPolynomial`. For more formalization details, see the doc of `MonomialOrder.sPolynomial`.) -/ have h_a_gt_zero : 0 < a := bot_lt_of_lt ha let leadingTerm_mul_eq (p q : MvPolynomial σ R) : m.leadingTerm p * q = m.leadingCoeff p • (monomial (m.degree p) 1 * q) := by rw [smul_eq_C_mul, ← mul_assoc, C_mul_monomial, mul_one, leadingTerm] -- simp [← mul_assoc] obtain ⟨c, h_sum_sPoly⟩ := m.sPolynomial_decomposition_of_degree_sum_smul_le (d := a) (B := G'.filter degFgEqA) (g := fun g ↦ monomial (m.degree (f g)) 1 * g.val) (c := fun g ↦ m.leadingCoeff (f g)) (hB := by simp [hG, m.leadingCoeff_mul_of_right_mem_nonZeroDivisors' hG₀]) (by simp only [Finset.mem_filter, and_imp, degFgEqA] intro b hb h rw [m.degree_mul_of_right_mem_nonZeroDivisors ?_ hG₀] at h ⊢ · simpa [m.degree_monomial] using h · simp contrapose! h_a_gt_zero with hfb simp [← h, hfb]) (by simp only [leadingTerm_mul_eq] at hp simp only [← sub_eq_iff_eq_add.mpr hp] apply lt_of_le_of_lt m.degree_sub_le simp? [ha] says simp only [sup_lt_iff, ha, true_and] apply lt_of_le_of_lt m.degree_sum_le simp only [Finset.sup_lt_iff h_a_gt_zero, lt'] intro g hg wlog h : degFgEqA g · simpa [h] using lt_of_le_of_ne (mul_comm g.val _ ▸ h_deg_le g hg) h simp? [h] says simp only [h, ↓reduceIte] wlog! +distrib h' : f g - m.leadingTerm (f g) ≠ 0 · simp [h_a_gt_zero, h'] apply lt_of_le_of_lt' (h_deg_le g hg) -- case edge about `degree 0` rw [mul_comm g.val, degree_mul_lt_iff_left_lt_of_ne_zero_of_mem_nonZeroDivisors h' hG₀] exact m.degree_sub_leadingTerm_lt_degree (m.degree_ne_zero_of_sub_leadingTerm_ne_zero h')) conv at h_sum_sPoly => simp only [← leadingTerm_mul_eq] rhs simp only [m.sPolynomial_monomial_mul_of_mem_nonZeroDivisors hG₀ hG₀, ← G'.filter degFgEqA |>.sum_coe_sort] /- For echo $g₁, g₂ ∈ G$, $0$ is a remainder of $sPoly(g₁, g₂)$ on division by G, and thus we obtain its "quotients" in form of a finitely supported function $q_{g₁, g₂}$ s.t. it satisfies the following conditions (`hq`): - $supp(q_{g₁, g₂}) ⊆ G$, - $sPoly(g₁, g₂) = ∑ g ∈ G, q_{g₁, g₂}(g) * g$, - $∀ g ∈ G, degree(q_{g₁, g₂}(g) * g) ≤ degree(sPoly(g₁, g₂))$, and - if $sPoly(g₁, g₂) = 0$ then $q_{g₁, g₂} = 0$. -/ simp [IsRemainder, -Subtype.forall, ← map_add, ← m.withBotDegree_mul_of_left_mem_nonZeroDivisors hG₀, m.withBotDegree_le_withBotDegree_iff] at hsPoly replace hsPoly (g₁ g₂ : G'.filter degFgEqA) := hsPoly g₁ g₂ let q (g₁ g₂ : G'.filter degFgEqA) := (hsPoly g₁ g₂).choose have hq (g₁ g₂ : G'.filter degFgEqA) := (hsPoly g₁ g₂).choose_spec -- I'd like to get rid of `.choose` in following formalization. simp_rw [show _ = q _ _ by unfold q; rfl] at hq -- TODO: a variant of `generalize` tactic that can replace with arguments clear_value q -- clear its value to ensure we will not use it (optional) /- Let $G''$ be $G' ∪ (∪ g₁, g₂ ∈ \{g ∈ G' | degree(f(g) * g) = a\}, supp(q_{g₁, g₂})).$ Obviously, $G''$ is a finite subset of $G$, and $support(q_{g₁, g₂}) ⊆ G''$ for all $g₁, g₂ ∈ \{g ∈ G' | degree(f(g) * g) = a\}$. Then for all $g₁, g₂ ∈ \{g ∈ G' | degree(f(g) * g) = a\}$, $sPoly(g₁, g₂) = ∑ g ∈ G'', q_{g₁, g₂}(g) * g$. -/ let G'' : Finset G := G' ∪ (G'.filter degFgEqA).attach.biUnion fun b₁ ↦ (G'.filter degFgEqA).attach.biUnion fun b₂ ↦ (q b₁ b₂).support conv at hq => ext g₁ g₂ simp only [Finsupp.linearCombination_apply_of_mem_supported (l := (q g₁ g₂)) (s := G'') (hs := by simp? [Finsupp.mem_supported, G''] says simp only [Finset.coe_union, Finset.coe_biUnion, Finset.coe_attach, Set.mem_univ, Set.iUnion_true, Finsupp.mem_supported, G''] apply Set.subset_union_of_subset_right exact Set.subset_iUnion₂_of_subset g₁ g₂ subset_rfl), smul_eq_mul] /- Substituting them into our decomposition by S-polynomials, we have: $$∑ g ∈ G' with (degree(f(g) * g) = a), leadingTerm(f(g)) * g = ∑ g₁, g₂ ∈ \{g ∈ G' | degree(f(g) * g) = a\}, c(g₁, g₂) * (lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂)) / lcm(lm(g₁), lm(g₂))) * sPoly(g₁, g₂) = ∑ g₁, g₂ ∈ \{g ∈ G' | degree(f(g) * g) = a\}, c(g₁, g₂)•(lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂)) / lcm(lm(g₁), lm(g₂))) * ∑ g ∈ G'', q_{g₁, g₂}(g) * g = ∑ g ∈ G'', (∑ g₁, g₂ ∈ \{g ∈ G' | degree(f(g) * g) = a\}, c(g₁, g₂)•(lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂)) / lcm(lm(g₁), lm(g₂))) * q_{g₁, g₂}(g)) * g. $$ (`h_sum_sPoly`) Note: degrees of $(f(g) - lt'(g)) * g$ and $c(g₁, g₂)•(lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂)) / lcm(lm(g₁), lm(g₂))) * q_{g₁, g₂} * g$ are both less than $a$. It is a key to complete the proof. We will proof it at the end. -/ simp_rw [(hq _ _).1] at h_sum_sPoly replace hq (g₁ g₂ : G'.filter degFgEqA) := (hq g₁ g₂).2 clear hsPoly -- clear the infoview (optional) set_option backward.isDefEq.respectTransparency false in simp_rw [mul_one, G''.mul_sum, ← mul_assoc, Finset.smul_sum, ← smul_mul_assoc, smul_monomial, Finset.sum_comm (t:=G''), ← Finset.sum_mul, smul_eq_mul (α := R)] at h_sum_sPoly /- With the assumption that $f(g)$ vanishes when $g ∉ G'$ and $G'' ⊆ G'$, we have $$p = ∑ g ∈ G' with (degree(f(g) * g) = a), leadingTerm(f(g)) * g + ∑ g ∈ G', (f(g) - lt'(g)) * g = ∑ g ∈ G' with (degree(f(g) * g) = a), leadingTerm(f(g)) * g + ∑ g ∈ G'', (f(g) - lt'(g)) * g = ∑ g ∈ G'', (∑ g₁, g₂ ∈ \{g ∈ G' | degree(f(g) * g) = a\}, c(g₁, g₂)•(lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂)) / lcm(lm(g₁), lm(g₂))) * q_{g₁, g₂}(g)) * g + ∑ g ∈ G'', (f(g) - lt'(g)) * g = ∑ g ∈ G'', (∑ g₁, g₂ ∈ \{g ∈ G' | degree(f(g) * g) = a\}, c(g₁, g₂)•(lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂)) / lcm(lm(g₁), lm(g₂))) * q_{g₁, g₂}(g) + (f(g) - lt'(g))) * g.$$ -/ convert_to p = _ + ∑ g ∈ G'', (f g - lt' g) * g using 2 at hp · exact Finset.sum_subset (by simp [G'']) (by simp_intro .. [hf₀support, lt']) simp_rw [h_sum_sPoly, ← Finset.sum_add_distrib, ← add_mul] at hp /- Let $f'(g)$ be $$∑ g₁, g₂ ∈ \{g ∈ G' | degree(f(g) * g) = a\}, c(g₁, g₂)•(lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂)) / lcm(lm(g₁), lm(g₂))) * q_{g₁, g₂}(g) + (f(g) - lt'(g)),$$ and $a'$ be $max(degree(p), max_{g ∈ G''} f'(g) * g)$. Then we have $p = ∑ g ∈ G'', f'(g) * g$, and apparently $degree(p) ≤ a'$ and $∀ g ∈ G'', degree(f'(g) * g) ≤ a'$. Now both $degree(p) ≤ a'$ and $P(a')$ are got. To prove the theorem, it remains to prove that $a' < a$. -/ -- use `by exact hp` to assign a long expression (which we don't want to write) to `?f'` refine ⟨m.toSyn (m.degree p) ⊔ G''.sup fun g ↦ m.toSyn <| m.degree <| ?f' g * g.val, (?_ : _ < _), by simp, ?f', G'', by exact hp, ?le_max⟩ case le_max => intro h g rw [mul_comm] exact le_trans (Finset.le_sup (f := fun g ↦ m.toSyn <| m.degree (?f' g * g.val)) g) le_sup_right /- It suffices that $degree(f'(g) * g) < a$ for all $g ∈ G''$. Then it suffices that, degrees of the left side (too long...) and the right side $f(g) - lt'(g)$ of the outermost $+$ in $f'$ multiplied by $g$ respectively are both less than $a$ for all $g ∈ G''$. -/ clear hp h_sum_sPoly -- remove them since they're long and will not be used anymore simp? [ha, Finset.sup_lt_iff h_a_gt_zero, add_mul, -Subtype.forall] says simp only [Finset.univ_eq_attach, mul_one, add_mul, sup_lt_iff, ha, Finset.sup_lt_iff h_a_gt_zero, true_and] intro g hg' apply lt_of_le_of_lt degree_add_le apply max_lt · /- To prove the left side, it suffices to show $degree(c(g₁, g₂)•(lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂)) / lcm(lm(g₁), lm(g₂))) * q_{g₁, g₂}(g) * g) < a$ for all $g₁, g₂ ∈ \{g ∈ G' | degree(f(g) * g) = a\}$ (`g₁`, `g₂`). -/ simp_rw [Finset.sum_mul] refine lt_of_le_of_lt m.degree_sum_le <| (Finset.sup_lt_iff h_a_gt_zero).mpr ?_ simp? [-Finset.mem_filter, -Subtype.forall] says simp only [Finset.mem_attach, forall_const] intro g₁ refine lt_of_le_of_lt m.degree_sum_le <| (Finset.sup_lt_iff h_a_gt_zero).mpr ?_ simp? [-Finset.mem_filter, -Subtype.forall] says simp only [Finset.mem_attach, forall_const] intro g₂ /- Without loss of generality, we assume $sPoly(g₁, g₂) ≠ 0$. (If it is $0$, then $q_{g₁, g₂} = 0$). $$degree( c(g₁, g₂) • (lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂)) / lcm(lm(g₁), lm(g₂))) * q_{g₁, g₂}(g) * g) ≤ degree(lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂))) - degree(lcm(lm(g₁), lm(g₂))) + degree(q_{g₁, g₂}(g) * g)$$ -/ obtain ⟨h_deg_gq_le_sPoly, h_q_eq_0_of_sPoly_eq_0⟩ := hq g₁ g₂ g wlog! hsPoly_ne_0 : m.sPolynomial g₁.val.val g₂.val.val ≠ 0 generalizing · suffices (q g₁ g₂) g = 0 by simp [this, h_a_gt_zero] rw [← mul_left_mem_nonZeroDivisors_eq_zero_iff <| m.mem_nonZeroDivisors_of_leadingCoeff_mem_nonZeroDivisors hG₀, h_q_eq_0_of_sPoly_eq_0 hsPoly_ne_0] rw [mul_assoc] apply lt_of_le_of_lt degree_mul_le rw [AddEquiv.map_add] refine add_lt_of_add_lt_right ?_ (degree_monomial_le _) /- $$... ≤ degree(lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂))) - degree(lcm(lm(g₁), lm(g₂))) + degree(sPoly(g₁, g₂))$$ -/ apply lt_of_le_of_lt (add_le_add_right (mul_comm g.val (q _ _ g) ▸ h_deg_gq_le_sPoly) _) /- $$... < degree(lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂))) - degree(lcm(lm(g₁), lm(g₂))) + degree(lcm(lm(g₁), lm(g₂)))$$ -/ apply lt_of_lt_of_le (add_lt_add_right (m.degree_sPolynomial_lt_sup_degree hsPoly_ne_0) _) /- $$... = degree(lcm(lm(f(g₁) * g₁), lm(f(g₂) * g₂)))$$ -/ rw [← AddEquiv.map_add, tsub_add_cancel_of_le <| sup_le_sup (by simp) (by simp)] /- $$... ≤ a.$$ -/ have hfgg₁ := (G'.mem_filter.mp g₁.2).2 have hfgg₂ := (G'.mem_filter.mp g₂.2).2 unfold degFgEqA at hfgg₁ hfgg₂ rw [degree_mul_of_right_mem_nonZeroDivisors _ hG₀, ← m.toSyn.eq_symm_apply] at hfgg₁ hfgg₂ · simp [hfgg₁, hfgg₂] all_goals by_contra! hfg0 simp [hfg0, h_a_gt_zero.ne] at hfgg₁ hfgg₂ · /- It is easy to prove $degree(f(g) - lt'(g)) < a$. -/ wlog h : degFgEqA g · by_cases hg'G' : g ∈ G' · simp [h, lt', lt_of_le_of_ne (mul_comm (f g) g ▸ h_deg_le g hg'G') h] · simp [hg'G', h_a_gt_zero, lt', hf₀support] simp? [h, lt'] says simp only [h, ↓reduceIte, lt'] wlog! +distrib hLTgg' : f g - m.leadingTerm (f g) ≠ 0 · simp [hLTgg', h_a_gt_zero] rw [← h] at ⊢ h_a_gt_zero apply ne_of_lt at h_a_gt_zero rw [ne_eq, eq_comm, toSyn_eq_zero_iff] at h_a_gt_zero have : f g ≠ 0 := by have := m.ne_zero_of_degree_ne_zero h_a_gt_zero contrapose! this simp [this] simp [degree_mul_of_right_mem_nonZeroDivisors hLTgg' hG₀, degree_mul_of_right_mem_nonZeroDivisors this hG₀, m.degree_sub_leadingTerm_lt_degree (m.degree_ne_zero_of_sub_leadingTerm_ne_zero hLTgg')] theorem isGroebnerBasis_iff_isRemainder_sPolynomial_zero₀ {G : Set (MvPolynomial σ R)} (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g) ∨ g = 0) : m.IsGroebnerBasis G (Ideal.span G) ↔ ∀ (g₁ g₂ : G), m.IsRemainder (m.sPolynomial g₁ g₂ : MvPolynomial σ R) G 0 := by rw [← isGroebnerBasis_sdiff_singleton_zero, ← Ideal.span_sdiff_singleton_zero, isGroebnerBasis_iff_isRemainder_sPolynomial_zero (G := G \ {0}) (by simp_intro _ _ [or_iff_not_imp_right.mp (hG _ _)])] simp? [imp_forall_iff, imp.swap (a := ¬(_ : MvPolynomial σ R) = 0) (b := _ ∈ G)] says simp only [isRemainder_sdiff_singleton_zero_iff_isRemainder, Subtype.forall, Set.mem_diff, Set.mem_singleton_iff, ne_eq, and_imp, imp_forall_iff, imp.swap (a := ¬(_ : MvPolynomial σ R) = 0) (b := _ ∈ G)] congr! with p q - - by_cases! h : p = 0 ∨ q = 0 · rcases h with h | h <;> simp [h] simp [h] /-- Buchberger Criterion: a basis of an ideal is a Gröbner basis of it if and only if any remainder of echo sPolynomial between two polynomials on the basis is 0. It is a variant of `MonomialOrder.IsGroebnerBasis.isGroebnerBasis_iff_isRemainder_sPolynomial_zero`. -/ theorem isGroebnerBasis_iff_forall_isRemainder_sPolynomial_zero {G : Set (MvPolynomial σ R)} (hG : ∀ g ∈ G, IsUnit (m.leadingCoeff g)) : m.IsGroebnerBasis G (Ideal.span G) ↔ ∀ (g₁ g₂ : G) (r : MvPolynomial σ R), m.IsRemainder (m.sPolynomial g₁ g₂ : MvPolynomial σ R) G r → r = 0 := by constructor · intro h g₁ g₂ r hr apply (remainder_eq_zero_iff_mem_ideal h hr).mpr rw [isGroebnerBasis_iff_subset_ideal_and_isRemainder_zero (hG := hG)] at h apply m.sPolynomial_mem_ideal <;> exact Set.mem_of_subset_of_mem h.1 (by simp) · rw [isGroebnerBasis_iff_isRemainder_sPolynomial_zero (hG := hG)] intro h g₁ g₂ obtain ⟨r, hr⟩ := exists_isRemainder hG (m.sPolynomial (R := R) ↑g₁ ↑g₂) rwa [h g₁ g₂ r hr] at hr -- todo: avoid requiring `hG` lemma _root_.MonomialOrder.Embedding.isGroebnerBasis_iff_isGroebnerBasis_rename {σ'} {m' : MonomialOrder σ'} {m : MonomialOrder σ} (e : Embedding m' m) (G : Set (MvPolynomial σ' R)) (hG : ∀ g ∈ G, IsUnit (m'.leadingCoeff g)) (I : Ideal (MvPolynomial σ' R)) : m'.IsGroebnerBasis G I ↔ m.IsGroebnerBasis (MvPolynomial.rename e '' G) (I.map (MvPolynomial.rename e)) := by classical rw [isGroebnerBasis_iff_ideal_eq_span_and_isGroebnerBasis_span (hG := hG), isGroebnerBasis_iff_isRemainder_sPolynomial_zero (hG := hG), isGroebnerBasis_iff_ideal_eq_span_and_isGroebnerBasis_span (hG := by simpa using hG), isGroebnerBasis_iff_isRemainder_sPolynomial_zero (hG := by simpa using hG), and_congr] · constructor · intro rfl rw [Ideal.map_span] · intro h apply congrArg (Ideal.map (killCompl e.coe_injective)) at h simpa [Ideal.map_mapₐ, killCompl_comp_rename, Ideal.map_span, ← Set.image_comp] using h · simp [e.sPolynomial_rename, e.isRemainder_iff_isRemainder_rename] -- todo: avoid requiring `hG` lemma _root_.MonomialOrder.Embedding.isGroebnerBasis_iff_isGroebnerBasis_rename₀ {σ'} {m' : MonomialOrder σ'} {m : MonomialOrder σ} (e : Embedding m' m) (G : Set (MvPolynomial σ' R)) (hG : ∀ g ∈ G, IsUnit (m'.leadingCoeff g) ∨ g = 0) (I : Ideal (MvPolynomial σ' R)) : m'.IsGroebnerBasis G I ↔ m.IsGroebnerBasis (MvPolynomial.rename e '' G) (I.map (MvPolynomial.rename e)) := by rw [← isGroebnerBasis_sdiff_singleton_zero, e.isGroebnerBasis_iff_isGroebnerBasis_rename (hG := by simp_intro .. [or_iff_not_imp_right.mp (hG _ _)]), Set.image_diff (rename_injective _ e.coe_injective)] simp -- lemma _root_.MonomialOrder.Embedding.isGroebnerBasis_iff_isGroebnerBasis_rename'' {σ'} -- {m' : MonomialOrder σ'} {m : MonomialOrder σ} -- (e : Embedding m' m) (G : Set (MvPolynomial σ' R)) -- (I : Ideal (MvPolynomial σ' R)) : -- m'.IsGroebnerBasis G I ↔ -- m.IsGroebnerBasis (MvPolynomial.rename e '' G) (I.map (MvPolynomial.rename e)) := by -- classical -- apply and_congr -- · refine ⟨fun h ↦ subset_trans (Set.image_mono h) Ideal.subset_span, ?_⟩ -- intro h -- apply Set.image_mono (f := killCompl e.coe_injective) at h -- apply (subset_trans · Ideal.subset_span) at h -- rw [← Ideal.map, Ideal.map_mapₐ, Set.image_image] at h -- simpa [killCompl_comp_rename] using h -- · simp_rw [Set.image_image, e.leadingTerm_rename, ← Set.image_image] -- #check Submodule.exists_finset_of_mem_iSup -- sorry end CommRing section Field variable {k : Type*} [Field k] {σ : Type*} {m : MonomialOrder σ} /-- A set of polynomials is a Gröbner basis of an ideal if and only if it is a subset of this ideal and 0 is a remainder of each member of this ideal on division by this set. It is a variant of `MonomialOrder.IsGroebnerBasis.isGroebnerBasis_iff_subset_ideal_and_isRemainder_zero`, over a field and without hypothesis on leading coefficients in the set. -/ theorem isGroebnerBasis_iff_subset_ideal_and_isRemainder_zero' (G : Set (MvPolynomial σ k)) (I : Ideal (MvPolynomial σ k)) : m.IsGroebnerBasis G I ↔ G ⊆ I ∧ ∀ p ∈ I, m.IsRemainder p G 0 := isGroebnerBasis_iff_subset_ideal_and_isRemainder_zero₀ G I (by simp [em']) lemma isRemainder_zero_iff_mem_ideal' {p : MvPolynomial σ k} {G : Set (MvPolynomial σ k)} {I : Ideal (MvPolynomial σ k)} (h : m.IsGroebnerBasis G I) : m.IsRemainder p G 0 ↔ p ∈ I := by refine isRemainder_zero_iff_mem_ideal₀ ?_ h simp [em'] /-- Buchberger Criterion: a basis of an ideal is a Gröbner basis of it if and only if any remainder of echo sPolynomial between two polynomials on the basis is 0. It is a variant of `MonomialOrder.IsGroebnerBasis.isGroebnerBasis_iff_isRemainder_sPolynomial_zero`. -/ theorem isGroebnerBasis_iff_isRemainder_sPolynomial_zero' (G : Set (MvPolynomial σ k)) : m.IsGroebnerBasis G (Ideal.span G) ↔ ∀ (g₁ g₂ : G) (r : MvPolynomial σ k), m.IsRemainder (m.sPolynomial g₁ g₂ : MvPolynomial σ k) G r → r = 0 := by constructor · intro h g₁ g₂ r hr apply (remainder_eq_zero_iff_mem_ideal h hr).mpr rw [isGroebnerBasis_iff_subset_ideal_and_isRemainder_zero'] at h apply m.sPolynomial_mem_ideal <;> exact Set.mem_of_subset_of_mem h.1 (by simp) · rw [isGroebnerBasis_iff_isRemainder_sPolynomial_zero₀ (hG := by simp [em'])] intro h g₁ g₂ obtain ⟨r, hr⟩ := exists_isRemainder' G (m.sPolynomial (R := k) ↑g₁ ↑g₂) rwa [h g₁ g₂ r hr] at hr theorem isGroebnerBasis_iff_ideal_eq_span_and_isGroebnerBasis_span' (G : Set (MvPolynomial σ k)) (I : Ideal (MvPolynomial σ k)) : m.IsGroebnerBasis G I ↔ (I = Ideal.span G ∧ m.IsGroebnerBasis G (Ideal.span G)) := isGroebnerBasis_iff_ideal_eq_span_and_isGroebnerBasis_span₀ G I (by simp [em']) theorem isGroebnerBasis_iff_subset_and_degree_le_eq_and_degree_le' (G : Set (MvPolynomial σ k)) (I : Ideal (MvPolynomial σ k)) : m.IsGroebnerBasis G I ↔ G ⊆ I ∧ ∀ p ∈ I, p ≠ 0 → ∃ g ∈ G, g ≠ 0 ∧ m.degree g ≤ m.degree p := isGroebnerBasis_iff_subset_and_degree_le_eq_and_degree_le₀ I (by simp [em']) --- lemma _root_.MonomialOrder.Embedding.isGroebnerBasis_iff_isGroebnerBasis_rename {σ'} --- {m' : MonomialOrder σ'} {m : MonomialOrder σ} --- (e : Embedding m' m) (G : Set (MvPolynomial σ' R)) --- (I : Ideal (MvPolynomial σ' R)) : --- m'.IsGroebnerBasis G I ↔ --- m.IsGroebnerBasis (MvPolynomial.rename e '' G) (I.map (MvPolynomial.rename e)) := by --- classical --- apply and_congr --- · refine ⟨fun h ↦ subset_trans (Set.image_mono h) Ideal.subset_span, ?_⟩ --- intro h --- apply Set.image_mono (f := killCompl e.coe_injective) at h --- apply (subset_trans · Ideal.subset_span) at h --- rw [← Ideal.map, Ideal.map_mapₐ, Set.image_image] at h --- simpa [killCompl_comp_rename] using h --- · simp_rw [Set.image_image, e.leadingTerm_rename, ← Set.image_image] --- sorry lemma _root_.MonomialOrder.Embedding.isGroebnerBasis_iff_isGroebnerBasis_rename' {σ'} {m' : MonomialOrder σ'} {m : MonomialOrder σ} (e : Embedding m' m) (G : Set (MvPolynomial σ' k)) (I : Ideal (MvPolynomial σ' k)) : m'.IsGroebnerBasis G I ↔ m.IsGroebnerBasis (MvPolynomial.rename e '' G) (I.map (MvPolynomial.rename e)) := e.isGroebnerBasis_iff_isGroebnerBasis_rename₀ (hG := by simp [em']) .. -- todo: generalize to ring. lemma exists_isGroebnerBasis_finite_of_exists_span_finite {B : Set (MvPolynomial σ k)} (hB : B.Finite) : ∃ G : Set (MvPolynomial σ k), m.IsGroebnerBasis G (Ideal.span B) ∧ G.Finite := by classical let σ' := hB.toFinset.biUnion MvPolynomial.vars let m' := m.ofInjective (σ' := σ') (Subtype.val_injective) let emb : m'.Embedding m := MonomialOrder.Embedding.ofInjective m Subtype.val_injective have ⟨G', hG', hG'finite⟩ := exists_isGroebnerBasis_finite (m := m') ((Ideal.span B).map (killCompl emb.coe_injective)) use rename emb '' G' refine ⟨?_, hG'finite.image ..⟩ rwa [emb.isGroebnerBasis_iff_isGroebnerBasis_rename', Ideal.map_mapₐ, Ideal.map_span, AlgHom.coe_comp, Function.comp_def, Set.image_congr (g := id), Set.image_id] at hG' intro p hpB apply p.rename_killCompl_app rw [Embedding.coe_ofInjective, Subtype.range_coe, SetLike.coe_subset_coe] apply Finset.subset_biUnion_of_mem vars (hB.mem_toFinset.mpr hpB) lemma isGroebnerBasis_of_forall_finite_isGroebnerBasis' {G : Set (MvPolynomial σ k)} {I : Ideal (MvPolynomial σ k)} (h : ∀ s : Finset σ, ∃ (σ' : Type*), ∃ m' : MonomialOrder σ', ∃ e : m'.Embedding m, ↑s ⊆ Set.range e ∧ m'.IsGroebnerBasis (rename e ⁻¹' G) (I.comap (rename e))) : m.IsGroebnerBasis G I := isGroebnerBasis_of_forall_finite_isGroebnerBasis₀ (hG := by simp_intro .. [em']) h theorem isGroebnerBasis_union_of_forall_finite_isGroebnerBasis' {I : Ideal (MvPolynomial σ k)} {σ' : Finset σ → Type*} {m' : (s : Finset σ) → MonomialOrder (σ' s)} {e : (s : Finset σ) → (m' s).Embedding m} {G' : (s : Finset σ) → Set (MvPolynomial (σ' s) k)} (h : ∀ s, ↑s ⊆ Set.range (e s)) (h' : ∀ s, (m' s).IsGroebnerBasis (G' s) (I.comap <| rename (e s))) : m.IsGroebnerBasis (⋃ s : Finset σ, rename (e s) '' G' s) I := isGroebnerBasis_union_of_forall_finite_isGroebnerBasis₀ (by simp_intro .. [em']) h h' -- todo: generalize to ring? lemma isGroebnerBasis_iff_minimal (I : Ideal (MvPolynomial σ k)) {G : Set (MvPolynomial σ k)} : m.IsGroebnerBasis G I ↔ G ⊆ I ∧ {a | Minimal (· ∈ m.degree '' ((I : Set (MvPolynomial σ k)) \ {0})) a} ⊆ m.degree '' (G \ {0}) := by classical constructor · intro h rw [IsGroebnerBasis.isGroebnerBasis_iff_subset_and_degree_le_eq_and_degree_le'] at h exists h.1 intro a ha -- by_contra! h' simp at ha ⊢ obtain ⟨p, hp, rfl⟩ := ha.prop obtain ⟨g, hg⟩ := h.2 p hp.1 hp.2 refine ⟨g, ⟨hg.1, hg.2.1⟩, ?_⟩ exact ha.eq_of_le ⟨g, ⟨h.1 hg.1, hg.2.1⟩, rfl⟩ hg.2.2 · intro h rw [isGroebnerBasis_iff] exists h.1 rw [--← span_leadingTerm_sdiff_singleton_zero, ← span_leadingTerm_sdiff_singleton_zero (B := G), ← Ideal.span_le, span_leadingTerm_eq_span_monomial', span_leadingTerm_eq_span_monomial', -- span_leadingTerm_eq_span_monomial (G := G \ {0}), ← Set.image_image (g := (monomial · (1 : k))) (f := m.degree), ← Set.image_image (g := (monomial · (1 : k))) (f := m.degree), ideal_span_monomial_image_eq_ideal_span_monomial_image_minimal, --ideal_span_monomial_image_eq_ideal_span_monomial_image_minimal (s := m.degree '' (G \ {0})), Ideal.span_le] intro p rw [SetLike.mem_coe, mem_ideal_span_monomial_image, Set.mem_image] rintro ⟨a, ⟨ha, rfl⟩⟩ obtain ⟨p, ⟨hp, rfl⟩⟩ := h.2 ha simp [support_monomial] exact ⟨p, And.intro hp (le_refl (m.degree p))⟩ end Field end IsGroebnerBasis end MonomialOrder