Skip to content

Commit

Permalink
feat: Add a DecidableEq instance for Polynomial (#5942)
Browse files Browse the repository at this point in the history
Add a `DecidableEq` instance for `Polynomial` (in the presence of `DecidableEq` for coefficients).

This instance is the companion of an analogue instance for `MvPolynomial`, and it allows to use if… then… else for `Polynomial` without having to `open Classical`.

This also makes `Polynomial.instNormalizationMonoid` computable, by defining it in terms of this new instance.



Co-authored-by: Antoine Chambert-Loir <antoine.chambert-loir@math.univ-paris-diderot.fr>
Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
  • Loading branch information
3 people committed Aug 10, 2023
1 parent 96a3768 commit 057299d
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 16 deletions.
3 changes: 3 additions & 0 deletions Mathlib/Data/Polynomial/Basic.lean
Expand Up @@ -367,6 +367,9 @@ def toFinsuppIso : R[X] ≃+* AddMonoidAlgebra R ℕ where
#align polynomial.to_finsupp_iso_apply Polynomial.toFinsuppIso_apply
#align polynomial.to_finsupp_iso_symm_apply Polynomial.toFinsuppIso_symm_apply

instance [DecidableEq R] : DecidableEq (R[X]) :=
@Equiv.decidableEq R[X] _ (toFinsuppIso R).toEquiv (Finsupp.decidableEq)

end AddMonoidAlgebra

theorem ofFinsupp_sum {ι : Type*} (s : Finset ι) (f : ι → AddMonoidAlgebra R ℕ) :
Expand Down
5 changes: 2 additions & 3 deletions Mathlib/Data/Polynomial/Degree/CardPowDegree.lean
Expand Up @@ -78,9 +78,8 @@ theorem cardPowDegree_apply (p : Fq[X]) :
rfl
#align polynomial.card_pow_degree_apply Polynomial.cardPowDegree_apply

-- @[simp] -- Porting note: simp can prove this
theorem cardPowDegree_zero : cardPowDegree (0 : Fq[X]) = 0 :=
if_pos rfl
@[simp, nolint simpNF]
theorem cardPowDegree_zero : cardPowDegree (0 : Fq[X]) = 0 := rfl
#align polynomial.card_pow_degree_zero Polynomial.cardPowDegree_zero

@[simp]
Expand Down
36 changes: 23 additions & 13 deletions Mathlib/Data/Polynomial/FieldDivision.lean
Expand Up @@ -19,7 +19,7 @@ This file starts looking like the ring theory of $ R[X] $

noncomputable section

open Classical BigOperators Polynomial
open BigOperators Polynomial

namespace Polynomial

Expand Down Expand Up @@ -227,6 +227,7 @@ instance : EuclideanDomain R[X] :=

theorem mod_eq_self_iff (hq0 : q ≠ 0) : p % q = p ↔ degree p < degree q :=
fun h => h ▸ EuclideanDomain.mod_lt _ hq0, fun h => by
classical
have : ¬degree (q * C (leadingCoeff q)⁻¹) ≤ degree p :=
not_le_of_gt <| by rwa [degree_mul_leadingCoeff_inv q hq0]
rw [mod_def, modByMonic, dif_pos (monic_mul_leadingCoeff_inv hq0)]
Expand Down Expand Up @@ -313,47 +314,51 @@ section

open EuclideanDomain

theorem gcd_map [Field k] (f : R →+* k) : gcd (p.map f) (q.map f) = (gcd p q).map f :=
theorem gcd_map [Field k] [DecidableEq R] [DecidableEq k] (f : R →+* k) :
gcd (p.map f) (q.map f) = (gcd p q).map f :=
GCD.induction p q (fun x => by simp_rw [Polynomial.map_zero, EuclideanDomain.gcd_zero_left])
fun x y _ ih => by rw [gcd_val, ← map_mod, ih, ← gcd_val]
#align polynomial.gcd_map Polynomial.gcd_map

end

theorem eval₂_gcd_eq_zero [CommSemiring k] {ϕ : R →+* k} {f g : R[X]} {α : k} (hf : f.eval₂ ϕ α = 0)
theorem eval₂_gcd_eq_zero [CommSemiring k] [DecidableEq R]
{ϕ : R →+* k} {f g : R[X]} {α : k} (hf : f.eval₂ ϕ α = 0)
(hg : g.eval₂ ϕ α = 0) : (EuclideanDomain.gcd f g).eval₂ ϕ α = 0 := by
rw [EuclideanDomain.gcd_eq_gcd_ab f g, Polynomial.eval₂_add, Polynomial.eval₂_mul,
Polynomial.eval₂_mul, hf, hg, MulZeroClass.zero_mul, MulZeroClass.zero_mul, zero_add]
#align polynomial.eval₂_gcd_eq_zero Polynomial.eval₂_gcd_eq_zero

theorem eval_gcd_eq_zero {f g : R[X]} {α : R} (hf : f.eval α = 0) (hg : g.eval α = 0) :
(EuclideanDomain.gcd f g).eval α = 0 :=
theorem eval_gcd_eq_zero [DecidableEq R] {f g : R[X]} {α : R}
(hf : f.eval α = 0) (hg : g.eval α = 0) : (EuclideanDomain.gcd f g).eval α = 0 :=
eval₂_gcd_eq_zero hf hg
#align polynomial.eval_gcd_eq_zero Polynomial.eval_gcd_eq_zero

theorem root_left_of_root_gcd [CommSemiring k] {ϕ : R →+* k} {f g : R[X]} {α : k}
theorem root_left_of_root_gcd [CommSemiring k] [DecidableEq R] {ϕ : R →+* k} {f g : R[X]} {α : k}
(hα : (EuclideanDomain.gcd f g).eval₂ ϕ α = 0) : f.eval₂ ϕ α = 0 := by
cases' EuclideanDomain.gcd_dvd_left f g with p hp
rw [hp, Polynomial.eval₂_mul, hα, MulZeroClass.zero_mul]
#align polynomial.root_left_of_root_gcd Polynomial.root_left_of_root_gcd

theorem root_right_of_root_gcd [CommSemiring k] {ϕ : R →+* k} {f g : R[X]} {α : k}
theorem root_right_of_root_gcd [CommSemiring k] [DecidableEq R] {ϕ : R →+* k} {f g : R[X]} {α : k}
(hα : (EuclideanDomain.gcd f g).eval₂ ϕ α = 0) : g.eval₂ ϕ α = 0 := by
cases' EuclideanDomain.gcd_dvd_right f g with p hp
rw [hp, Polynomial.eval₂_mul, hα, MulZeroClass.zero_mul]
#align polynomial.root_right_of_root_gcd Polynomial.root_right_of_root_gcd

theorem root_gcd_iff_root_left_right [CommSemiring k] {ϕ : R →+* k} {f g : R[X]} {α : k} :
theorem root_gcd_iff_root_left_right [CommSemiring k] [DecidableEq R]
{ϕ : R →+* k} {f g : R[X]} {α : k} :
(EuclideanDomain.gcd f g).eval₂ ϕ α = 0 ↔ f.eval₂ ϕ α = 0 ∧ g.eval₂ ϕ α = 0 :=
fun h => ⟨root_left_of_root_gcd h, root_right_of_root_gcd h⟩, fun h => eval₂_gcd_eq_zero h.1 h.2
#align polynomial.root_gcd_iff_root_left_right Polynomial.root_gcd_iff_root_left_right

theorem isRoot_gcd_iff_isRoot_left_right {f g : R[X]} {α : R} :
theorem isRoot_gcd_iff_isRoot_left_right [DecidableEq R] {f g : R[X]} {α : R} :
(EuclideanDomain.gcd f g).IsRoot α ↔ f.IsRoot α ∧ g.IsRoot α :=
root_gcd_iff_root_left_right
#align polynomial.is_root_gcd_iff_is_root_left_right Polynomial.isRoot_gcd_iff_isRoot_left_right

theorem isCoprime_map [Field k] (f : R →+* k) : IsCoprime (p.map f) (q.map f) ↔ IsCoprime p q := by
classical
rw [← EuclideanDomain.gcd_isUnit_iff, ← EuclideanDomain.gcd_isUnit_iff, gcd_map, isUnit_map]
#align polynomial.is_coprime_map Polynomial.isCoprime_map

Expand All @@ -364,6 +369,7 @@ theorem mem_roots_map [CommRing k] [IsDomain k] {f : R →+* k} {x : k} (hp : p

theorem rootSet_monomial [CommRing S] [IsDomain S] [Algebra R S] {n : ℕ} (hn : n ≠ 0) {a : R}
(ha : a ≠ 0) : (monomial n a).rootSet S = {0} := by
classical
rw [rootSet, map_monomial, roots_monomial ((_root_.map_ne_zero (algebraMap R S)).2 ha),
Multiset.toFinset_nsmul _ _ hn, Multiset.toFinset_singleton, Finset.coe_singleton]
#align polynomial.root_set_monomial Polynomial.rootSet_monomial
Expand All @@ -383,6 +389,7 @@ set_option linter.uppercaseLean3 false in

theorem rootSet_prod [CommRing S] [IsDomain S] [Algebra R S] {ι : Type*} (f : ι → R[X])
(s : Finset ι) (h : s.prod f ≠ 0) : (s.prod f).rootSet S = ⋃ i ∈ s, (f i).rootSet S := by
classical
simp only [rootSet, ← Finset.mem_coe]
rw [Polynomial.map_prod, roots_prod, Finset.bind_toFinset, s.val_toFinset, Finset.coe_biUnion]
rwa [← Polynomial.map_prod, Ne, map_eq_zero]
Expand All @@ -408,7 +415,7 @@ theorem coeff_inv_units (u : R[X]ˣ) (n : ℕ) : ((↑u : R[X]).coeff n)⁻¹ =
· simp
#align polynomial.coeff_inv_units Polynomial.coeff_inv_units

theorem monic_normalize (hp0 : p ≠ 0) : Monic (normalize p) := by
theorem monic_normalize [DecidableEq R] (hp0 : p ≠ 0) : Monic (normalize p) := by
rw [Ne.def, ← leadingCoeff_eq_zero, ← Ne.def, ← isUnit_iff_ne_zero] at hp0
rw [Monic, leadingCoeff_normalize, normalize_eq_one]
apply hp0
Expand Down Expand Up @@ -450,12 +457,13 @@ theorem dvd_C_mul (ha : a ≠ 0) : p ∣ Polynomial.C a * q ↔ p ∣ q :=
set_option linter.uppercaseLean3 false in
#align polynomial.dvd_C_mul Polynomial.dvd_C_mul

theorem coe_normUnit_of_ne_zero (hp : p ≠ 0) : (normUnit p : R[X]) = C p.leadingCoeff⁻¹ := by
theorem coe_normUnit_of_ne_zero [DecidableEq R] (hp : p ≠ 0) :
(normUnit p : R[X]) = C p.leadingCoeff⁻¹ := by
have : p.leadingCoeff ≠ 0 := mt leadingCoeff_eq_zero.mp hp
simp [CommGroupWithZero.coe_normUnit _ this]
#align polynomial.coe_norm_unit_of_ne_zero Polynomial.coe_normUnit_of_ne_zero

theorem normalize_monic (h : Monic p) : normalize p = p := by simp [h]
theorem normalize_monic [DecidableEq R] (h : Monic p) : normalize p = p := by simp [h]
#align polynomial.normalize_monic Polynomial.normalize_monic

theorem map_dvd_map' [Field k] (f : R →+* k) {x y : R[X]} : x.map f ∣ y.map f ↔ x ∣ y := by
Expand All @@ -468,10 +476,11 @@ theorem map_dvd_map' [Field k] (f : R →+* k) {x y : R[X]} : x.map f ∣ y.map
map_dvd_map _ f.injective (monic_mul_leadingCoeff_inv H)]
#align polynomial.map_dvd_map' Polynomial.map_dvd_map'

theorem degree_normalize : degree (normalize p) = degree p := by simp
theorem degree_normalize [DecidableEq R] : degree (normalize p) = degree p := by simp
#align polynomial.degree_normalize Polynomial.degree_normalize

theorem prime_of_degree_eq_one (hp1 : degree p = 1) : Prime p := by
classical
have : Prime (normalize p) :=
Monic.prime_of_degree_eq_one (hp1 ▸ degree_normalize)
(monic_normalize fun hp0 => absurd hp1 (hp0.symm ▸ by simp))
Expand Down Expand Up @@ -529,6 +538,7 @@ then `f / (X - a)` is coprime with `X - a`.
Note that we do not assume `f a = 0`, because `f / (X - a) = (f - f a) / (X - a)`. -/
theorem isCoprime_of_is_root_of_eval_derivative_ne_zero {K : Type*} [Field K] (f : K[X]) (a : K)
(hf' : f.derivative.eval a ≠ 0) : IsCoprime (X - C a : K[X]) (f /ₘ (X - C a)) := by
classical
refine Or.resolve_left
(EuclideanDomain.dvd_or_coprime (X - C a) (f /ₘ (X - C a))
(irreducible_of_degree_eq_one (Polynomial.degree_X_sub_C a))) ?_
Expand Down

0 comments on commit 057299d

Please sign in to comment.