import Mathlib.Data.MvPolynomial.Basic import Mathlib.Data.MvPolynomial.Division import Mathlib.Data.MvPolynomial.CommRing import Mathlib.Algebra.BigOperators.Basic import Mathlib.Data.Finset.Basic import Mathlib.Data.Finset.Sum import Mathlib.Data.Finset.Lattice import Mathlib.Data.Finsupp.Basic import Mathlib.Data.Finsupp.Order import Mathlib.Data.Set.Basic import Mathlib.Tactic.LibrarySearch import Mathlib.Data.List.Basic import Mathlib.RingTheory.Polynomial.Basic import Basic import TermOrder import Multideg open BigOperators open Classical lemma List.filter_eq_nil' {α : Type _} {p : α→Prop} {l : List α} : l.filter (fun x => decide (p x)) = [] ↔ ∀ a ∈ l , ¬p a := by conv => enter [2, a, ha] rw [Iff.intro (decide_eq_true (p:=p a)) of_decide_eq_true] exact List.filter_eq_nil lemma List.filter_ne_nil' {α : Type _} {p : α→Prop} {l : List α} : l.filter (fun x => decide (p x)) ≠ [] ↔ ∃ a ∈ l , p a := by have := (List.filter_eq_nil' (α:=α) (p:=p) (l:=l)).not push_neg at this exact this lemma List.of_mem_filter' {α : Type _} {p : α→Prop} {a : α} {l : List α} : a ∈ l.filter (fun x => decide (p x)) → p a := by rw [Iff.intro (decide_eq_true (p:=p a)) of_decide_eq_true] exact of_mem_filter namespace MvPolynomial section MvDiv variable {σ : Type _} {s : σ →₀ ℕ} {k : Type _} [Field k] variable [term_order_class: TermOrderClass (TermOrder (σ→₀ℕ))] variable (p: MvPolynomial σ k) (G: List (MvPolynomial σ k)) set_option synthInstance.maxHeartbeats 40000 noncomputable def step: (G.toFinset →₀ MvPolynomial σ k) × MvPolynomial σ k := if p = 0 then ⟨0, 0⟩ else if hgs: ∃ g ∈ G, leading_term g∣ leading_term p then let gs := G.filter (leading_term ·∣ leading_term p) let g := gs.head! have gnonempty: gs ≠ [] := List.filter_ne_nil'.mpr hgs have hG: g ∈ G := List.mem_of_mem_filter (gs.head!_mem_self gnonempty) have hg: leading_term g ∣ leading_term p := List.of_mem_filter' (a:=g) (gs.head!_mem_self gnonempty) -- a is needed ⟨Finsupp.single ⟨g, List.mem_toFinset.mpr hG⟩ hg.choose, p - g * hg.choose⟩ else ⟨0, p⟩ def step_apply := by have key: p.step = p.step := rfl conv at key => rhs; unfold step exact key @[simp] lemma step_multideg_le: (p.step G).2.multideg ≤ p.multideg := by unfold step by_cases hp : p = 0 · -- simp? [hp] simp only [hp, zero_sub, ite_true, multideg_zero, le_refl] · by_cases hgs: ∃ g ∈ G, leading_term g∣ leading_term p ·-- simp? [hp, hgs] simp only [hp, ne_eq, hgs, dite_true, ite_false] rw [sub_eq_add_neg, neg_eq_neg_one_mul] apply multideg_add_le_left rw [←multideg_leading_term, leading_term_mul, leading_term_mul'_right] generalize_proofs _ h rw [←Exists.choose_spec h] -- simp? simp only [leading_term_neg, leading_term_1, leading_term_leading_term, neg_mul, one_mul, multideg_neg, multideg_leading_term, le_refl] -- simp only [lt_neg, leading_term_1, leading_term_leading_term, one_mul, multideg_leading_term, ne_eq, le_refl] ·-- simp? [hgs, hp] simp only [hp, ne_eq, hgs, dite_false, ite_false, le_refl] @[simp] lemma step_sub_multideg''_lt {p: MvPolynomial σ k} (G: List (MvPolynomial σ k)) (hp: p ≠ 0): multideg'' ((p.step G).2 - coeff p.multideg (p.step G).2•lm p) < multideg'' p := sub_multideg''_lt hp (step_multideg_le p G) @[simp] lemma step_zero: (0: MvPolynomial σ k).step G = ⟨0, 0⟩ := by rw [step_apply] simp only [zero_sub, ite_true] lemma ne_zero_of_step_quo_ne_zero (hp : (p.step G).2 ≠ 0) : p ≠ 0 := by by_contra h simp [h] at hp @[simp] lemma step_sub_multideg_le {p: MvPolynomial σ k} (G: List (MvPolynomial σ k)): multideg ((p.step G).2- coeff p.multideg (p.step G).2 • lm p) ≤ multideg p := sub_multideg_le (step_multideg_le p G) noncomputable def mv_div (p: MvPolynomial σ k) (G: List (MvPolynomial σ k)) : (G.toFinset →₀ MvPolynomial σ k) × MvPolynomial σ k := if hp: p = 0 then ⟨0, p⟩ else let xs_r := step p G let xs'_r' := mv_div (xs_r.2 - coeff p.multideg xs_r.2 • lm p) G ⟨xs_r.1 + xs'_r'.1, xs'_r'.2 + coeff p.multideg xs_r.2 • lm p⟩ termination_by _ => multideg'' p decreasing_by exact step_sub_multideg''_lt G hp @[reducible] noncomputable def quo: G.toFinset →₀ MvPolynomial σ k := (mv_div p G).1 @[reducible] noncomputable def rem: MvPolynomial σ k := (mv_div p G).2 def mv_div_apply := by have key: p.mv_div G = p.mv_div G := rfl nth_rewrite 2 [mv_div] at key exact key lemma quo_apply: quo p G = (mv_div p G).1 := rfl lemma rem_apply: rem p G = (mv_div p G).2 := rfl @[simp] lemma step_empty: step p [] = ⟨0, p⟩ := by rw [step_apply] -- simp? simp only [ne_eq, List.find?, List.not_mem_nil, false_and, exists_false, List.filter_nil, dite_false, ite_eq_right_iff, Prod.mk.injEq, true_and] intro hp exact hp.symm @[simp] lemma mv_div_empty (p: MvPolynomial σ k): p.mv_div [] = ⟨0, p⟩ := by rw [mv_div_apply] -- simp? simp only [ne_eq, step_empty, zero_add, dite_eq_ite, ite_eq_left_iff, Prod.mk.injEq] intro hp rw [mv_div_empty (p - coeff (multideg p) p • lm p)] -- simp? simp only [ne_eq, sub_add_cancel, and_self] termination_by mv_div_empty p => multideg'' p decreasing_by -- ↓↓↓ Workaround to make lean remember the instance ↓↓↓ let term_order_class := term_order_class -- Why should I do that?????? exact sub_multideg''_lt hp le_rfl @[simp] lemma rem_empty (p: MvPolynomial σ k): rem p [] = p := by -- simp? [rem_apply] simp only [rem_apply, mv_div_empty] @[simp] lemma quo_empty (p: MvPolynomial σ k): quo p [] = 0 := by simp only [quo_apply, mv_div_empty] @[simp] lemma mv_div_zero: (0: MvPolynomial σ k).mv_div G = ⟨0, 0⟩ := by rw [mv_div_apply] simp only [step_zero, multideg_zero, coeff_zero, zero_smul, sub_self, zero_add, add_zero, Prod.mk.eta, dite_eq_ite, ite_true] @[simp] lemma quo_zero: quo (0: MvPolynomial σ k) G = 0 := by simp only [quo_apply, mv_div_zero] @[simp] lemma rem_zero: rem (0: MvPolynomial σ k) G = 0 := by simp only [rem_apply, mv_div_zero] lemma step_quo_sum_add_rem: (p.step G).1.sum (·*·) + (p.step G).2 = p := by unfold step by_cases hp: p = 0 · --simp? [hp] simp only [hp, zero_sub, ite_true, add_zero] rw [Finsupp.sum_zero_index] -- simp only [hp, zero_sub, ite_true, Finsupp.sum_zero_index, add_zero] · by_cases hg: ∃ g, g ∈ G ∧ leading_term g ∣ leading_term p · -- simp? [hp, hg] simp only [hp, ne_eq, hg, dite_true, ite_false, mul_zero, Finsupp.sum_single_index, add_sub_cancel'_right] · --simp? [hp, hg] simp only [hp, ne_eq, hg, dite_false, ite_false, zero_add] rw [Finsupp.sum_zero_index, zero_add] @[simp] lemma step_quo_sum_eq_sub_rem: (p.step G).1.sum (·*·) = p - (p.step G).2 := by rw [sub_eq_of_eq_add] exact (step_quo_sum_add_rem p G).symm @[simp] lemma quo_sum_eq_sub_rem (p: MvPolynomial σ k) (G: List (MvPolynomial σ k)): (p.quo G).sum (·*·) = p - p.rem G := by rw [quo_apply, rem_apply, mv_div_apply] by_cases hp: p = 0 ·-- simp? [hp] simp only [hp, multideg_zero, dite_eq_ite, ite_true, Finsupp.sum_zero_index, sub_self] ·-- simp? [hp] simp only [hp, ne_eq, dite_eq_ite, ite_false] rw [Finsupp.sum_add_index] · -- rw [←quo_apply] rw [quo_sum_eq_sub_rem ((step p G).snd - coeff (multideg p) (step p G).snd • lm p) G, step_quo_sum_eq_sub_rem] ring ·-- simp? simp only [ne_eq, Finset.mem_union, Finsupp.mem_support_iff, mul_zero, implies_true, Subtype.forall, forall_const] · intros a _ b₁ b₂ exact mul_add (↑a: MvPolynomial σ k) b₁ b₂ termination_by _ => multideg'' p decreasing_by exact step_sub_multideg''_lt G hp theorem quo_quo_sum_add_rem: (p.quo G).sum (·*·) + p.rem G = p := by -- simp? simp only [quo_sum_eq_sub_rem, sub_add_cancel] @[simp] lemma step_multideg''_quo_mul_le (hq: q ∈ G) : (q * ((p.step G).1 ⟨q, List.mem_toFinset.mpr hq⟩)).multideg'' ≤ p.multideg'' := by rw [step_apply] by_cases hp: p = 0 ·simp [hp] · -- simp? [hp] simp only [hp, ne_eq, ite_false, mul_eq_zero] by_cases hg: ∃ g, g ∈ G ∧ leading_term g ∣ leading_term p ·-- simp? [hg, Finsupp.single_apply] simp only [hg, dite_true, ne_eq, Subtype.mk.injEq, Finsupp.single_apply, mul_ite, mul_zero, ite_eq_right_iff, mul_eq_zero] let g := List.head! (G.filter (fun x => decide (leading_term x ∣ leading_term p))) by_cases hg : g = q · -- simp? [hg] simp only [hg, ite_true, mul_eq_zero, ne_eq, ge_iff_le] generalize_proofs _ h rw [←multideg''_leading_term, leading_term_mul'_right, multideg''_leading_term, ←h.choose_spec, multideg''_leading_term] ·simp [hg] ·simp [hg] theorem multideg''_quo_mul_le (p : MvPolynomial σ k) (G : List (MvPolynomial σ k)) (q: MvPolynomial σ k) (hq: q ∈ G): (q * (p.quo G ⟨q, List.mem_toFinset.mpr hq⟩)).multideg'' ≤ p.multideg'' := by rw [quo_apply] unfold mv_div by_cases hp: p = 0 · -- simp? [hp] simp only [hp, multideg''_zero, dite_eq_ite, ite_true, Finsupp.coe_zero, Pi.zero_apply, mul_zero, le_refl] · -- simp? [hp] simp only [hp, ne_eq, dite_eq_ite, ite_false, Finsupp.coe_add, Pi.add_apply, mul_eq_zero] rw [mul_add] apply le_trans multideg''_add_le -- simp? [step_multideg''_quo_mul_le p G hq] simp only [mul_eq_zero, ne_eq, ge_iff_le, max_le_iff, step_multideg''_quo_mul_le p G hq, true_and] -- Why step_multideg_quo_mul_le not work? rw [←quo_apply] apply le_trans (multideg''_quo_mul_le ((p.step G).2 - (p.step G).2.coeff (multideg p) • lm p) G q hq) exact le_of_lt (step_sub_multideg''_lt G hp) termination_by _ => multideg'' p decreasing_by exact step_sub_multideg''_lt G hp lemma step_eq_iff (hp : p ≠ 0): (p.step G).2 = p ↔ ∀ g ∈ G, g ≠ 0 → ¬ LE.le (α:=σ→₀ℕ) g.multideg p.multideg := by constructor · intros h g hg hg' -- simp? [step_apply, hp] at h simp only [step_apply, ne_eq, multideg_eq_zero_iff, not_exists, hp, ite_false] at h by_cases hg's : ∃ g, g ∈ G ∧ leading_term g ∣ leading_term p · simp [hg's] at h -- simp [step_quo_ne_zero'' p G hp hg's] at h -- simp [step_quo_dvd_choose p G hp hg's] at h -- simp only [hg's, dite_true, sub_eq_self, mul_eq_zero, -- ne_eq, multideg_eq_zero_iff, not_exists] at h let g's := G.filter (leading_term ·∣ leading_term p) have gnonempty: g's ≠ [] := List.filter_ne_nil'.mpr (hg's) have := List.of_mem_filter (List.head!_mem_self gnonempty) have key := of_decide_eq_true this cases' h with h h · exfalso rw [h] at key simp [hp, monomial_dvd_monomial, leading_term_def] at key · exfalso have key := h ▸ key.choose_spec simp [hp] at key · push_neg at hg's specialize hg's g hg simp [leading_term_def, hg', hp, monomial_dvd_monomial] at hg's rw [imp_iff_not_or] at hg's cases' hg's with hg's hg's ·exact hg's · exfalso rw [dvd_iff_exists_eq_mul_left, not_exists] at hg's apply hg's (p.leading_coeff / g.leading_coeff) rw [div_mul_cancel _ (g.leading_coeff_eq_zero_iff.not.mpr hg')] · intros hg simp [step_apply, hp] by_cases hg's : ∃ g, g ∈ G ∧ leading_term g ∣ leading_term p · exfalso rcases hg's with ⟨g',hg',hg'p⟩ simp [monomial_dvd_monomial, leading_term_def, hp] at hg'p simp [(not_imp_not.mp (hg g' hg')) hg'p.1, hp] at hg'p · simp [hg's, hg] lemma step_multideg_eq_iff_eq (h : (p.step G).2 ≠ 0): (p.step G).2.multideg = p.multideg ↔ (p.step G).2 = p := by have hp := ne_zero_of_step_quo_ne_zero p G h simp [step, hp, h] by_cases hg : ∃ g, g ∈ G ∧ leading_term g ∣ leading_term p · simp [hg, hp, step_apply] at h simp [hg] generalize_proofs _ hdvd have hp' : p.leading_term ≠ 0 := p.leading_term_eq_zero_iff.not.mpr hp rw [hdvd.choose_spec] at hp' simp at hp' simp [hp'] let g := List.head! (G.filter (leading_term · ∣ leading_term p)) have : p.leading_term = leading_term (g * hdvd.choose) := by rw [leading_term_mul'_right, ←hdvd.choose_spec] rw [leading_term_leading_term] refine ne_of_lt ((multideg_sub_lt_left_iff ?_ h).mpr this) apply le_of_eq nth_rewrite 1 [leading_term_def] at this -- Why rw not work? nth_rewrite 1 [leading_term_def] at this rw [monomial_eq_monomial_iff] at this simp [hp] at this exact this.1.symm · simp [hg] lemma step_multideg''_eq_iff : (p.step G).2.multideg'' = p.multideg'' ↔ (p.step G).2 = p := by by_cases hstep : (p.step G).2 = 0 · by_cases hp : p = 0 · simp [multideg''_def, hp, hstep] · simp [multideg''_def, hp, hstep] rw [(⟨symm, symm⟩ : Iff (p=0) (0=p))] at hp exact hp · simp [multideg''_def, hstep, ne_zero_of_step_quo_ne_zero p G hstep] exact step_multideg_eq_iff_eq p G hstep lemma step_multideg_eq_iff (h : (p.step G).2 ≠ 0): (p.step G).2.multideg = p.multideg ↔ ∀ g ∈ G, g ≠ 0 → ¬ LE.le (α:=σ→₀ℕ) g.multideg p.multideg := Trans.trans (step_multideg_eq_iff_eq p G h) (step_eq_iff p G (ne_zero_of_step_quo_ne_zero p G h)) theorem rem_support (p : MvPolynomial σ k) (G : List (MvPolynomial σ k)) {g : MvPolynomial σ k} (h : g ∈ G) (h' : g ≠ 0): ∀ s ∈ (p.rem G).support, ¬ LE.le (α:=σ→₀ℕ) g.multideg s := by intros s hs -- rw [rem_apply, mv_div_apply] at hs' by_cases hp : p = 0 · -- why simp [hp] at hs not work?? rw [hp, rem_zero, support_zero] at hs exfalso exact Finset.not_mem_empty s hs · -- workaround rw [rem_apply, mv_div_apply] at hs -- simp? only [hp] at hs -- simp? only [←rem_apply] at hs -- simp? at hs -- simp? [hp, ←rem_apply, -coeff_smul] at hs simp only [ne_eq, multideg_eq_zero_iff, not_exists, hp, rem_apply, dite_eq_ite, ite_false, mem_support_iff, coeff_add] at hs -- simp? only [coeff_smul] at hs -- set_option synthInstance.etaExperiment true in rw [coeff_smul] at hs -- simp? at hs rw [smul_eq_mul] at hs have hnext := rem_support ((step p G).snd - (p.step G).2.coeff p.multideg • p.lm) G h h' s -- simp? at hnext simp only [ne_eq, mem_support_iff, not_imp_not] at hnext by_contra tmp simp only [ne_eq, hp, hnext tmp , zero_add, mul_eq_zero] at hs push_neg at hs cases' hs with hs₁ hs₂ -- simp? [hp, lm, multideg'_eq_multideg hp] at hs₂ simp only [lm, ne_eq, hp, not_false_eq_true, multideg'_eq_multideg hp, dite_eq_ite, ite_true, coeff_monomial, ite_eq_right_iff, one_ne_zero, not_forall, exists_prop, and_true] at hs₂ have : (step p G).snd ≠ 0 := by by_contra h simp [h] at hs₁ apply not_not.mpr tmp refine hs₂ ▸ (step_multideg_eq_iff p G this).mp ?_ g h h' exact eq_of_le_of_not_lt (step_multideg_le p G) (not_lt_of_le (le_multideg_of_coeff_ne_zero hs₁)) termination_by _ => multideg'' p decreasing_by exact step_sub_multideg''_lt G hp variable (G': Finset (MvPolynomial σ k)) def is_rem (r: MvPolynomial σ k) := (∀ g ∈ G', g ≠ 0 → ∀ s ∈ r.support, ¬LE.le (α:=σ→₀ℕ) g.multideg s) ∧ ∃(q : G' →₀ MvPolynomial σ k), (∀(g: MvPolynomial σ k) (hg : g ∈ G'), (g * q ⟨g, hg⟩).multideg'' ≤ p.multideg'' )∧ p = q.sum (·*·) + r theorem rem_is_rem : is_rem p G.toFinset (p.rem G) := by constructor · intro g hg exact rem_support p G (List.mem_toFinset.mp hg) · use p.quo G constructor · intros g hg exact multideg''_quo_mul_le p G g (List.mem_toFinset.mp hg) · exact (quo_quo_sum_add_rem p G).symm lemma rem_is_rem' : is_rem p G' (p.rem G'.toList) := by have := rem_is_rem p G'.toList simp at this exact this theorem exists_rem : ∃ r : MvPolynomial σ k, is_rem p G' r := by use p.rem G'.toList simp only [rem_is_rem'] end MvDiv end MvPolynomial