Skip to content

Commit 80f036f

Browse files
committed
feat: Polynomial.coeffList (#9085)
`Polynomial.coeffList` is the list of coefficients, in descending order from leading term to constant term. (The zero polynomial has coeffList of `[]`). The PR defines coeffList and proves some basic facts, notably relating `P.coeffList` to `P.eraseLead.coeffList`. Co-authored-by: Alex Meiburg <timeroot.alex@gmail.com>
1 parent 3d845f2 commit 80f036f

File tree

7 files changed

+233
-1
lines changed

7 files changed

+233
-1
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,7 @@ import Mathlib.Algebra.Polynomial.Bivariate
899899
import Mathlib.Algebra.Polynomial.CancelLeads
900900
import Mathlib.Algebra.Polynomial.Cardinal
901901
import Mathlib.Algebra.Polynomial.Coeff
902+
import Mathlib.Algebra.Polynomial.CoeffList
902903
import Mathlib.Algebra.Polynomial.CoeffMem
903904
import Mathlib.Algebra.Polynomial.Degree.CardPowDegree
904905
import Mathlib.Algebra.Polynomial.Degree.Definitions

Mathlib/Algebra/Order/SuccPred.lean

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Mathlib.Algebra.Order.Monoid.Canonical.Defs
88
import Mathlib.Algebra.Order.ZeroLEOne
99
import Mathlib.Data.Int.Cast.Defs
1010
import Mathlib.Order.SuccPred.Limit
11+
import Mathlib.Order.SuccPred.WithBot
1112

1213
/-!
1314
# Interaction between successors and arithmetic
@@ -187,6 +188,16 @@ theorem not_isSuccLimit_natCast [AddMonoidWithOne α] [SuccAddOrder α] [Canonic
187188
(n : ℕ) : ¬ IsSuccLimit (n : α) :=
188189
fun h ↦ (h.natCast_lt n).false
189190

191+
@[simp]
192+
theorem succ_eq_zero [AddZeroClass α] [CanonicallyOrderedAdd α] [One α] [NoMaxOrder α]
193+
[SuccAddOrder α] {a : WithBot α} : WithBot.succ a = 0 ↔ a = ⊥ := by
194+
cases a
195+
· simp [bot_eq_zero]
196+
· rename_i a
197+
simp only [WithBot.succ_coe, WithBot.coe_ne_bot, iff_false]
198+
by_contra h
199+
simpa [h] using max_of_succ_le (a := a)
200+
190201
end PartialOrder
191202

192203
section LinearOrder

Mathlib/Algebra/Polynomial/Coeff.lean

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker
55
-/
66
import Mathlib.Algebra.MonoidAlgebra.Support
77
import Mathlib.Algebra.Polynomial.Basic
8-
import Mathlib.Algebra.Regular.Basic
98
import Mathlib.Data.Nat.Choose.Sum
109

1110
/-!
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/-
2+
Copyright (c) 2023 Alex Meiburg. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Alex Meiburg
5+
-/
6+
import Mathlib.Algebra.Polynomial.Degree.Definitions
7+
import Mathlib.Algebra.Polynomial.EraseLead
8+
import Mathlib.Data.List.Range
9+
10+
/-!
11+
# A list of coefficients of a polynomial
12+
13+
## Definition
14+
15+
* `coeffList f`: a `List` of the coefficients, from leading term down to constant term.
16+
* `coeffList 0` is defined to be `[]`.
17+
18+
This is useful for talking about polynomials in terms of list operations. It is "redundant" data in
19+
the sense that `Polynomial` is already a `Finsupp` (of its coefficients), and `Polynomial.coeff`
20+
turns this into a function, and these have exactly the same data as `coeffList`. The difference is
21+
that `coeffList` is intended for working together with list operations: getting `List.head`,
22+
comparing adjacent coefficients with each other, or anything that involves induction on Pollynomials
23+
by dropping the leading term (which is `Polynomial.eraseLead`).
24+
25+
Note that `coeffList` _starts_ with the highest-degree terms and _ends_ with the constant term. This
26+
might seem backwards in the sense that `Polynomial.coeff` and `List.get!` are reversed to one
27+
another, but it means that induction on `List`s is the same as induction on
28+
`Polynomial.leadingCoeff`.
29+
30+
The most significant theorem here is `coeffList_eraseLead`, which says that `coeffList P` can be
31+
written as `leadingCoeff P :: List.replicate k 0 ++ coeffList P.eraseLead`. That is, the list
32+
of coefficients starts with the leading coefficient, followed by some number of zeros, and then the
33+
coefficients of `P.eraseLead`.
34+
-/
35+
36+
namespace Polynomial
37+
38+
variable {R : Type*}
39+
40+
section Semiring
41+
42+
variable [Semiring R]
43+
44+
/-- The list of coefficients starting from the leading term down to the constant term. -/
45+
def coeffList (P : R[X]) : List R :=
46+
(List.range P.degree.succ).reverse.map P.coeff
47+
48+
variable {P : R[X]}
49+
50+
variable (R) in
51+
@[simp]
52+
theorem coeffList_zero : (0 : R[X]).coeffList = [] := by
53+
simp [coeffList]
54+
55+
/-- Only the zero polynomial has no coefficients. -/
56+
@[simp]
57+
theorem coeffList_eq_nil {P : R[X]} : P.coeffList = [] ↔ P = 0 := by
58+
simp [coeffList]
59+
60+
@[simp]
61+
theorem coeffList_C {x : R} (h : x ≠ 0) : (C x).coeffList = [x] := by
62+
simp [coeffList, h, List.range_succ, degree_eq_natDegree (C_ne_zero.mpr h)]
63+
64+
theorem coeffList_eq_cons_leadingCoeff (h : P ≠ 0) :
65+
∃ ls, P.coeffList = P.leadingCoeff :: ls := by
66+
simp [coeffList, List.range_succ, withBotSucc_degree_eq_natDegree_add_one h]
67+
68+
@[simp]
69+
theorem head?_coeffList (h : P ≠ 0) :
70+
P.coeffList.head? = P.leadingCoeff :=
71+
(coeffList_eq_cons_leadingCoeff h).casesOn fun _ ↦ (Eq.symm · ▸ rfl)
72+
73+
@[simp] theorem head_coeffList (P : R[X]) (hP) :
74+
P.coeffList.head hP = P.leadingCoeff :=
75+
let h := coeffList_eq_nil.not.mp hP
76+
(coeffList_eq_cons_leadingCoeff h).casesOn fun _ _ ↦
77+
Option.some.injEq _ _ ▸ List.head?_eq_head _ ▸ head?_coeffList h
78+
79+
theorem length_coeffList_eq_withBotSucc_degree (P : R[X]) : P.coeffList.length = P.degree.succ := by
80+
simp [coeffList]
81+
82+
@[simp]
83+
theorem length_coeffList_eq_ite [DecidableEq R] (P : R[X]) :
84+
P.coeffList.length = if P = 0 then 0 else P.natDegree + 1 := by
85+
by_cases h : P = 0 <;> simp [h, coeffList, withBotSucc_degree_eq_natDegree_add_one]
86+
87+
theorem leadingCoeff_cons_eraseLead (h : P.nextCoeff ≠ 0) :
88+
P.leadingCoeff :: P.eraseLead.coeffList = P.coeffList := by
89+
have h₂ := ne_zero_of_natDegree_gt (natDegree_pos_of_nextCoeff_ne_zero h)
90+
have h₃ := mt nextCoeff_eq_zero_of_eraseLead_eq_zero h
91+
simpa [natDegree_eraseLead_add_one h, coeffList, withBotSucc_degree_eq_natDegree_add_one h₂,
92+
withBotSucc_degree_eq_natDegree_add_one h₃, List.range_succ] using
93+
(Polynomial.eraseLead_coeff_of_ne · ·.ne)
94+
95+
@[simp]
96+
theorem coeffList_monomial {x : R} (hx : x ≠ 0) (n : ℕ) :
97+
(monomial n x).coeffList = x :: List.replicate n 0 := by
98+
have h := mt (Polynomial.monomial_eq_zero_iff x n).mp hx
99+
apply List.ext_get (by classical simp [hx])
100+
rintro (_|k) _ h₁
101+
· exact (coeffList_eq_cons_leadingCoeff h).rec (by simp_all)
102+
· rw [List.length_cons, List.length_replicate] at h₁
103+
have : ((monomial n) x).natDegree.succ = n + 1 := by
104+
simp [Polynomial.natDegree_monomial_eq n hx]
105+
simpa [coeffList, withBotSucc_degree_eq_natDegree_add_one h]
106+
using Polynomial.coeff_monomial_of_ne _ (by omega)
107+
108+
/- Coefficients of a polynomial `P` are always the leading coefficient, some number of zeros, and
109+
then `coeffList P.eraseLead`. -/
110+
theorem coeffList_eraseLead (h : P ≠ 0) :
111+
P.coeffList =
112+
P.leadingCoeff :: (.replicate (P.natDegree - P.eraseLead.degree.succ) 0
113+
++ P.eraseLead.coeffList) := by
114+
by_cases hdp : P.natDegree = 0
115+
· rw [eq_C_of_natDegree_eq_zero hdp] at h ⊢
116+
simp [coeffList_C (C_ne_zero.mp h)]
117+
by_cases hep : P.eraseLead = 0
118+
· have h₂ : .monomial P.natDegree P.leadingCoeff = P := by
119+
simpa [hep] using P.eraseLead_add_monomial_natDegree_leadingCoeff
120+
nth_rewrite 1 [← h₂]
121+
simp [coeffList_monomial (Polynomial.leadingCoeff_ne_zero.mpr h), hep]
122+
have h₁ := withBotSucc_degree_eq_natDegree_add_one h
123+
have h₂ := withBotSucc_degree_eq_natDegree_add_one hep
124+
obtain ⟨n, hn, hn2⟩ : ∃ d, P.natDegree = P.eraseLead.natDegree + 1 + d ∧
125+
d = P.natDegree - P.eraseLead.degree.succ := by
126+
use P.natDegree - P.eraseLead.natDegree - 1
127+
have := eraseLead_natDegree_le P
128+
omega
129+
rw [← hn2]; clear hn2
130+
apply List.ext_getElem?
131+
rintro (_|k)
132+
· obtain ⟨w,h⟩ := (coeffList_eq_cons_leadingCoeff h)
133+
simp_all
134+
simp only [coeffList, support_eq_empty, h, reduceIte, List.map_reverse, hep]
135+
by_cases hkd : P.natDegree + 1 ≤ k + 1
136+
· rw [List.getElem?_eq_none]
137+
<;> simpa [hep, h] using by omega
138+
obtain ⟨dk, hdk⟩ := exists_add_of_le (Nat.le_of_lt_succ (Nat.lt_of_not_le hkd))
139+
rw [List.getElem?_reverse (by simpa [withBotSucc_degree_eq_natDegree_add_one h] using hkd),
140+
List.getElem?_cons_succ, List.length_map, List.length_range, List.getElem?_map,
141+
List.getElem?_range (by omega), Option.map_some']
142+
conv_lhs => arg 1; equals P.eraseLead.coeff dk =>
143+
rw [eraseLead_coeff_of_ne (f := P) dk (by omega)]
144+
congr
145+
omega
146+
by_cases hkn : k < n
147+
· simpa [List.getElem?_append, hkn] using coeff_eq_zero_of_natDegree_lt (by omega)
148+
· rw [List.getElem?_append_right (List.length_replicate _ _ ▸ Nat.le_of_not_gt hkn),
149+
List.length_replicate, List.getElem?_reverse, List.getElem?_map]
150+
· rw [List.length_map, List.length_range,
151+
List.getElem?_range (by omega), Option.map_some']
152+
congr 2
153+
omega
154+
· simpa using by omega
155+
156+
end Semiring
157+
section Ring
158+
variable [Ring R] (P : R[X])
159+
160+
@[simp]
161+
theorem coeffList_neg : (-P).coeffList = P.coeffList.map (-·) := by
162+
by_cases hp : P = 0
163+
· rw [hp, coeffList_zero, neg_zero, coeffList_zero, List.map_nil]
164+
· simp [coeffList, hp]
165+
166+
end Ring
167+
168+
section DivisionSemiring
169+
variable [DivisionSemiring R] (P : R[X])
170+
171+
theorem coeffList_C_mul {x : R} (hx : x ≠ 0) : (C x * P).coeffList = P.coeffList.map (x * ·) := by
172+
by_cases hp : P = 0
173+
· simp [hp]
174+
· simp [coeffList, Polynomial.degree_C hx]
175+
176+
end DivisionSemiring
177+
end Polynomial

Mathlib/Algebra/Polynomial/Degree/Definitions.lean

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import Mathlib.Algebra.MonoidAlgebra.Degree
77
import Mathlib.Algebra.Order.Ring.WithTop
88
import Mathlib.Algebra.Polynomial.Basic
99
import Mathlib.Data.Nat.Cast.WithTop
10+
import Mathlib.Data.Nat.SuccPred
11+
import Mathlib.Order.SuccPred.WithBot
1012

1113
/-!
1214
# Degree of univariate polynomials
@@ -240,6 +242,10 @@ theorem degree_X_le : degree (X : R[X]) ≤ 1 :=
240242
theorem natDegree_X_le : (X : R[X]).natDegree ≤ 1 :=
241243
natDegree_le_of_degree_le degree_X_le
242244

245+
theorem withBotSucc_degree_eq_natDegree_add_one (h : p ≠ 0) : p.degree.succ = p.natDegree + 1 := by
246+
rw [degree_eq_natDegree h]
247+
exact WithBot.succ_coe p.natDegree
248+
243249
end Semiring
244250

245251
section NonzeroSemiring

Mathlib/Data/Nat/SuccPred.lean

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ Authors: Yaël Dillies
55
-/
66
import Mathlib.Algebra.Order.Group.Nat
77
import Mathlib.Algebra.Ring.Nat
8+
import Mathlib.Algebra.Order.Monoid.Unbundled.WithTop
89
import Mathlib.Algebra.Order.Sub.Unbundled.Basic
910
import Mathlib.Algebra.Order.SuccPred
1011
import Mathlib.Data.Fin.Basic
1112
import Mathlib.Order.Nat
1213
import Mathlib.Order.SuccPred.Archimedean
14+
import Mathlib.Order.SuccPred.WithBot
1315

1416
/-!
1517
# Successors and predecessors of naturals
@@ -80,3 +82,9 @@ theorem Fin.coe_covBy_iff {n : ℕ} {a b : Fin n} : (a : ℕ) ⋖ b ↔ a ⋖ b
8082
and_congr_right' ⟨fun h _c hc => h hc, fun h c ha hb => @h ⟨c, hb.trans b.prop⟩ ha hb⟩
8183

8284
alias ⟨_, CovBy.coe_fin⟩ := Fin.coe_covBy_iff
85+
86+
@[simp]
87+
theorem withBotSucc_zero : WithBot.succ 0 = 1 := rfl
88+
89+
@[simp]
90+
theorem withBotSucc_one : WithBot.succ 1 = 2 := rfl

Mathlib/Order/SuccPred/WithBot.lean

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,21 @@ lemma succ_strictMono [NoMaxOrder α] : StrictMono (succ : WithBot α → α)
3939
@[gcongr] lemma succ_le_succ (hxy : x ≤ y) : x.succ ≤ y.succ := succ_mono hxy
4040
@[gcongr] lemma succ_lt_succ [NoMaxOrder α] (hxy : x < y) : x.succ < y.succ := succ_strictMono hxy
4141

42+
section LinearOrder
43+
44+
variable {α : Type*} [Nontrivial α] [LinearOrder α] [OrderBot α] [SuccOrder α]
45+
46+
@[simp]
47+
theorem succ_eq_bot (a : WithBot α) : WithBot.succ a = ⊥ ↔ a = ⊥ := by
48+
cases a
49+
· simp
50+
· simp only [WithBot.succ_coe, WithBot.coe_ne_bot, iff_false]
51+
apply ne_of_gt
52+
by_contra! h
53+
have h₂ : _ = ⊥ := le_bot_iff.mp ((Order.le_succ _).trans h)
54+
exact not_isMax_bot (h₂ ▸ Order.max_of_succ_le (h.trans bot_le))
55+
56+
end LinearOrder
4257
end WithBot
4358

4459
namespace WithTop
@@ -69,4 +84,19 @@ lemma pred_strictMono [NoMinOrder α] : StrictMono (pred : WithTop α → α)
6984
@[gcongr] lemma pred_le_pred (hxy : x ≤ y) : x.pred ≤ y.pred := pred_mono hxy
7085
@[gcongr] lemma pred_lt_pred [NoMinOrder α] (hxy : x < y) : x.pred < y.pred := pred_strictMono hxy
7186

87+
section LinearOrder
88+
89+
variable {α : Type*} [Nontrivial α] [LinearOrder α] [OrderTop α] [PredOrder α]
90+
91+
@[simp]
92+
theorem pred_eq_top (a : WithTop α) : WithTop.pred a = ⊤ ↔ a = ⊤ := by
93+
cases a
94+
· simp
95+
· simp only [WithTop.pred_coe, WithTop.coe_ne_top, iff_false]
96+
apply ne_of_lt
97+
by_contra! h
98+
have h₂ : _ = ⊤ := top_le_iff.mp (h.trans (Order.pred_le _))
99+
exact not_isMin_top (h₂ ▸ Order.min_of_le_pred (le_top.trans h))
100+
101+
end LinearOrder
72102
end WithTop

0 commit comments

Comments
 (0)