Skip to content

Commit b7e84bf

Browse files
Port/FieldTheory.Finite.Polynomial (#4597)
1 parent 22a3771 commit b7e84bf

File tree

2 files changed

+262
-0
lines changed

2 files changed

+262
-0
lines changed

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,6 +1559,7 @@ import Mathlib.Dynamics.OmegaLimit
15591559
import Mathlib.Dynamics.PeriodicPts
15601560
import Mathlib.FieldTheory.AxGrothendieck
15611561
import Mathlib.FieldTheory.Finite.Basic
1562+
import Mathlib.FieldTheory.Finite.Polynomial
15621563
import Mathlib.FieldTheory.Finiteness
15631564
import Mathlib.FieldTheory.IntermediateField
15641565
import Mathlib.FieldTheory.Minpoly.Basic
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
/-
2+
Copyright (c) 2020 Johan Commelin. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Johan Commelin
5+
6+
! This file was ported from Lean 3 source module field_theory.finite.polynomial
7+
! leanprover-community/mathlib commit 5aa3c1de9f3c642eac76e11071c852766f220fd0
8+
! Please do not edit these lines, except to modify the commit id
9+
! if you have ported upstream changes.
10+
-/
11+
import Mathlib.LinearAlgebra.FiniteDimensional
12+
import Mathlib.LinearAlgebra.Basic
13+
import Mathlib.RingTheory.MvPolynomial.Basic
14+
import Mathlib.Data.MvPolynomial.Expand
15+
import Mathlib.FieldTheory.Finite.Basic
16+
17+
/-!
18+
## Polynomials over finite fields
19+
-/
20+
21+
22+
namespace MvPolynomial
23+
24+
variable {σ : Type _}
25+
26+
/-- A polynomial over the integers is divisible by `n : ℕ`
27+
if and only if it is zero over `ZMod n`. -/
28+
theorem c_dvd_iff_zMod (n : ℕ) (φ : MvPolynomial σ ℤ) :
29+
C (n : ℤ) ∣ φ ↔ map (Int.castRingHom (ZMod n)) φ = 0 :=
30+
C_dvd_iff_map_hom_eq_zero _ _ (CharP.int_cast_eq_zero_iff (ZMod n) n) _
31+
set_option linter.uppercaseLean3 false in
32+
#align mv_polynomial.C_dvd_iff_zmod MvPolynomial.c_dvd_iff_zMod
33+
34+
section frobenius
35+
36+
variable {p : ℕ} [Fact p.Prime]
37+
38+
theorem frobenius_zMod (f : MvPolynomial σ (ZMod p)) : frobenius _ p f = expand p f := by
39+
apply induction_on f
40+
· intro a; rw [expand_C, frobenius_def, ← C_pow, ZMod.pow_card]
41+
· simp only [AlgHom.map_add, RingHom.map_add]; intro _ _ hf hg; rw [hf, hg]
42+
· simp only [expand_X, RingHom.map_mul, AlgHom.map_mul]
43+
intro _ _ hf; rw [hf, frobenius_def]
44+
#align mv_polynomial.frobenius_zmod MvPolynomial.frobenius_zMod
45+
46+
theorem expand_zMod (f : MvPolynomial σ (ZMod p)) : expand p f = f ^ p :=
47+
(frobenius_zMod _).symm
48+
#align mv_polynomial.expand_zmod MvPolynomial.expand_zMod
49+
50+
end frobenius
51+
52+
end MvPolynomial
53+
54+
namespace MvPolynomial
55+
56+
noncomputable section
57+
58+
open scoped BigOperators Classical
59+
60+
open Set LinearMap Submodule
61+
62+
variable {K : Type _} {σ : Type _}
63+
64+
section Indicator
65+
66+
variable [Fintype K] [Fintype σ]
67+
68+
/-- Over a field, this is the indicator function as an `MvPolynomial`. -/
69+
def indicator [CommRing K] (a : σ → K) : MvPolynomial σ K :=
70+
∏ n, (1 - (X n - C (a n)) ^ (Fintype.card K - 1))
71+
#align mv_polynomial.indicator MvPolynomial.indicator
72+
73+
section CommRing
74+
75+
variable [CommRing K]
76+
77+
theorem eval_indicator_apply_eq_one (a : σ → K) : eval a (indicator a) = 1 := by
78+
nontriviality
79+
have : 0 < Fintype.card K - 1 := tsub_pos_of_lt Fintype.one_lt_card
80+
simp only [indicator, map_prod, map_sub, map_one, map_pow, eval_X, eval_C, sub_self,
81+
zero_pow this, sub_zero, Finset.prod_const_one]
82+
#align mv_polynomial.eval_indicator_apply_eq_one MvPolynomial.eval_indicator_apply_eq_one
83+
84+
theorem degrees_indicator (c : σ → K) :
85+
degrees (indicator c) ≤ ∑ s : σ, (Fintype.card K - 1) • {s} := by
86+
rw [indicator]
87+
refine' le_trans (degrees_prod _ _) (Finset.sum_le_sum fun s _ => _)
88+
refine' le_trans (degrees_sub _ _) _
89+
rw [degrees_one, ← bot_eq_zero, bot_sup_eq]
90+
refine' le_trans (degrees_pow _ _) (nsmul_le_nsmul_of_le_right _ _)
91+
refine' le_trans (degrees_sub _ _) _
92+
rw [degrees_C, ← bot_eq_zero, sup_bot_eq]
93+
exact degrees_X' _
94+
#align mv_polynomial.degrees_indicator MvPolynomial.degrees_indicator
95+
96+
theorem indicator_mem_restrictDegree (c : σ → K) :
97+
indicator c ∈ restrictDegree σ K (Fintype.card K - 1) := by
98+
rw [mem_restrictDegree_iff_sup, indicator]
99+
intro n
100+
refine' le_trans (Multiset.count_le_of_le _ <| degrees_indicator _) (le_of_eq _)
101+
simp_rw [← Multiset.coe_countAddMonoidHom, (Multiset.countAddMonoidHom n).map_sum,
102+
AddMonoidHom.map_nsmul, Multiset.coe_countAddMonoidHom, nsmul_eq_mul, Nat.cast_id]
103+
trans
104+
refine' Finset.sum_eq_single n _ _
105+
· intro b _ ne
106+
simp [Multiset.count_singleton, ne, if_neg (Ne.symm _)]
107+
· intro h; exact (h <| Finset.mem_univ _).elim
108+
· rw [Multiset.count_singleton_self, mul_one]
109+
#align mv_polynomial.indicator_mem_restrict_degree MvPolynomial.indicator_mem_restrictDegree
110+
111+
end CommRing
112+
113+
variable [Field K]
114+
115+
theorem eval_indicator_apply_eq_zero (a b : σ → K) (h : a ≠ b) : eval a (indicator b) = 0 := by
116+
obtain ⟨i, hi⟩ : ∃ i, a i ≠ b i := by rwa [Ne, Function.funext_iff, not_forall] at h
117+
simp only [indicator, map_prod, map_sub, map_one, map_pow, eval_X, eval_C, sub_self,
118+
Finset.prod_eq_zero_iff]
119+
refine' ⟨i, Finset.mem_univ _, _⟩
120+
rw [FiniteField.pow_card_sub_one_eq_one, sub_self]
121+
rwa [Ne, sub_eq_zero]
122+
#align mv_polynomial.eval_indicator_apply_eq_zero MvPolynomial.eval_indicator_apply_eq_zero
123+
124+
end Indicator
125+
126+
section
127+
128+
variable (K σ)
129+
130+
/-- `MvPolynomial.eval` as a `K`-linear map. -/
131+
@[simps]
132+
def evalₗ [CommSemiring K] : MvPolynomial σ K →ₗ[K] (σ → K) → K where
133+
toFun p e := eval e p
134+
map_add' p q := by ext x; simp
135+
map_smul' a p := by ext e; simp
136+
#align mv_polynomial.evalₗ MvPolynomial.evalₗ
137+
138+
variable [Field K] [Fintype K] [Finite σ]
139+
140+
-- Porting note: `K` and `σ` were implicit in mathlib3, even if they were declared via
141+
-- `variables (K σ)` (I don't understand why). They are now explicit, as expected.
142+
theorem map_restrict_dom_evalₗ : (restrictDegree σ K (Fintype.card K - 1)).map (evalₗ K σ) = ⊤ := by
143+
cases nonempty_fintype σ
144+
refine' top_unique (SetLike.le_def.2 fun e _ => mem_map.2 _)
145+
refine' ⟨∑ n : σ → K, e n • indicator n, _, _⟩
146+
· exact sum_mem fun c _ => smul_mem _ _ (indicator_mem_restrictDegree _)
147+
· ext n
148+
simp only [LinearMap.map_sum, @Finset.sum_apply (σ → K) (fun _ => K) _ _ _ _ _, Pi.smul_apply,
149+
LinearMap.map_smul]
150+
simp only [evalₗ_apply]
151+
trans
152+
refine' Finset.sum_eq_single n (fun b _ h => _) _
153+
· rw [eval_indicator_apply_eq_zero _ _ h.symm, smul_zero]
154+
· exact fun h => (h <| Finset.mem_univ n).elim
155+
· rw [eval_indicator_apply_eq_one, smul_eq_mul, mul_one]
156+
#align mv_polynomial.map_restrict_dom_evalₗ MvPolynomial.map_restrict_dom_evalₗ
157+
158+
end
159+
160+
end
161+
162+
end MvPolynomial
163+
164+
namespace MvPolynomial
165+
166+
open scoped Classical Cardinal
167+
168+
open LinearMap Submodule
169+
170+
universe u
171+
172+
variable (σ : Type u) (K : Type u) [Fintype K]
173+
174+
--Porting note: `@[derive [add_comm_group, module K, inhabited]]` done by hand.
175+
/-- The submodule of multivariate polynomials whose degree of each variable is strictly less
176+
than the cardinality of K. -/
177+
def R [CommRing K] : Type u :=
178+
restrictDegree σ K (Fintype.card K - 1)
179+
set_option linter.uppercaseLean3 false in
180+
#align mv_polynomial.R MvPolynomial.R
181+
182+
noncomputable instance [CommRing K] : AddCommGroup (R σ K) :=
183+
inferInstanceAs (AddCommGroup (restrictDegree σ K (Fintype.card K - 1)))
184+
185+
noncomputable instance [CommRing K] : Module K (R σ K) :=
186+
inferInstanceAs (Module K (restrictDegree σ K (Fintype.card K - 1)))
187+
188+
noncomputable instance [CommRing K] : Inhabited (R σ K) :=
189+
inferInstanceAs (Inhabited (restrictDegree σ K (Fintype.card K - 1)))
190+
191+
/-- Evaluation in the `mv_polynomial.R` subtype. -/
192+
def evalᵢ [CommRing K] : R σ K →ₗ[K] (σ → K) → K :=
193+
(evalₗ K σ).comp (restrictDegree σ K (Fintype.card K - 1)).subtype
194+
#align mv_polynomial.evalᵢ MvPolynomial.evalᵢ
195+
196+
section CommRing
197+
198+
variable [CommRing K]
199+
200+
noncomputable instance decidableRestrictDegree (m : ℕ) :
201+
DecidablePred (· ∈ { n : σ →₀ ℕ | ∀ i, n i ≤ m }) := by
202+
simp only [Set.mem_setOf_eq]; infer_instance
203+
#align mv_polynomial.decidable_restrict_degree MvPolynomial.decidableRestrictDegree
204+
205+
end CommRing
206+
207+
variable [Field K]
208+
209+
theorem rank_R [Fintype σ] : Module.rank K (R σ K) = Fintype.card (σ → K) :=
210+
calc
211+
Module.rank K (R σ K) =
212+
Module.rank K (↥{ s : σ →₀ ℕ | ∀ n : σ, s n ≤ Fintype.card K - 1 } →₀ K) :=
213+
LinearEquiv.rank_eq
214+
(Finsupp.supportedEquivFinsupp { s : σ →₀ ℕ | ∀ n : σ, s n ≤ Fintype.card K - 1 })
215+
_ = (#{ s : σ →₀ ℕ | ∀ n : σ, s n ≤ Fintype.card K - 1 }) := by rw [rank_finsupp_self']
216+
_ = (#{ s : σ → ℕ | ∀ n : σ, s n < Fintype.card K }) := by
217+
refine' Quotient.sound ⟨Equiv.subtypeEquiv Finsupp.equivFunOnFinite fun f => _⟩
218+
refine' forall_congr' fun n => le_tsub_iff_right _
219+
exact Fintype.card_pos_iff.20
220+
_ = (#σ → { n // n < Fintype.card K }) :=
221+
(@Equiv.subtypePiEquivPi σ (fun _ => ℕ) fun s n => n < Fintype.card K).cardinal_eq
222+
_ = (#σ → Fin (Fintype.card K)) :=
223+
(Equiv.arrowCongr (Equiv.refl σ) Fin.equivSubtype.symm).cardinal_eq
224+
_ = (#σ → K) := (Equiv.arrowCongr (Equiv.refl σ) (Fintype.equivFin K).symm).cardinal_eq
225+
_ = Fintype.card (σ → K) := Cardinal.mk_fintype _
226+
set_option linter.uppercaseLean3 false in
227+
#align mv_polynomial.rank_R MvPolynomial.rank_R
228+
229+
instance [Finite σ] : FiniteDimensional K (R σ K) := by
230+
cases nonempty_fintype σ
231+
exact
232+
IsNoetherian.iff_fg.1
233+
(IsNoetherian.iff_rank_lt_aleph0.mpr <| by
234+
simpa only [rank_R] using Cardinal.nat_lt_aleph0 (Fintype.card (σ → K)))
235+
236+
theorem finrank_R [Fintype σ] : FiniteDimensional.finrank K (R σ K) = Fintype.card (σ → K) :=
237+
FiniteDimensional.finrank_eq_of_rank_eq (rank_R σ K)
238+
set_option linter.uppercaseLean3 false in
239+
#align mv_polynomial.finrank_R MvPolynomial.finrank_R
240+
241+
-- Porting note: was `(evalᵢ σ K).range`.
242+
theorem range_evalᵢ [Finite σ] : range (evalᵢ σ K) = ⊤ := by
243+
rw [evalᵢ, LinearMap.range_comp, range_subtype]
244+
exact map_restrict_dom_evalₗ K σ
245+
#align mv_polynomial.range_evalᵢ MvPolynomial.range_evalᵢ
246+
247+
--Porting note: was `(evalᵢ σ K).ker`.
248+
theorem ker_evalₗ [Finite σ] : ker (evalᵢ σ K) = ⊥ := by
249+
cases nonempty_fintype σ
250+
refine' (ker_eq_bot_iff_range_eq_top_of_finrank_eq_finrank _).mpr (range_evalᵢ σ K)
251+
rw [FiniteDimensional.finrank_fintype_fun_eq_card, finrank_R]
252+
#align mv_polynomial.ker_evalₗ MvPolynomial.ker_evalₗ
253+
254+
theorem eq_zero_of_eval_eq_zero [Finite σ] (p : MvPolynomial σ K) (h : ∀ v : σ → K, eval v p = 0)
255+
(hp : p ∈ restrictDegree σ K (Fintype.card K - 1)) : p = 0 :=
256+
let p' : R σ K := ⟨p, hp⟩
257+
have : p' ∈ ker (evalᵢ σ K) := funext h
258+
show p'.1 = (0 : R σ K).1 from congr_arg _ <| by rwa [ker_evalₗ, mem_bot] at this
259+
#align mv_polynomial.eq_zero_of_eval_eq_zero MvPolynomial.eq_zero_of_eval_eq_zero
260+
261+
end MvPolynomial

0 commit comments

Comments
 (0)