-
Notifications
You must be signed in to change notification settings - Fork 259
/
Basic.lean
354 lines (267 loc) Β· 13.4 KB
/
Basic.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
/-
Copyright (c) 2020 Johan Commelin. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johan Commelin, Robert Y. Lewis
-/
import Mathlib.Algebra.MvPolynomial.Counit
import Mathlib.Algebra.MvPolynomial.Invertible
import Mathlib.RingTheory.WittVector.Defs
#align_import ring_theory.witt_vector.basic from "leanprover-community/mathlib"@"9556784a5b84697562e9c6acb40500d4a82e675a"
/-!
# Witt vectors
This file verifies that the ring operations on `WittVector p R`
satisfy the axioms of a commutative ring.
## Main definitions
* `WittVector.map`: lifts a ring homomorphism `R β+* S` to a ring homomorphism `π R β+* π S`.
* `WittVector.ghostComponent n x`: evaluates the `n`th Witt polynomial
on the first `n` coefficients of `x`, producing a value in `R`.
This is a ring homomorphism.
* `WittVector.ghostMap`: a ring homomorphism `π R β+* (β β R)`, obtained by packaging
all the ghost components together.
If `p` is invertible in `R`, then the ghost map is an equivalence,
which we use to define the ring operations on `π R`.
* `WittVector.CommRing`: the ring structure induced by the ghost components.
## Notation
We use notation `π R`, entered `\bbW`, for the Witt vectors over `R`.
## Implementation details
As we prove that the ghost components respect the ring operations, we face a number of repetitive
proofs. To avoid duplicating code we factor these proofs into a custom tactic, only slightly more
powerful than a tactic macro. This tactic is not particularly useful outside of its applications
in this file.
## References
* [Hazewinkel, *Witt Vectors*][Haze09]
* [Commelin and Lewis, *Formalizing the Ring of Witt Vectors*][CL21]
-/
noncomputable section
open MvPolynomial Function
variable {p : β} {R S T : Type*} [hp : Fact p.Prime] [CommRing R] [CommRing S] [CommRing T]
variable {Ξ± : Type*} {Ξ² : Type*}
local notation "π" => WittVector p
local notation "W_" => wittPolynomial p
-- type as `\bbW`
open scoped Witt
namespace WittVector
/-- `f : Ξ± β Ξ²` induces a map from `π Ξ±` to `π Ξ²` by applying `f` componentwise.
If `f` is a ring homomorphism, then so is `f`, see `WittVector.map f`. -/
def mapFun (f : Ξ± β Ξ²) : π Ξ± β π Ξ² := fun x => mk _ (f β x.coeff)
#align witt_vector.map_fun WittVector.mapFun
namespace mapFun
-- Porting note: switched the proof to tactic mode. I think that `ext` was the issue.
theorem injective (f : Ξ± β Ξ²) (hf : Injective f) : Injective (mapFun f : π Ξ± β π Ξ²) := by
intros _ _ h
ext p
exact hf (congr_arg (fun x => coeff x p) h : _)
#align witt_vector.map_fun.injective WittVector.mapFun.injective
theorem surjective (f : Ξ± β Ξ²) (hf : Surjective f) : Surjective (mapFun f : π Ξ± β π Ξ²) := fun x =>
β¨mk _ fun n => Classical.choose <| hf <| x.coeff n,
by ext n; simp only [mapFun, coeff_mk, comp_apply, Classical.choose_spec (hf (x.coeff n))]β©
#align witt_vector.map_fun.surjective WittVector.mapFun.surjective
-- Porting note: using `(x y : π R)` instead of `(x y : WittVector p R)` produced sorries.
variable (f : R β+* S) (x y : WittVector p R)
/-- Auxiliary tactic for showing that `mapFun` respects the ring operations. -/
-- porting note: a very crude port.
macro "map_fun_tac" : tactic => `(tactic| (
ext n
simp only [mapFun, mk, comp_apply, zero_coeff, map_zero,
-- Porting note: the lemmas on the next line do not have the `simp` tag in mathlib4
add_coeff, sub_coeff, mul_coeff, neg_coeff, nsmul_coeff, zsmul_coeff, pow_coeff,
peval, map_aeval, algebraMap_int_eq, coe_evalβHom] <;>
try { cases n <;> simp <;> done } <;> -- Porting note: this line solves `one`
apply evalβHom_congr (RingHom.ext_int _ _) _ rfl <;>
ext β¨i, kβ© <;>
fin_cases i <;> rfl))
-- and until `pow`.
-- We do not tag these lemmas as `@[simp]` because they will be bundled in `map` later on.
theorem zero : mapFun f (0 : π R) = 0 := by map_fun_tac
#align witt_vector.map_fun.zero WittVector.mapFun.zero
theorem one : mapFun f (1 : π R) = 1 := by map_fun_tac
#align witt_vector.map_fun.one WittVector.mapFun.one
theorem add : mapFun f (x + y) = mapFun f x + mapFun f y := by map_fun_tac
#align witt_vector.map_fun.add WittVector.mapFun.add
theorem sub : mapFun f (x - y) = mapFun f x - mapFun f y := by map_fun_tac
#align witt_vector.map_fun.sub WittVector.mapFun.sub
theorem mul : mapFun f (x * y) = mapFun f x * mapFun f y := by map_fun_tac
#align witt_vector.map_fun.mul WittVector.mapFun.mul
theorem neg : mapFun f (-x) = -mapFun f x := by map_fun_tac
#align witt_vector.map_fun.neg WittVector.mapFun.neg
theorem nsmul (n : β) (x : WittVector p R) : mapFun f (n β’ x) = n β’ mapFun f x := by map_fun_tac
#align witt_vector.map_fun.nsmul WittVector.mapFun.nsmul
theorem zsmul (z : β€) (x : WittVector p R) : mapFun f (z β’ x) = z β’ mapFun f x := by map_fun_tac
#align witt_vector.map_fun.zsmul WittVector.mapFun.zsmul
theorem pow (n : β) : mapFun f (x ^ n) = mapFun f x ^ n := by map_fun_tac
#align witt_vector.map_fun.pow WittVector.mapFun.pow
theorem natCast (n : β) : mapFun f (n : π R) = n :=
show mapFun f n.unaryCast = (n : WittVector p S) by
induction n <;> simp [*, Nat.unaryCast, add, one, zero] <;> rfl
#align witt_vector.map_fun.nat_cast WittVector.mapFun.natCast
@[deprecated (since := "2024-04-17")]
alias nat_cast := natCast
theorem intCast (n : β€) : mapFun f (n : π R) = n :=
show mapFun f n.castDef = (n : WittVector p S) by
cases n <;> simp [*, Int.castDef, add, one, neg, zero, natCast] <;> rfl
#align witt_vector.map_fun.int_cast WittVector.mapFun.intCast
@[deprecated (since := "2024-04-17")]
alias int_cast := intCast
end mapFun
end WittVector
namespace WittVector
/-- Evaluates the `n`th Witt polynomial on the first `n` coefficients of `x`,
producing a value in `R`.
This function will be bundled as the ring homomorphism `WittVector.ghostMap`
once the ring structure is available,
but we rely on it to set up the ring structure in the first place. -/
private def ghostFun : π R β β β R := fun x n => aeval x.coeff (W_ β€ n)
section Tactic
open Lean Elab Tactic
/-- An auxiliary tactic for proving that `ghostFun` respects the ring operations. -/
elab "ghost_fun_tac" Ο:term "," fn:term : tactic => do
evalTactic (β `(tactic| (
ext n
have := congr_fun (congr_arg (@peval R _ _) (wittStructureInt_prop p $Ο n)) $fn
simp only [wittZero, OfNat.ofNat, Zero.zero, wittOne, One.one,
HAdd.hAdd, Add.add, HSub.hSub, Sub.sub, Neg.neg, HMul.hMul, Mul.mul,HPow.hPow, Pow.pow,
wittNSMul, wittZSMul, HSMul.hSMul, SMul.smul]
simpa (config := { unfoldPartialApp := true }) [WittVector.ghostFun, aeval_rename, aeval_bindβ,
comp, uncurry, peval, eval] using this
)))
end Tactic
section GhostFun
variable (x y : WittVector p R)
-- The following lemmas are not `@[simp]` because they will be bundled in `ghostMap` later on.
@[local simp]
theorem matrix_vecEmpty_coeff {R} (i j) :
@coeff p R (Matrix.vecEmpty i) j = (Matrix.vecEmpty i : β β R) j := by
rcases i with β¨_ | _ | _ | _ | i_val, β¨β©β©
#align witt_vector.matrix_vec_empty_coeff WittVector.matrix_vecEmpty_coeff
private theorem ghostFun_zero : ghostFun (0 : π R) = 0 := by
ghost_fun_tac 0, ![]
private theorem ghostFun_one : ghostFun (1 : π R) = 1 := by
ghost_fun_tac 1, ![]
private theorem ghostFun_add : ghostFun (x + y) = ghostFun x + ghostFun y := by
ghost_fun_tac X 0 + X 1, ![x.coeff, y.coeff]
private theorem ghostFun_natCast (i : β) : ghostFun (i : π R) = i :=
show ghostFun i.unaryCast = _ by
induction i <;>
simp [*, Nat.unaryCast, ghostFun_zero, ghostFun_one, ghostFun_add, -Pi.natCast_def]
@[deprecated (since := "2024-04-17")]
alias ghostFun_nat_cast := ghostFun_natCast
private theorem ghostFun_sub : ghostFun (x - y) = ghostFun x - ghostFun y := by
ghost_fun_tac X 0 - X 1, ![x.coeff, y.coeff]
private theorem ghostFun_mul : ghostFun (x * y) = ghostFun x * ghostFun y := by
ghost_fun_tac X 0 * X 1, ![x.coeff, y.coeff]
private theorem ghostFun_neg : ghostFun (-x) = -ghostFun x := by ghost_fun_tac -X 0, ![x.coeff]
private theorem ghostFun_intCast (i : β€) : ghostFun (i : π R) = i :=
show ghostFun i.castDef = _ by
cases i <;> simp [*, Int.castDef, ghostFun_natCast, ghostFun_neg, -Pi.natCast_def,
-Pi.intCast_def]
@[deprecated (since := "2024-04-17")]
alias ghostFun_int_cast := ghostFun_intCast
private lemma ghostFun_nsmul (m : β) (x : WittVector p R) : ghostFun (m β’ x) = m β’ ghostFun x := by
ghost_fun_tac m β’ (X 0), ![x.coeff]
private lemma ghostFun_zsmul (m : β€) (x : WittVector p R) : ghostFun (m β’ x) = m β’ ghostFun x := by
ghost_fun_tac m β’ (X 0), ![x.coeff]
private theorem ghostFun_pow (m : β) : ghostFun (x ^ m) = ghostFun x ^ m := by
ghost_fun_tac X 0 ^ m, ![x.coeff]
end GhostFun
variable (p) (R)
/-- The bijection between `π R` and `β β R`, under the assumption that `p` is invertible in `R`.
In `WittVector.ghostEquiv` we upgrade this to an isomorphism of rings. -/
private def ghostEquiv' [Invertible (p : R)] : π R β (β β R) where
toFun := ghostFun
invFun x := mk p fun n => aeval x (xInTermsOfW p R n)
left_inv := by
intro x
ext n
have := bindβ_wittPolynomial_xInTermsOfW p R n
apply_fun aeval x.coeff at this
simpa (config := { unfoldPartialApp := true }) only [aeval_bindβ, aeval_X, ghostFun,
aeval_wittPolynomial]
right_inv := by
intro x
ext n
have := bindβ_xInTermsOfW_wittPolynomial p R n
apply_fun aeval x at this
simpa only [aeval_bindβ, aeval_X, ghostFun, aeval_wittPolynomial]
@[local instance]
private def comm_ring_auxβ : CommRing (π (MvPolynomial R β)) :=
(ghostEquiv' p (MvPolynomial R β)).injective.commRing ghostFun ghostFun_zero ghostFun_one
ghostFun_add ghostFun_mul ghostFun_neg ghostFun_sub ghostFun_nsmul ghostFun_zsmul
ghostFun_pow ghostFun_natCast ghostFun_intCast
@[local instance]
private abbrev comm_ring_auxβ : CommRing (π (MvPolynomial R β€)) :=
(mapFun.injective _ <| map_injective (Int.castRingHom β) Int.cast_injective).commRing _
(mapFun.zero _) (mapFun.one _) (mapFun.add _) (mapFun.mul _) (mapFun.neg _) (mapFun.sub _)
(mapFun.nsmul _) (mapFun.zsmul _) (mapFun.pow _) (mapFun.natCast _) (mapFun.intCast _)
/-- The commutative ring structure on `π R`. -/
instance : CommRing (π R) :=
(mapFun.surjective _ <| counit_surjective _).commRing (mapFun <| MvPolynomial.counit _)
(mapFun.zero _) (mapFun.one _) (mapFun.add _) (mapFun.mul _) (mapFun.neg _) (mapFun.sub _)
(mapFun.nsmul _) (mapFun.zsmul _) (mapFun.pow _) (mapFun.natCast _) (mapFun.intCast _)
variable {p R}
/-- `WittVector.map f` is the ring homomorphism `π R β+* π S` naturally induced
by a ring homomorphism `f : R β+* S`. It acts coefficientwise. -/
noncomputable def map (f : R β+* S) : π R β+* π S where
toFun := mapFun f
map_zero' := mapFun.zero f
map_one' := mapFun.one f
map_add' := mapFun.add f
map_mul' := mapFun.mul f
#align witt_vector.map WittVector.map
theorem map_injective (f : R β+* S) (hf : Injective f) : Injective (map f : π R β π S) :=
mapFun.injective f hf
#align witt_vector.map_injective WittVector.map_injective
theorem map_surjective (f : R β+* S) (hf : Surjective f) : Surjective (map f : π R β π S) :=
mapFun.surjective f hf
#align witt_vector.map_surjective WittVector.map_surjective
@[simp]
theorem map_coeff (f : R β+* S) (x : π R) (n : β) : (map f x).coeff n = f (x.coeff n) :=
rfl
#align witt_vector.map_coeff WittVector.map_coeff
/-- `WittVector.ghostMap` is a ring homomorphism that maps each Witt vector
to the sequence of its ghost components. -/
def ghostMap : π R β+* β β R where
toFun := ghostFun
map_zero' := ghostFun_zero
map_one' := ghostFun_one
map_add' := ghostFun_add
map_mul' := ghostFun_mul
#align witt_vector.ghost_map WittVector.ghostMap
/-- Evaluates the `n`th Witt polynomial on the first `n` coefficients of `x`,
producing a value in `R`. -/
def ghostComponent (n : β) : π R β+* R :=
(Pi.evalRingHom _ n).comp ghostMap
#align witt_vector.ghost_component WittVector.ghostComponent
theorem ghostComponent_apply (n : β) (x : π R) : ghostComponent n x = aeval x.coeff (W_ β€ n) :=
rfl
#align witt_vector.ghost_component_apply WittVector.ghostComponent_apply
@[simp]
theorem ghostMap_apply (x : π R) (n : β) : ghostMap x n = ghostComponent n x :=
rfl
#align witt_vector.ghost_map_apply WittVector.ghostMap_apply
section Invertible
variable (p R)
variable [Invertible (p : R)]
/-- `WittVector.ghostMap` is a ring isomorphism when `p` is invertible in `R`. -/
def ghostEquiv : π R β+* (β β R) :=
{ (ghostMap : π R β+* β β R), ghostEquiv' p R with }
#align witt_vector.ghost_equiv WittVector.ghostEquiv
@[simp]
theorem ghostEquiv_coe : (ghostEquiv p R : π R β+* β β R) = ghostMap :=
rfl
#align witt_vector.ghost_equiv_coe WittVector.ghostEquiv_coe
theorem ghostMap.bijective_of_invertible : Function.Bijective (ghostMap : π R β β β R) :=
(ghostEquiv p R).bijective
#align witt_vector.ghost_map.bijective_of_invertible WittVector.ghostMap.bijective_of_invertible
end Invertible
/-- `WittVector.coeff x 0` as a `RingHom` -/
@[simps]
noncomputable def constantCoeff : π R β+* R where
toFun x := x.coeff 0
map_zero' := by simp
map_one' := by simp
map_add' := add_coeff_zero
map_mul' := mul_coeff_zero
#align witt_vector.constant_coeff WittVector.constantCoeff
instance [Nontrivial R] : Nontrivial (π R) :=
constantCoeff.domain_nontrivial
end WittVector