|
| 1 | +/- |
| 2 | +Copyright (c) 2022 Damiano Testa. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Damiano Testa |
| 5 | +-/ |
| 6 | + |
| 7 | +import data.polynomial.algebra_map |
| 8 | + |
| 9 | +/-! # Laurent polynomials |
| 10 | +
|
| 11 | +We introduce Laurent polynomials over a semiring `R`. Mathematically, they are expressions of the |
| 12 | +form |
| 13 | +$$ |
| 14 | +\sum_{i \in \mathbb{Z}} a_i T ^ i |
| 15 | +$$ |
| 16 | +where the sum extends over a finite subset of `ℤ`. Thus, negative exponents are allowed. The |
| 17 | +coefficients come from the semiring `R` and the variable `T` commutes with everything. |
| 18 | +
|
| 19 | +Since we are going to convert back and forth between polynomials and Laurent polynomials, we |
| 20 | +decided to maintain some distinction by using the symbol `T`, rather than `X`, as the variable for |
| 21 | +Laurent polynomials |
| 22 | +
|
| 23 | +## Notation |
| 24 | +The symbol `R[T;T⁻¹]` stands for `laurent_polynomial R`. We also define |
| 25 | +
|
| 26 | +* `C : R →+* R[T;T⁻¹]` the inclusion of constant polynomials, analogous to the one for `R[X]`; |
| 27 | +* `T : ℤ → R[T;T⁻¹]` the sequence of powers of the variable `T`. |
| 28 | +
|
| 29 | +## Implementation notes |
| 30 | +
|
| 31 | +We define Laurent polynomials as `add_monoid_algebra R ℤ`. |
| 32 | +Thus, they are essentially `finsupp`s `ℤ →₀ R`. |
| 33 | +This choice differs from the current irreducible design of `polynomial`, that instead shields away |
| 34 | +the implementation via `finsupp`s. It is closer to the original definition of polynomials. |
| 35 | +
|
| 36 | +As a consequence, `laurent_polynomial` plays well with polynomials, but there is a little roughness |
| 37 | +in establishing the API, since the `finsupp` implementation of `polynomial R` is well-shielded. |
| 38 | +
|
| 39 | +Unlike the case of polynomials, I felt that the exponent notation was not too easy to use, as only |
| 40 | +natural exponents would be allowed. Moreover, in the end, it seems likely that we should aim to |
| 41 | +perform computations on exponents in `ℤ` anyway and separating this via the symbol `T` seems |
| 42 | +convenient. |
| 43 | +
|
| 44 | +I made a *heavy* use of `simp` lemmas, aiming to bring Laurent polynomials to the form `C a * T n`. |
| 45 | +Any comments or suggestions for improvements is greatly appreciated! |
| 46 | +
|
| 47 | +## Future work |
| 48 | +Lots is missing! I would certainly like to show that `R[T;T⁻¹]` is the localization of `R[X]` |
| 49 | +inverting `X`. This should be mostly in place, given `exists_T_pow` (which is part of PR #13415). |
| 50 | +(Riccardo) giving a morphism (as `R`-alg, so in the commutative case) |
| 51 | +from `R[T,T⁻¹]` to `S` is the same as choosing a unit of `S`. |
| 52 | +-/ |
| 53 | + |
| 54 | +open_locale polynomial big_operators |
| 55 | +open polynomial add_monoid_algebra finsupp |
| 56 | +noncomputable theory |
| 57 | + |
| 58 | +variables {R : Type*} |
| 59 | + |
| 60 | +/-- The semiring of Laurent polynomials with coefficients in the semiring `R`. |
| 61 | +We denote it by `R[T;T⁻¹]`. |
| 62 | +The ring homomorphism `C : R →+* R[T;T⁻¹]` includes `R` as the constant polynomials. -/ |
| 63 | +abbreviation laurent_polynomial (R : Type*) [semiring R] := add_monoid_algebra R ℤ |
| 64 | + |
| 65 | +local notation R`[T;T⁻¹]`:9000 := laurent_polynomial R |
| 66 | + |
| 67 | +/-- The ring homomorphism, taking a polynomial with coefficients in `R` to a Laurent polynomial |
| 68 | +with coefficients in `R`. -/ |
| 69 | +def polynomial.to_laurent [semiring R] : R[X] →+* R[T;T⁻¹] := |
| 70 | +(map_domain_ring_hom R int.of_nat_hom).comp (to_finsupp_iso R) |
| 71 | + |
| 72 | +/-- This is not a simp lemma, as it is usually preferable to use the lemmas about `C` and `X` |
| 73 | +instead. -/ |
| 74 | +lemma polynomial.to_laurent_apply [semiring R] (p : R[X]) : |
| 75 | + p.to_laurent = p.to_finsupp.map_domain coe := rfl |
| 76 | + |
| 77 | +/-- The `R`-algebra map, taking a polynomial with coefficients in `R` to a Laurent polynomial |
| 78 | +with coefficients in `R`. -/ |
| 79 | +def polynomial.to_laurent_alg [comm_semiring R] : |
| 80 | + R[X] →ₐ[R] R[T;T⁻¹] := |
| 81 | +begin |
| 82 | + refine alg_hom.comp _ (to_finsupp_iso_alg R).to_alg_hom, |
| 83 | + exact (map_domain_alg_hom R R int.of_nat_hom), |
| 84 | +end |
| 85 | + |
| 86 | +@[simp] |
| 87 | +lemma polynomial.to_laurent_alg_apply [comm_semiring R] (f : R[X]) : |
| 88 | + f.to_laurent_alg = f.to_laurent := rfl |
| 89 | + |
| 90 | +namespace laurent_polynomial |
| 91 | + |
| 92 | +section semiring |
| 93 | +variables [semiring R] |
| 94 | + |
| 95 | +lemma single_zero_one_eq_one : (single 0 1 : R[T;T⁻¹]) = (1 : R[T;T⁻¹]) := rfl |
| 96 | + |
| 97 | +/-! ### The functions `C` and `T`. -/ |
| 98 | +/-- The ring homomorphism `C`, including `R` into the ring of Laurent polynomials over `R` as |
| 99 | +the constant Laurent polynomials. -/ |
| 100 | +def C : R →+* R[T;T⁻¹] := |
| 101 | +single_zero_ring_hom |
| 102 | + |
| 103 | +lemma algebra_map_apply {R A : Type*} [comm_semiring R] [semiring A] [algebra R A] (r : R) : |
| 104 | + algebra_map R (laurent_polynomial A) r = C (algebra_map R A r) := |
| 105 | +rfl |
| 106 | + |
| 107 | +/-- |
| 108 | +When we have `[comm_semiring R]`, the function `C` is the same as `algebra_map R R[T;T⁻¹]`. |
| 109 | +(But note that `C` is defined when `R` is not necessarily commutative, in which case |
| 110 | +`algebra_map` is not available.) |
| 111 | +-/ |
| 112 | +lemma C_eq_algebra_map {R : Type*} [comm_semiring R] (r : R) : |
| 113 | + C r = algebra_map R R[T;T⁻¹] r := |
| 114 | +rfl |
| 115 | + |
| 116 | +lemma single_eq_C (r : R) : single 0 r = C r := rfl |
| 117 | + |
| 118 | +/-- The function `n ↦ T ^ n`, implemented as a sequence `ℤ → R[T;T⁻¹]`. |
| 119 | +
|
| 120 | +Using directly `T ^ n` does not work, since we want the exponents to be of Type `ℤ` and there |
| 121 | +is no `ℤ`-power defined on `R[T;T⁻¹]`. Using that `T` is a unit introduces extra coercions. |
| 122 | +For these reasons, the definition of `T` is as a sequence. -/ |
| 123 | +def T (n : ℤ) : R[T;T⁻¹] := single n 1 |
| 124 | + |
| 125 | +@[simp] |
| 126 | +lemma T_zero : (T 0 : R[T;T⁻¹]) = 1 := rfl |
| 127 | + |
| 128 | +lemma T_add (m n : ℤ) : (T (m + n) : R[T;T⁻¹]) = T m * T n := |
| 129 | +by { convert single_mul_single.symm, simp [T] } |
| 130 | + |
| 131 | +@[simp] |
| 132 | +lemma T_pow (m : ℤ) (n : ℕ) : (T m ^ n : R[T;T⁻¹]) = T (n * m) := |
| 133 | +by rw [T, T, single_pow n, one_pow, nsmul_eq_mul, int.nat_cast_eq_coe_nat] |
| 134 | + |
| 135 | +/-- The `simp` version of `mul_assoc`, in the presence of `T`'s. -/ |
| 136 | +@[simp] |
| 137 | +lemma mul_T_assoc (f : R[T;T⁻¹]) (m n : ℤ) : f * T m * T n = f * T (m + n) := |
| 138 | +by simp [← T_add, mul_assoc] |
| 139 | + |
| 140 | +@[simp] |
| 141 | +lemma single_eq_C_mul_T (r : R) (n : ℤ) : |
| 142 | + (single n r : R[T;T⁻¹]) = (C r * T n : R[T;T⁻¹]) := |
| 143 | +by convert single_mul_single.symm; simp |
| 144 | + |
| 145 | +-- This lemma locks in the right changes and is what Lean proved directly. |
| 146 | +-- The actual `simp`-normal form of a Laurent monomial is `C a * T n`, whenever it can be reached. |
| 147 | +@[simp] |
| 148 | +lemma _root_.polynomial.to_laurent_C_mul_T (n : ℕ) (r : R) : |
| 149 | + ((polynomial.monomial n r).to_laurent : R[T;T⁻¹]) = C r * T n := |
| 150 | +show map_domain coe (monomial n r).to_finsupp = (C r * T n : R[T;T⁻¹]), |
| 151 | +by rw [to_finsupp_monomial, map_domain_single, single_eq_C_mul_T] |
| 152 | + |
| 153 | +@[simp] |
| 154 | +lemma _root_.polynomial.to_laurent_C (r : R) : |
| 155 | + (polynomial.C r).to_laurent = C r := |
| 156 | +begin |
| 157 | + convert polynomial.to_laurent_C_mul_T 0 r, |
| 158 | + simp only [int.coe_nat_zero, T_zero, mul_one], |
| 159 | +end |
| 160 | + |
| 161 | +@[simp] |
| 162 | +lemma _root_.polynomial.to_laurent_X : |
| 163 | + (polynomial.X.to_laurent : R[T;T⁻¹]) = T 1 := |
| 164 | +begin |
| 165 | + have : (polynomial.X : R[X]) = monomial 1 1, |
| 166 | + { simp [monomial_eq_C_mul_X] }, |
| 167 | + simp [this, polynomial.to_laurent_C_mul_T], |
| 168 | +end |
| 169 | + |
| 170 | +@[simp] lemma _root_.polynomial.to_laurent_one : (polynomial.to_laurent : R[X] → R[T;T⁻¹]) 1 = 1 := |
| 171 | +map_one polynomial.to_laurent |
| 172 | + |
| 173 | +@[simp] |
| 174 | +lemma _root_.polynomial.to_laurent_C_mul_eq (r : R) (f : R[X]): |
| 175 | + (polynomial.C r * f).to_laurent = C r * f.to_laurent := |
| 176 | +by simp only [_root_.map_mul, polynomial.to_laurent_C] |
| 177 | + |
| 178 | +@[simp] |
| 179 | +lemma _root_.polynomial.to_laurent_X_pow (n : ℕ) : |
| 180 | + (X ^ n : R[X]).to_laurent = T n := |
| 181 | +by simp only [map_pow, polynomial.to_laurent_X, T_pow, mul_one] |
| 182 | + |
| 183 | +@[simp] |
| 184 | +lemma _root_.polynomial.to_laurent_C_mul_X_pow (n : ℕ) (r : R) : |
| 185 | + (polynomial.C r * X ^ n).to_laurent = C r * T n := |
| 186 | +by simp only [_root_.map_mul, polynomial.to_laurent_C, polynomial.to_laurent_X_pow] |
| 187 | + |
| 188 | +instance invertible_T (n : ℤ) : invertible (T n : R[T;T⁻¹]) := |
| 189 | +{ inv_of := T (- n), |
| 190 | + inv_of_mul_self := by rw [← T_add, add_left_neg, T_zero], |
| 191 | + mul_inv_of_self := by rw [← T_add, add_right_neg, T_zero] } |
| 192 | + |
| 193 | +@[simp] |
| 194 | +lemma inv_of_T (n : ℤ) : ⅟ (T n : R[T;T⁻¹]) = T (- n) := rfl |
| 195 | + |
| 196 | +lemma is_unit_T (n : ℤ) : is_unit (T n : R[T;T⁻¹]) := |
| 197 | +is_unit_of_invertible _ |
| 198 | + |
| 199 | +end semiring |
| 200 | + |
| 201 | +end laurent_polynomial |
0 commit comments