Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit dfe1897

Browse files
adomanieric-wieser
andcommitted
feat(data/polynomial/laurent): laurent polynomials -- defs and some API (#13784)
I broke off the initial part of #13415 into this initial segment, leaving the rest of the PR as depending on this one. Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
1 parent 58d83ed commit dfe1897

File tree

1 file changed

+201
-0
lines changed

1 file changed

+201
-0
lines changed

src/data/polynomial/laurent.lean

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
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

Comments
 (0)