|
| 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.2 ⟨0⟩ |
| 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