Skip to content

Commit db15210

Browse files
feat: port Data.Polynomial.Expand (#4083)
Co-authored-by: Jujian Zhang <jujian.zhang1998@outlook.com>
1 parent 87c4a75 commit db15210

File tree

2 files changed

+300
-0
lines changed

2 files changed

+300
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,7 @@ import Mathlib.Data.Polynomial.Derivative
11971197
import Mathlib.Data.Polynomial.Div
11981198
import Mathlib.Data.Polynomial.EraseLead
11991199
import Mathlib.Data.Polynomial.Eval
1200+
import Mathlib.Data.Polynomial.Expand
12001201
import Mathlib.Data.Polynomial.FieldDivision
12011202
import Mathlib.Data.Polynomial.HasseDeriv
12021203
import Mathlib.Data.Polynomial.Identities
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
/-
2+
Copyright (c) 2020 Kenny Lau. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Kenny Lau
5+
6+
! This file was ported from Lean 3 source module data.polynomial.expand
7+
! leanprover-community/mathlib commit bbeb185db4ccee8ed07dc48449414ebfa39cb821
8+
! Please do not edit these lines, except to modify the commit id
9+
! if you have ported upstream changes.
10+
-/
11+
import Mathlib.RingTheory.Polynomial.Basic
12+
import Mathlib.RingTheory.Ideal.LocalRing
13+
14+
/-!
15+
# Expand a polynomial by a factor of p, so `∑ aₙ xⁿ` becomes `∑ aₙ xⁿᵖ`.
16+
17+
## Main definitions
18+
19+
* `Polynomial.expand R p f`: expand the polynomial `f` with coefficients in a
20+
commutative semiring `R` by a factor of p, so `expand R p (∑ aₙ xⁿ)` is `∑ aₙ xⁿᵖ`.
21+
* `Polynomial.contract p f`: the opposite of `expand`, so it sends `∑ aₙ xⁿᵖ` to `∑ aₙ xⁿ`.
22+
23+
-/
24+
25+
26+
universe u v w
27+
28+
open Classical BigOperators Polynomial
29+
30+
open Finset
31+
32+
namespace Polynomial
33+
34+
section CommSemiring
35+
36+
variable (R : Type u) [CommSemiring R] {S : Type v} [CommSemiring S] (p q : ℕ)
37+
38+
/-- Expand the polynomial by a factor of p, so `∑ aₙ xⁿ` becomes `∑ aₙ xⁿᵖ`. -/
39+
noncomputable def expand : R[X] →ₐ[R] R[X] :=
40+
{ (eval₂RingHom C (X ^ p) : R[X] →+* R[X]) with commutes' := fun _ => eval₂_C _ _ }
41+
#align polynomial.expand Polynomial.expand
42+
43+
theorem coe_expand : (expand R p : R[X] → R[X]) = eval₂ C (X ^ p) :=
44+
rfl
45+
#align polynomial.coe_expand Polynomial.coe_expand
46+
47+
variable {R}
48+
49+
theorem expand_eq_sum {f : R[X]} : expand R p f = f.sum fun e a => C a * (X ^ p) ^ e := by
50+
simp [expand, eval₂]
51+
#align polynomial.expand_eq_sum Polynomial.expand_eq_sum
52+
53+
@[simp]
54+
theorem expand_C (r : R) : expand R p (C r) = C r :=
55+
eval₂_C _ _
56+
set_option linter.uppercaseLean3 false in
57+
#align polynomial.expand_C Polynomial.expand_C
58+
59+
@[simp]
60+
theorem expand_X : expand R p X = X ^ p :=
61+
eval₂_X _ _
62+
set_option linter.uppercaseLean3 false in
63+
#align polynomial.expand_X Polynomial.expand_X
64+
65+
@[simp]
66+
theorem expand_monomial (r : R) : expand R p (monomial q r) = monomial (q * p) r := by
67+
simp_rw [← smul_X_eq_monomial, AlgHom.map_smul, AlgHom.map_pow, expand_X, mul_comm, pow_mul]
68+
#align polynomial.expand_monomial Polynomial.expand_monomial
69+
70+
theorem expand_expand (f : R[X]) : expand R p (expand R q f) = expand R (p * q) f :=
71+
Polynomial.induction_on f (fun r => by simp_rw [expand_C])
72+
(fun f g ihf ihg => by simp_rw [AlgHom.map_add, ihf, ihg]) fun n r _ => by
73+
simp_rw [AlgHom.map_mul, expand_C, AlgHom.map_pow, expand_X, AlgHom.map_pow, expand_X, pow_mul]
74+
#align polynomial.expand_expand Polynomial.expand_expand
75+
76+
theorem expand_mul (f : R[X]) : expand R (p * q) f = expand R p (expand R q f) :=
77+
(expand_expand p q f).symm
78+
#align polynomial.expand_mul Polynomial.expand_mul
79+
80+
@[simp]
81+
theorem expand_zero (f : R[X]) : expand R 0 f = C (eval 1 f) := by simp [expand]
82+
#align polynomial.expand_zero Polynomial.expand_zero
83+
84+
@[simp]
85+
theorem expand_one (f : R[X]) : expand R 1 f = f :=
86+
Polynomial.induction_on f (fun r => by rw [expand_C])
87+
(fun f g ihf ihg => by rw [AlgHom.map_add, ihf, ihg]) fun n r _ => by
88+
rw [AlgHom.map_mul, expand_C, AlgHom.map_pow, expand_X, pow_one]
89+
#align polynomial.expand_one Polynomial.expand_one
90+
91+
theorem expand_pow (f : R[X]) : expand R (p ^ q) f = (expand R p^[q]) f :=
92+
Nat.recOn q (by rw [pow_zero, expand_one, Function.iterate_zero, id]) fun n ih => by
93+
rw [Function.iterate_succ_apply', pow_succ, expand_mul, ih]
94+
#align polynomial.expand_pow Polynomial.expand_pow
95+
96+
theorem derivative_expand (f : R[X]) : Polynomial.derivative (expand R p f) =
97+
expand R p (Polynomial.derivative f) * (p * (X ^ (p - 1) : R[X])) := by
98+
rw [coe_expand, derivative_eval₂_C, derivative_pow, C_eq_nat_cast, derivative_X, mul_one]
99+
#align polynomial.derivative_expand Polynomial.derivative_expand
100+
101+
theorem coeff_expand {p : ℕ} (hp : 0 < p) (f : R[X]) (n : ℕ) :
102+
(expand R p f).coeff n = if p ∣ n then f.coeff (n / p) else 0 := by
103+
simp only [expand_eq_sum]
104+
simp_rw [coeff_sum, ← pow_mul, C_mul_X_pow_eq_monomial, coeff_monomial, sum]
105+
split_ifs with h
106+
· rw [Finset.sum_eq_single (n / p), Nat.mul_div_cancel' h, if_pos rfl]
107+
· intro b _ hb2
108+
rw [if_neg]
109+
intro hb3
110+
apply hb2
111+
rw [← hb3, Nat.mul_div_cancel_left b hp]
112+
· intro hn
113+
rw [not_mem_support_iff.1 hn]
114+
split_ifs <;> rfl
115+
· rw [Finset.sum_eq_zero]
116+
intro k _
117+
rw [if_neg]
118+
exact fun hkn => h ⟨k, hkn.symm⟩
119+
#align polynomial.coeff_expand Polynomial.coeff_expand
120+
121+
@[simp]
122+
theorem coeff_expand_mul {p : ℕ} (hp : 0 < p) (f : R[X]) (n : ℕ) :
123+
(expand R p f).coeff (n * p) = f.coeff n := by
124+
rw [coeff_expand hp, if_pos (dvd_mul_left _ _), Nat.mul_div_cancel _ hp]
125+
#align polynomial.coeff_expand_mul Polynomial.coeff_expand_mul
126+
127+
@[simp]
128+
theorem coeff_expand_mul' {p : ℕ} (hp : 0 < p) (f : R[X]) (n : ℕ) :
129+
(expand R p f).coeff (p * n) = f.coeff n := by rw [mul_comm, coeff_expand_mul hp]
130+
#align polynomial.coeff_expand_mul' Polynomial.coeff_expand_mul'
131+
132+
/-- Expansion is injective. -/
133+
theorem expand_injective {n : ℕ} (hn : 0 < n) : Function.Injective (expand R n) := fun g g' H =>
134+
ext fun k => by rw [← coeff_expand_mul hn, H, coeff_expand_mul hn]
135+
#align polynomial.expand_injective Polynomial.expand_injective
136+
137+
theorem expand_inj {p : ℕ} (hp : 0 < p) {f g : R[X]} : expand R p f = expand R p g ↔ f = g :=
138+
(expand_injective hp).eq_iff
139+
#align polynomial.expand_inj Polynomial.expand_inj
140+
141+
theorem expand_eq_zero {p : ℕ} (hp : 0 < p) {f : R[X]} : expand R p f = 0 ↔ f = 0 :=
142+
(expand_injective hp).eq_iff' (map_zero _)
143+
#align polynomial.expand_eq_zero Polynomial.expand_eq_zero
144+
145+
theorem expand_ne_zero {p : ℕ} (hp : 0 < p) {f : R[X]} : expand R p f ≠ 0 ↔ f ≠ 0 :=
146+
(expand_eq_zero hp).not
147+
#align polynomial.expand_ne_zero Polynomial.expand_ne_zero
148+
149+
theorem expand_eq_C {p : ℕ} (hp : 0 < p) {f : R[X]} {r : R} : expand R p f = C r ↔ f = C r := by
150+
rw [← expand_C, expand_inj hp, expand_C]
151+
set_option linter.uppercaseLean3 false in
152+
#align polynomial.expand_eq_C Polynomial.expand_eq_C
153+
154+
theorem natDegree_expand (p : ℕ) (f : R[X]) : (expand R p f).natDegree = f.natDegree * p := by
155+
cases' p.eq_zero_or_pos with hp hp
156+
· rw [hp, coe_expand, pow_zero, MulZeroClass.mul_zero, ← C_1, eval₂_hom, natDegree_C]
157+
by_cases hf : f = 0
158+
· rw [hf, AlgHom.map_zero, natDegree_zero, MulZeroClass.zero_mul]
159+
have hf1 : expand R p f ≠ 0 := mt (expand_eq_zero hp).1 hf
160+
rw [← WithBot.coe_eq_coe]
161+
convert (degree_eq_natDegree hf1).symm -- Porting note: was `rw [degree_eq_natDegree hf1]`
162+
symm
163+
refine' le_antisymm ((degree_le_iff_coeff_zero _ _).2 fun n hn => _) _
164+
· rw [coeff_expand hp]
165+
split_ifs with hpn
166+
· rw [coeff_eq_zero_of_natDegree_lt]
167+
contrapose! hn
168+
erw [WithBot.coe_le_coe, ← Nat.div_mul_cancel hpn]
169+
exact Nat.mul_le_mul_right p hn
170+
· rfl
171+
· refine' le_degree_of_ne_zero _
172+
erw [coeff_expand_mul hp, ← leadingCoeff]
173+
exact mt leadingCoeff_eq_zero.1 hf
174+
#align polynomial.nat_degree_expand Polynomial.natDegree_expand
175+
176+
theorem Monic.expand {p : ℕ} {f : R[X]} (hp : 0 < p) (h : f.Monic) : (expand R p f).Monic := by
177+
rw [Monic.def, Polynomial.leadingCoeff, natDegree_expand, coeff_expand hp]
178+
simp [hp, h]
179+
#align polynomial.monic.expand Polynomial.Monic.expand
180+
181+
theorem map_expand {p : ℕ} {f : R →+* S} {q : R[X]} :
182+
map f (expand R p q) = expand S p (map f q) := by
183+
by_cases hp : p = 0
184+
· simp [hp]
185+
ext
186+
rw [coeff_map, coeff_expand (Nat.pos_of_ne_zero hp), coeff_expand (Nat.pos_of_ne_zero hp)]
187+
split_ifs <;> simp_all
188+
#align polynomial.map_expand Polynomial.map_expand
189+
190+
@[simp]
191+
theorem expand_eval (p : ℕ) (P : R[X]) (r : R) : eval r (expand R p P) = eval (r ^ p) P := by
192+
refine' Polynomial.induction_on P (fun a => by simp) (fun f g hf hg => _) fun n a _ => by simp
193+
rw [AlgHom.map_add, eval_add, eval_add, hf, hg]
194+
#align polynomial.expand_eval Polynomial.expand_eval
195+
196+
@[simp]
197+
theorem expand_aeval {A : Type _} [Semiring A] [Algebra R A] (p : ℕ) (P : R[X]) (r : A) :
198+
aeval r (expand R p P) = aeval (r ^ p) P := by
199+
refine' Polynomial.induction_on P (fun a => by simp) (fun f g hf hg => _) fun n a _ => by simp
200+
rw [AlgHom.map_add, aeval_add, aeval_add, hf, hg]
201+
#align polynomial.expand_aeval Polynomial.expand_aeval
202+
203+
/-- The opposite of `expand`: sends `∑ aₙ xⁿᵖ` to `∑ aₙ xⁿ`. -/
204+
noncomputable def contract (p : ℕ) (f : R[X]) : R[X] :=
205+
∑ n in range (f.natDegree + 1), monomial n (f.coeff (n * p))
206+
#align polynomial.contract Polynomial.contract
207+
208+
theorem coeff_contract {p : ℕ} (hp : p ≠ 0) (f : R[X]) (n : ℕ) :
209+
(contract p f).coeff n = f.coeff (n * p) := by
210+
simp only [contract, coeff_monomial, sum_ite_eq', finset_sum_coeff, mem_range, not_lt,
211+
ite_eq_left_iff]
212+
intro hn
213+
apply (coeff_eq_zero_of_natDegree_lt _).symm
214+
calc
215+
f.natDegree < f.natDegree + 1 := Nat.lt_succ_self _
216+
_ ≤ n * 1 := by simpa only [mul_one] using hn
217+
_ ≤ n * p := mul_le_mul_of_nonneg_left (show 1 ≤ p from hp.bot_lt) (zero_le n)
218+
#align polynomial.coeff_contract Polynomial.coeff_contract
219+
220+
theorem contract_expand {f : R[X]} (hp : p ≠ 0) : contract p (expand R p f) = f := by
221+
ext
222+
simp [coeff_contract hp, coeff_expand hp.bot_lt, Nat.mul_div_cancel _ hp.bot_lt]
223+
#align polynomial.contract_expand Polynomial.contract_expand
224+
225+
section CharP
226+
227+
variable [CharP R p]
228+
229+
theorem expand_contract [NoZeroDivisors R] {f : R[X]} (hf : Polynomial.derivative f = 0)
230+
(hp : p ≠ 0) : expand R p (contract p f) = f := by
231+
ext n
232+
rw [coeff_expand hp.bot_lt, coeff_contract hp]
233+
split_ifs with h
234+
· rw [Nat.div_mul_cancel h]
235+
· cases' n with n
236+
· exact absurd (dvd_zero p) h
237+
have := coeff_derivative f n
238+
rw [hf, coeff_zero, zero_eq_mul] at this
239+
cases' this with h'
240+
· rw [h']
241+
rename_i _ _ _ _ h'
242+
rw [← Nat.cast_succ, CharP.cast_eq_zero_iff R p] at h'
243+
exact absurd h' h
244+
#align polynomial.expand_contract Polynomial.expand_contract
245+
246+
variable [hp : Fact p.Prime]
247+
248+
theorem expand_char (f : R[X]) : map (frobenius R p) (expand R p f) = f ^ p := by
249+
refine' f.induction_on' (fun a b ha hb => _) fun n a => _
250+
· rw [AlgHom.map_add, Polynomial.map_add, ha, hb, add_pow_char]
251+
· rw [expand_monomial, map_monomial, ← C_mul_X_pow_eq_monomial, ← C_mul_X_pow_eq_monomial,
252+
mul_pow, ← C.map_pow, frobenius_def]
253+
ring
254+
#align polynomial.expand_char Polynomial.expand_char
255+
256+
theorem map_expand_pow_char (f : R[X]) (n : ℕ) :
257+
map (frobenius R p ^ n) (expand R (p ^ n) f) = f ^ p ^ n := by
258+
induction' n with _ n_ih
259+
· simp [RingHom.one_def]
260+
symm
261+
rw [pow_succ', pow_mul, ← n_ih, ← expand_char, pow_succ, RingHom.mul_def, ← map_map, mul_comm,
262+
expand_mul, ← map_expand]
263+
#align polynomial.map_expand_pow_char Polynomial.map_expand_pow_char
264+
265+
end CharP
266+
267+
end CommSemiring
268+
269+
section IsDomain
270+
271+
variable (R : Type u) [CommRing R] [IsDomain R]
272+
273+
theorem isLocalRingHom_expand {p : ℕ} (hp : 0 < p) :
274+
IsLocalRingHom (↑(expand R p) : R[X] →+* R[X]) := by
275+
refine' ⟨fun f hf1 => _⟩; norm_cast at hf1
276+
have hf2 := eq_C_of_degree_eq_zero (degree_eq_zero_of_isUnit hf1)
277+
rw [coeff_expand hp, if_pos (dvd_zero _), p.zero_div] at hf2
278+
rw [hf2, isUnit_C] at hf1; rw [expand_eq_C hp] at hf2; rwa [hf2, isUnit_C]
279+
#align polynomial.is_local_ring_hom_expand Polynomial.isLocalRingHom_expand
280+
281+
variable {R}
282+
283+
theorem of_irreducible_expand {p : ℕ} (hp : p ≠ 0) {f : R[X]} (hf : Irreducible (expand R p f)) :
284+
Irreducible f :=
285+
let _ := isLocalRingHom_expand R hp.bot_lt
286+
of_irreducible_map (↑(expand R p)) hf
287+
#align polynomial.of_irreducible_expand Polynomial.of_irreducible_expand
288+
289+
theorem of_irreducible_expand_pow {p : ℕ} (hp : p ≠ 0) {f : R[X]} {n : ℕ} :
290+
Irreducible (expand R (p ^ n) f) → Irreducible f :=
291+
Nat.recOn n (fun hf => by rwa [pow_zero, expand_one] at hf) fun n ih hf =>
292+
ih <| of_irreducible_expand hp <| by
293+
rw [pow_succ] at hf
294+
rwa [expand_expand]
295+
#align polynomial.of_irreducible_expand_pow Polynomial.of_irreducible_expand_pow
296+
297+
end IsDomain
298+
299+
end Polynomial

0 commit comments

Comments
 (0)