Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 1923c23

Browse files
kbuzzardjohoelzl
authored andcommitted
feat(data/polynomial): interface general coefficients of a polynomial (#339)
* feat(data/polynomial): interface general coefficients of a polynomial * fix(data/polynomial): fixing the code I broke when defining polynomial.ext * fix(data/polynomial): tidy up comments * Update polynomial.lean * adding interface for scalar multiplication and coefficients * feat(data/polynomial): coeff is R-linear
1 parent 282754c commit 1923c23

File tree

1 file changed

+133
-6
lines changed

1 file changed

+133
-6
lines changed

data/polynomial.lean

Lines changed: 133 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import data.finsupp algebra.euclidean_domain
99

1010
/-- `polynomial α` is the type of univariate polynomials over `α`.
1111
12-
Polynomials should be seen as (semi-)rings with the additional the constructor `X`. `C` is the
13-
embedding from `. -/
12+
Polynomials should be seen as (semi-)rings with the additional constructor `X`.
13+
The embedding from α is called `C`. -/
1414
def polynomial (α : Type*) [comm_semiring α] := ℕ →₀ α
1515

1616
open finsupp finset lattice
@@ -52,6 +52,12 @@ def C (a : α) : polynomial α := single 0 a
5252
/-- `X` is the polynomial variable (aka indeterminant). -/
5353
def X : polynomial α := single 1 1
5454

55+
/-- coeff p n is the coefficient of X^n in p -/
56+
def coeff (p : polynomial α) (n : ℕ) := p n
57+
58+
theorem ext (p q : polynomial α) : p = q ↔ ∀ n, coeff p n = coeff q n :=
59+
⟨λ h n, h ▸ rfl,finsupp.ext⟩
60+
5561
/-- `degree p` is the degree of the polynomial `p`, i.e. the largest `X`-exponent in `p`.
5662
`degree p = some n` when `p ≠ 0` and `n` is the highest power of `X` that appears in `p`, otherwise
5763
`degree 0 = ⊥`. -/
@@ -60,7 +66,7 @@ def degree (p : polynomial α) : with_bot ℕ := p.support.sup some
6066
def degree_lt_wf : well_founded (λp q : polynomial α, degree p < degree q) :=
6167
inv_image.wf degree (with_bot.well_founded_lt nat.lt_wf)
6268

63-
/-- `nat_degree p` forces `degree p` to ℕ, by fixing the zero polnomial to the 0 degree. -/
69+
/-- `nat_degree p` forces `degree p` to ℕ, by defining nat_degree 0 = 0. -/
6470
def nat_degree (p : polynomial α) : ℕ := (degree p).get_or_else 0
6571

6672
lemma single_eq_C_mul_X : ∀{n}, single n a = C a * X^n
@@ -134,6 +140,113 @@ suffices (single n 1 : polynomial α) i = (if n = i then 1 else 0),
134140
by rw [single_eq_C_mul_X] at this; simpa,
135141
single_apply
136142

143+
section coeff
144+
145+
@[simp] lemma coeff_zero (n : ℕ) : coeff (0 : polynomial α) n = 0 := rfl
146+
147+
@[simp] lemma coeff_C_mul_X (x : α) (k n : ℕ) :
148+
coeff (C x * X^k : polynomial α) n = if n = k then x else 0 :=
149+
by rw [← single_eq_C_mul_X, coeff, single_apply]; split_ifs; cc
150+
151+
@[simp] lemma coeff_C (x : α) (n : ℕ) :
152+
coeff (C x) n = if n = 0 then x else 0 :=
153+
by simpa only [pow_zero, mul_one] using coeff_C_mul_X x 0 n
154+
155+
@[simp] lemma coeff_one (n : ℕ) :
156+
coeff (1 : polynomial α) n = if n = 0 then 1 else 0 :=
157+
coeff_C 1 n
158+
159+
variable α
160+
@[simp] lemma coeff_X_pow (k n : ℕ) :
161+
coeff (X^k : polynomial α) n = if n = k then 1 else 0 :=
162+
by simpa only [C_1, one_mul] using coeff_C_mul_X (1:α) k n
163+
164+
@[simp] lemma coeff_X (n : ℕ) :
165+
coeff (X : polynomial α) n = if n = 1 then 1 else 0 :=
166+
by simpa only [pow_one] using coeff_X_pow α 1 n
167+
variable {α}
168+
169+
@[simp] lemma coeff_add (p q : polynomial α) (n : ℕ) :
170+
coeff (p + q) n = coeff p n + coeff q n := rfl
171+
172+
lemma coeff_mul_left (p q : polynomial α) (n : ℕ) :
173+
coeff (p * q) n = (range (n+1)).sum (λ k, coeff p k * coeff q (n-k)) :=
174+
begin
175+
refine polynomial.induction_on p (λ x, _) (λ p1 p2 ih1 ih2, _) (λ pn x ih, _),
176+
{ refine polynomial.induction_on q (λ y, _) (λ q1 q2 ih1 ih2, _) (λ qn y ih, _),
177+
{ rw [sum_eq_single 0, ← C_mul, coeff_C, coeff_C, coeff_C, if_pos rfl, nat.sub_zero],
178+
{ by_cases h : n = 0,
179+
{ simp only [if_pos h] },
180+
{ simp only [if_neg h, mul_zero] } },
181+
{ intros k h1 h2, rw [coeff_C, if_neg h2, zero_mul] },
182+
{ exact λ h1, (h1 (mem_range.2 (nat.zero_lt_succ n))).elim } },
183+
{ simp only [mul_add, coeff_add],
184+
-- why can't I just rw [ih1, ih2]???
185+
generalize_hyp h1 : coeff (C x * q1) n = Q1 at ih1 ⊢, rw ih1,
186+
generalize_hyp h2 : coeff (C x * q2) n = Q2 at ih2 ⊢, rw ih2,
187+
rw finset.sum_add_distrib },
188+
{ rw [sum_eq_single 0, ← mul_assoc, ← C_mul, coeff_C_mul_X, coeff_C_mul_X, coeff_C, if_pos rfl, nat.sub_zero],
189+
{ split_ifs; simp only [h, if_pos rfl, if_false, mul_zero] },
190+
{ intros k h1 h2, rw [coeff_C, if_neg h2, zero_mul] },
191+
{ exact λ h1, (h1 (mem_range.2 (nat.zero_lt_succ n))).elim } } },
192+
{ simp only [add_mul, coeff_add],
193+
-- why can't I just rw [ih1, ih2]???
194+
generalize_hyp h1 : coeff (p1 * q) n = P1 at ih1 ⊢, rw ih1,
195+
generalize_hyp h2 : coeff (p2 * q) n = P2 at ih2 ⊢, rw ih2,
196+
rw finset.sum_add_distrib },
197+
{ refine polynomial.induction_on q (λ y, _) (λ q1 q2 ih1 ih2, _) (λ qn y ih, _),
198+
{ rw [sum_eq_single n, mul_right_comm, ← C_mul, coeff_C_mul_X, coeff_C_mul_X, coeff_C, if_pos (nat.sub_self _)],
199+
{ split_ifs with h; simp only [h, if_pos rfl, if_false, zero_mul] },
200+
{ intros k h1 h2, rw [coeff_C, if_neg, mul_zero],
201+
refine mt (λ H, le_antisymm (nat.le_of_lt_succ (mem_range.1 h1)) (nat.sub_eq_zero_iff_le.1 H)) h2 },
202+
{ exact λ h1, (h1 (mem_range.2 (le_refl (n+1)))).elim } },
203+
{ simp only [mul_add, coeff_add],
204+
generalize_hyp h1 : coeff (C x * X ^ (pn + 1) * q1) n = Q1 at ih1 ⊢, rw ih1,
205+
generalize_hyp h2 : coeff (C x * X ^ (pn + 1) * q2) n = Q2 at ih2 ⊢, rw ih2,
206+
rw finset.sum_add_distrib },
207+
{ rw [mul_left_comm, mul_assoc, ← pow_add, ← mul_assoc, ← C_mul],
208+
rw [sum_eq_single (pn + 1), coeff_C_mul_X, coeff_C_mul_X, coeff_C_mul_X, if_pos rfl],
209+
{ have H : n = pn + 1 + (qn + 1) ↔ n - (pn + 1) = qn + 1,
210+
{ split, { intro H, rw [H, nat.add_sub_cancel_left] },
211+
intro H,
212+
have H1 : pn + 1 < n,
213+
{ refine lt_of_not_ge (λ H1, _),
214+
rw [nat.sub_eq_zero_of_le H1] at H,
215+
exact nat.succ_ne_zero qn H.symm },
216+
rw [(nat.sub_eq_iff_eq_add (le_of_lt H1)).1 H, add_comm] },
217+
split_ifs with h,
218+
{ rw [if_pos (H.1 h), mul_comm] },
219+
{ rw [if_neg (mt H.2 h), mul_zero] } },
220+
{ intros k h1 h2, rw [coeff_C_mul_X, if_neg h2, zero_mul] },
221+
{ intro H,
222+
rw [coeff_C_mul_X, if_pos rfl, coeff_C_mul_X, if_neg, mul_zero],
223+
rw [mem_range, not_lt] at H,
224+
rw [nat.sub_eq_zero_of_le (le_of_lt H)],
225+
exact ne.symm (nat.succ_ne_zero _) } } }
226+
end
227+
228+
lemma coeff_mul_right (p q : polynomial α) (n : ℕ) :
229+
coeff (p * q) n = (range (n+1)).sum (λ k, coeff p (n-k) * coeff q k) :=
230+
by rw [mul_comm, coeff_mul_left]; simp only [mul_comm]
231+
232+
theorem coeff_mul_X_pow (p : polynomial α) (n d : ℕ) :
233+
coeff (p * polynomial.X ^ n) (d + n) = coeff p d :=
234+
begin
235+
rw [coeff_mul_right, sum_eq_single n, coeff_X_pow, if_pos rfl, mul_one, nat.add_sub_cancel],
236+
{ intros b h1 h2, rw [coeff_X_pow, if_neg h2, mul_zero] },
237+
{ exact λ h1, (h1 (mem_range.2 (nat.le_add_left _ _))).elim }
238+
end
239+
240+
theorem coeff_mul_X (p : polynomial α) (n : ℕ) :
241+
coeff (p * X) (n + 1) = coeff p n :=
242+
by simpa only [pow_one] using coeff_mul_X_pow p 1 n
243+
244+
theorem mul_X_pow_eq_zero {p : polynomial α} {n : ℕ}
245+
(H : p * X ^ n = 0) : p = 0 :=
246+
(ext _ _).2 $ λ k, (coeff_mul_X_pow p n k).symm.trans $ (ext _ _).1 H (k+n)
247+
248+
end coeff
249+
137250
section eval₂
138251
variables {β : Type*} [comm_semiring β]
139252
variables (f : α → β) [is_semiring_hom f] (x : β)
@@ -529,8 +642,22 @@ section comm_ring
529642
variables [comm_ring α] {p q : polynomial α}
530643
instance : comm_ring (polynomial α) := finsupp.to_comm_ring
531644
instance : has_scalar α (polynomial α) := finsupp.to_has_scalar
532-
instance : module α (polynomial α) := finsupp.to_module α
533-
645+
-- TODO if this becomes a semimodule then the below lemma could be proved for semimodules
646+
instance : module α (polynomial α) := finsupp.to_module α
647+
648+
-- TODO -- this is OK for semimodules
649+
@[simp] lemma coeff_smul (p : polynomial α) (r : α) (n : ℕ) :
650+
coeff (r • p) n = r * coeff p n := finsupp.smul_apply
651+
652+
-- TODO -- this is OK for semimodules
653+
lemma C_mul' (a : α) (f : polynomial α) : C a * f = a • f :=
654+
(ext _ _).2 $ λ n, C_mul_apply f
655+
656+
-- TODO -- this is OK for semimodules
657+
lemma coeff_is_linear (n : ℕ) : is_linear_map (λ f : polynomial α, coeff f n) := {
658+
add := λ f g, coeff_add f g n,
659+
smul := λ r p, coeff_smul p r n
660+
}
534661
instance C.is_ring_hom : is_ring_hom (@C α _ _) := by apply is_ring_hom.of_semiring
535662

536663
instance eval₂.is_ring_hom {β} [comm_ring β]
@@ -936,7 +1063,7 @@ lemma degree_pos_of_root (hp : p ≠ 0) (h : is_root p a) : 0 < degree p :=
9361063
lt_of_not_ge $ λ hlt, begin
9371064
have := eq_C_of_degree_le_zero hlt,
9381065
rw [is_root, this, eval_C] at h,
939-
exact hp (ext (λ n, show p n = 0, from
1066+
exact hp (finsupp.ext (λ n, show p n = 0, from
9401067
nat.cases_on n h (λ _, eq_zero_of_degree_lt (lt_of_le_of_lt hlt
9411068
(with_bot.coe_lt_coe.2 (nat.succ_pos _)))))),
9421069
end

0 commit comments

Comments
 (0)