Skip to content

Commit e2a1cd1

Browse files
committed
feat(Algebra/Polynomial): small and useful lemmas (#29956)
1 parent 68b37c8 commit e2a1cd1

File tree

16 files changed

+261
-85
lines changed

16 files changed

+261
-85
lines changed

Mathlib/Algebra/Polynomial/AlgebraMap.lean

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -479,10 +479,9 @@ theorem isRoot_of_eval₂_map_eq_zero (hf : Function.Injective f) {r : R} :
479479
apply hf
480480
rw [← eval₂_hom, h, f.map_zero]
481481

482-
theorem isRoot_of_aeval_algebraMap_eq_zero [Algebra R S] {p : R[X]}
483-
(inj : Function.Injective (algebraMap R S)) {r : R} (hr : aeval (algebraMap R S r) p = 0) :
484-
p.IsRoot r :=
485-
isRoot_of_eval₂_map_eq_zero inj hr
482+
theorem isRoot_of_aeval_algebraMap_eq_zero [Algebra R S] [FaithfulSMul R S] {p : R[X]} {r : R}
483+
(hr : p.aeval (algebraMap R S r) = 0) : p.IsRoot r :=
484+
isRoot_of_eval₂_map_eq_zero (FaithfulSMul.algebraMap_injective _ _) hr
486485

487486
end Semiring
488487

Mathlib/Algebra/Polynomial/Basic.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,9 @@ theorem C_0 : C (0 : R) = 0 := by simp
459459
theorem C_1 : C (1 : R) = 1 :=
460460
rfl
461461

462+
theorem C_ofNat (n : ℕ) [n.AtLeastTwo] : C ofNat(n) = (ofNat(n) : R[X]) :=
463+
rfl
464+
462465
theorem C_mul : C (a * b) = C a * C b :=
463466
C.map_mul a b
464467

Mathlib/Algebra/Polynomial/Degree/Lemmas.lean

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,39 @@ theorem natDegree_map_eq_iff {f : R →+* S} {p : Polynomial R} :
271271
· simp_rw [h, ne_eq, or_true, iff_true, ← Nat.le_zero, ← h, natDegree_map_le]
272272
simp_all [natDegree, WithBot.unbotD_eq_unbotD_iff]
273273

274+
theorem degree_map_eq_of_isUnit_leadingCoeff [Nontrivial S] (f : R →+* S)
275+
(hp : IsUnit p.leadingCoeff) : (p.map f).degree = p.degree :=
276+
degree_map_eq_of_leadingCoeff_ne_zero _ <| f.isUnit_map hp |>.ne_zero
277+
278+
theorem natDegree_map_eq_of_isUnit_leadingCoeff [Nontrivial S] (f : R →+* S)
279+
(hp : IsUnit p.leadingCoeff) : (p.map f).natDegree = p.natDegree :=
280+
natDegree_eq_natDegree <| degree_map_eq_of_isUnit_leadingCoeff _ hp
281+
282+
theorem leadingCoeff_map_eq_of_isUnit_leadingCoeff [Nontrivial S] (f : R →+* S)
283+
(hp : IsUnit p.leadingCoeff) : (p.map f).leadingCoeff = f p.leadingCoeff :=
284+
leadingCoeff_map_of_leadingCoeff_ne_zero _ <| f.isUnit_map hp |>.ne_zero
285+
286+
theorem nextCoeff_map_eq_of_isUnit_leadingCoeff [Nontrivial S] (f : R →+* S)
287+
(hp : IsUnit p.leadingCoeff) : (p.map f).nextCoeff = f p.nextCoeff :=
288+
nextCoeff_map_of_leadingCoeff_ne_zero _ <| f.isUnit_map hp |>.ne_zero
289+
290+
theorem degree_map_eq_of_injective {f : R →+* S} (hf : Function.Injective f) (p : Polynomial R) :
291+
(p.map f).degree = p.degree := by
292+
simp [hf, map_ne_zero_iff, ne_or_eq]
293+
294+
theorem natDegree_map_eq_of_injective {f : R →+* S} (hf : Function.Injective f) (p : Polynomial R) :
295+
(p.map f).natDegree = p.natDegree :=
296+
natDegree_eq_of_degree_eq <| degree_map_eq_of_injective hf _
297+
298+
theorem leadingCoeff_map_of_injective {f : R →+* S} (hf : Function.Injective f)
299+
(p : Polynomial R) : (p.map f).leadingCoeff = f p.leadingCoeff := by
300+
simp only [leadingCoeff, natDegree_map_eq_of_injective hf, coeff_map]
301+
302+
theorem nextCoeff_map {f : R →+* S} (hf : Function.Injective f) (p : Polynomial R) :
303+
(p.map f).nextCoeff = f p.nextCoeff := by
304+
simp only [hf, nextCoeff, natDegree_map_eq_of_injective]
305+
split_ifs <;> simp
306+
274307
theorem natDegree_pos_of_nextCoeff_ne_zero (h : p.nextCoeff ≠ 0) : 0 < p.natDegree := by
275308
grind [nextCoeff]
276309

@@ -323,6 +356,13 @@ lemma natDegree_eq_one : p.natDegree = 1 ↔ ∃ a ≠ 0, ∃ b, C a * X + C b =
323356
· rintro ⟨a, ha, b, rfl⟩
324357
simp [ha]
325358

359+
theorem subsingleton_isRoot_of_natDegree_eq_one [IsLeftCancelMulZero R] [IsRightCancelAdd R]
360+
(h : p.natDegree = 1) : { x | IsRoot p x }.Subsingleton := by
361+
intro r₁
362+
obtain ⟨r₂, hr₂, r₃, rfl⟩ : ∃ a, a ≠ 0 ∧ ∃ b, C a * X + C b = p := by rwa [natDegree_eq_one] at h
363+
have (x y : R) := mul_left_cancel₀ hr₂ (b := x) (c := y)
364+
grind [IsRoot, eval_add, eval_mul_X, eval_C]
365+
326366
variable [NoZeroDivisors R]
327367

328368
theorem degree_mul_C (a0 : a ≠ 0) : (p * C a).degree = p.degree := by
@@ -357,6 +397,14 @@ theorem leadingCoeff_comp (hq : natDegree q ≠ 0) :
357397
leadingCoeff (p.comp q) = leadingCoeff p * leadingCoeff q ^ natDegree p := by
358398
rw [← coeff_comp_degree_mul_degree hq, ← natDegree_comp, coeff_natDegree]
359399

400+
@[simp]
401+
theorem nextCoeff_C_mul : (C a * p).nextCoeff = a * p.nextCoeff := by
402+
by_cases h₀ : a = 0 <;> simp [h₀, nextCoeff, natDegree_C_mul]
403+
404+
@[simp]
405+
theorem nextCoeff_mul_C : (p * C a).nextCoeff = p.nextCoeff * a := by
406+
by_cases h₀ : a = 0 <;> simp [h₀, nextCoeff, natDegree_mul_C]
407+
360408
end NoZeroDivisors
361409

362410
@[simp] lemma comp_neg_X_leadingCoeff_eq [Ring R] (p : R[X]) :

Mathlib/Algebra/Polynomial/Div.lean

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,11 @@ lemma le_rootMultiplicity_mul {p q : R[X]} (x : R) (hpq : p * q ≠ 0) :
704704
rw [le_rootMultiplicity_iff hpq, pow_add]
705705
gcongr <;> apply pow_rootMultiplicity_dvd
706706

707+
lemma rootMultiplicity_le_rootMultiplicity_of_dvd {p q : R[X]} (hq : q ≠ 0) (hpq : p ∣ q) (x : R) :
708+
p.rootMultiplicity x ≤ q.rootMultiplicity x := by
709+
obtain ⟨_, rfl⟩ := hpq
710+
exact Nat.le_of_add_right_le <| le_rootMultiplicity_mul x hq
711+
707712
lemma pow_rootMultiplicity_not_dvd (p0 : p ≠ 0) (a : R) :
708713
¬(X - C a) ^ (rootMultiplicity a p + 1) ∣ p := by rw [← rootMultiplicity_le_iff p0]
709714

@@ -743,6 +748,19 @@ lemma degree_eq_one_of_irreducible_of_root (hi : Irreducible p) {x : R} (hx : Is
743748
rw [h₁] at h₂; exact absurd h₂ (by decide))
744749
fun hgu => by rw [hg, degree_mul, degree_X_sub_C, degree_eq_zero_of_isUnit hgu, add_zero]
745750

751+
lemma _root_.Irreducible.not_isRoot_of_natDegree_ne_one
752+
(hi : Irreducible p) (hdeg : p.natDegree ≠ 1) {x : R} : ¬p.IsRoot x :=
753+
fun hr ↦ hdeg <| natDegree_eq_of_degree_eq_some <| degree_eq_one_of_irreducible_of_root hi hr
754+
755+
lemma _root_.Irreducible.isRoot_eq_bot_of_natDegree_ne_one
756+
(hi : Irreducible p) (hdeg : p.natDegree ≠ 1) : p.IsRoot = ⊥ :=
757+
le_bot_iff.mp fun _ ↦ hi.not_isRoot_of_natDegree_ne_one hdeg
758+
759+
lemma _root_.Irreducible.subsingleton_isRoot [IsLeftCancelMulZero R] [IsRightCancelAdd R]
760+
(hi : Irreducible p) : { x | p.IsRoot x }.Subsingleton :=
761+
fun _ hx ↦ (subsingleton_isRoot_of_natDegree_eq_one <| natDegree_eq_of_degree_eq_some <|
762+
degree_eq_one_of_irreducible_of_root hi hx) hx
763+
746764
lemma leadingCoeff_divByMonic_X_sub_C (p : R[X]) (hp : degree p ≠ 0) (a : R) :
747765
leadingCoeff (p /ₘ (X - C a)) = leadingCoeff p := by
748766
nontriviality

Mathlib/Algebra/Polynomial/Eval/Coeff.lean

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,11 @@ theorem coeff_zero_eq_eval_zero (p : R[X]) : coeff p 0 = p.eval 0 :=
5858
rw [eval_eq_sum]
5959
exact Finset.sum_eq_single _ (fun b _ hb => by simp [zero_pow hb]) (by simp)
6060

61-
theorem zero_isRoot_of_coeff_zero_eq_zero {p : R[X]} (hp : p.coeff 0 = 0) : IsRoot p 0 := by
62-
rwa [coeff_zero_eq_eval_zero] at hp
61+
theorem zero_isRoot_iff_coeff_zero_eq_zero {p : R[X]} : IsRoot p 0 ↔ p.coeff 0 = 0 := by
62+
rw [coeff_zero_eq_eval_zero, IsRoot]
63+
64+
alias ⟨coeff_zero_eq_zero_of_zero_isRoot, zero_isRoot_of_coeff_zero_eq_zero⟩ :=
65+
zero_isRoot_iff_coeff_zero_eq_zero
6366

6467
end Eval
6568

Mathlib/Algebra/Polynomial/Eval/Defs.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,9 @@ protected theorem map_pow (n : ℕ) : (p ^ n).map f = p.map f ^ n :=
552552
theorem eval_map (x : S) : (p.map f).eval x = p.eval₂ f x :=
553553
(eval₂_eq_eval_map f).symm
554554

555+
@[simp] lemma eval_map_apply (x : R) : (p.map f).eval (f x) = f (p.eval x) :=
556+
eval_map f _ ▸ eval₂_at_apply ..
557+
555558
protected theorem map_sum {ι : Type*} (g : ι → R[X]) (s : Finset ι) :
556559
(∑ i ∈ s, g i).map f = ∑ i ∈ s, (g i).map f :=
557560
map_sum (mapRingHom f) _ _

Mathlib/Algebra/Polynomial/Eval/Degree.lean

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ theorem leadingCoeff_map_of_leadingCoeff_ne_zero (f : R →+* S) (hf : f (leadin
182182
unfold leadingCoeff
183183
rw [coeff_map, natDegree_map_of_leadingCoeff_ne_zero f hf]
184184

185+
theorem nextCoeff_map_of_leadingCoeff_ne_zero (f : R →+* S) (hf : f p.leadingCoeff ≠ 0) :
186+
(p.map f).nextCoeff = f p.nextCoeff := by
187+
grind [nextCoeff, natDegree_map_of_leadingCoeff_ne_zero, coeff_map, map_zero]
188+
185189
end Map
186190

187191
end Semiring

Mathlib/Algebra/Polynomial/FieldDivision.lean

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -249,35 +249,38 @@ theorem degree_pos_of_ne_zero_of_nonunit (hp0 : p ≠ 0) (hp : ¬IsUnit p) : 0 <
249249
rw [eq_C_of_degree_le_zero h] at hp0 hp
250250
exact hp (IsUnit.map C (IsUnit.mk0 (coeff p 0) (mt C_inj.2 (by simpa using hp0))))
251251

252+
end DivisionRing
253+
254+
section SimpleRing
255+
256+
variable [Ring R] [IsSimpleRing R] [Semiring S] [Nontrivial S] {p q : R[X]}
257+
252258
@[simp]
253-
protected theorem map_eq_zero [Semiring S] [Nontrivial S] (f : R →+* S) : p.map f = 0 ↔ p = 0 := by
254-
simp only [Polynomial.ext_iff]
255-
congr!
256-
simp [map_eq_zero, coeff_map, coeff_zero]
259+
protected theorem map_eq_zero (f : R →+* S) : p.map f = 0 ↔ p = 0 :=
260+
Polynomial.map_eq_zero_iff f.injective
257261

258-
theorem map_ne_zero [Semiring S] [Nontrivial S] {f : R →+* S} (hp : p ≠ 0) : p.map f ≠ 0 :=
262+
theorem map_ne_zero {f : R →+* S} (hp : p ≠ 0) : p.map f ≠ 0 :=
259263
mt (Polynomial.map_eq_zero f).1 hp
260264

261265
@[simp]
262-
theorem degree_map [Semiring S] [Nontrivial S] (p : R[X]) (f : R →+* S) :
263-
degree (p.map f) = degree p :=
264-
p.degree_map_eq_of_injective f.injective
266+
theorem degree_map (p : R[X]) (f : R →+* S) : (p.map f).degree = p.degree :=
267+
degree_map_eq_of_injective f.injective _
265268

266269
@[simp]
267-
theorem natDegree_map [Semiring S] [Nontrivial S] (f : R →+* S) :
268-
natDegree (p.map f) = natDegree p :=
269-
natDegree_eq_of_degree_eq (degree_map _ f)
270+
theorem natDegree_map (f : R →+* S) : (p.map f).natDegree = p.natDegree :=
271+
natDegree_map_eq_of_injective f.injective _
270272

271273
@[simp]
272-
theorem leadingCoeff_map [Semiring S] [Nontrivial S] (f : R →+* S) :
273-
leadingCoeff (p.map f) = f (leadingCoeff p) := by
274-
simp only [← coeff_natDegree, coeff_map f, natDegree_map]
274+
theorem leadingCoeff_map (f : R →+* S) : (p.map f).leadingCoeff = f p.leadingCoeff :=
275+
leadingCoeff_map_of_injective f.injective _
275276

276-
theorem monic_map_iff [Semiring S] [Nontrivial S] {f : R →+* S} {p : R[X]} :
277-
(p.map f).Monic ↔ p.Monic := by
278-
rw [Monic, leadingCoeff_map, ← f.map_one, Function.Injective.eq_iff f.injective, Monic]
277+
theorem nextCoeff_map_eq (p : R[X]) (f : R →+* S) : (p.map f).nextCoeff = f p.nextCoeff :=
278+
nextCoeff_map f.injective _
279279

280-
end DivisionRing
280+
@[simp] theorem monic_map_iff {f : R →+* S} {p : R[X]} : (p.map f).Monic ↔ p.Monic :=
281+
Function.Injective.monic_map_iff f.injective |>.symm
282+
283+
end SimpleRing
281284

282285
section Field
283286

Mathlib/Algebra/Polynomial/Monic.lean

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,9 @@ theorem Monic.as_sum (hp : p.Monic) :
5252
@[deprecated (since := "2025-08-14")] alias ne_zero_of_ne_zero_of_monic :=
5353
Monic.ne_zero_of_polynomial_ne
5454

55-
theorem Monic.map [Semiring S] (f : R →+* S) (hp : Monic p) : Monic (p.map f) := by
56-
unfold Monic
57-
nontriviality
58-
have : f p.leadingCoeff ≠ 0 := by
59-
rw [show _ = _ from hp, f.map_one]
60-
exact one_ne_zero
61-
rw [Polynomial.leadingCoeff, coeff_map]
62-
suffices p.coeff (p.map f).natDegree = 1 by simp [this]
63-
rwa [natDegree_eq_of_degree_eq (degree_map_eq_of_leadingCoeff_ne_zero f this)]
55+
theorem Monic.map [Semiring S] (f : R →+* S) (hp : Monic p) : Monic (p.map f) :=
56+
subsingleton_or_nontrivial S |>.elim (·.elim ..) fun _ ↦
57+
f.map_one ▸ hp ▸ leadingCoeff_map_eq_of_isUnit_leadingCoeff _ <| hp ▸ isUnit_one
6458

6559
theorem monic_C_mul_of_mul_leadingCoeff_eq_one {b : R} (hp : b * p.leadingCoeff = 1) :
6660
Monic (C b * p) := by
@@ -366,32 +360,11 @@ open Function
366360

367361
variable [Semiring S] {f : R →+* S}
368362

369-
theorem degree_map_eq_of_injective (hf : Injective f) (p : R[X]) : degree (p.map f) = degree p :=
370-
letI := Classical.decEq R
371-
if h : p = 0 then by simp [h]
372-
else
373-
degree_map_eq_of_leadingCoeff_ne_zero _
374-
(by rw [← f.map_zero]; exact mt hf.eq_iff.1 (mt leadingCoeff_eq_zero.1 h))
375-
376-
theorem natDegree_map_eq_of_injective (hf : Injective f) (p : R[X]) :
377-
natDegree (p.map f) = natDegree p :=
378-
natDegree_eq_of_degree_eq (degree_map_eq_of_injective hf p)
379-
380-
theorem leadingCoeff_map_of_injective (hf : Injective f) (p : R[X]) :
381-
leadingCoeff (p.map f) = f (leadingCoeff p) := by
382-
unfold leadingCoeff
383-
rw [coeff_map, natDegree_map_eq_of_injective hf p]
384-
385363
@[deprecated (since := "2025-10-26")]
386364
alias leadingCoeff_map' := leadingCoeff_map_of_injective
387365
@[deprecated (since := "2025-10-26")]
388366
alias leadingCoeff_of_injective := leadingCoeff_map_of_injective
389367

390-
theorem nextCoeff_map (hf : Injective f) (p : R[X]) : (p.map f).nextCoeff = f p.nextCoeff := by
391-
unfold nextCoeff
392-
rw [natDegree_map_eq_of_injective hf]
393-
split_ifs <;> simp [*]
394-
395368
theorem monic_of_injective (hf : Injective f) {p : R[X]} (hp : (p.map f).Monic) : p.Monic := by
396369
apply hf
397370
rw [← leadingCoeff_map_of_injective hf, hp.leadingCoeff, f.map_one]

Mathlib/Algebra/Polynomial/RingDivision.lean

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,14 @@ theorem mem_nonZeroDivisors_of_trailingCoeff {p : R[X]} (h : p.trailingCoeff ∈
130130

131131
end nonZeroDivisors
132132

133+
lemma _root_.Irreducible.aeval_ne_zero_of_natDegree_ne_one [IsDomain R] [Ring S] [Algebra R S]
134+
[FaithfulSMul R S] {p : R[X]} (hp : Irreducible p) (hdeg : p.natDegree ≠ 1) {x : S}
135+
(hx : x ∈ (algebraMap R S).range) : p.aeval x ≠ 0 := by
136+
obtain ⟨_, rfl⟩ := hx
137+
rw [aeval_algebraMap_apply_eq_algebraMap_eval]
138+
exact fun heq ↦ hp.not_isRoot_of_natDegree_ne_one hdeg <|
139+
FaithfulSMul.algebraMap_injective _ _ <| map_zero (algebraMap R S) ▸ heq
140+
133141
theorem natDegree_pos_of_monic_of_aeval_eq_zero [Nontrivial R] [Semiring S] [Algebra R S]
134142
[FaithfulSMul R S] {p : R[X]} (hp : p.Monic) {x : S} (hx : aeval x p = 0) :
135143
0 < p.natDegree :=

0 commit comments

Comments
 (0)