|
| 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 |
0 commit comments