-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathLFunction.lean
More file actions
329 lines (287 loc) · 14.4 KB
/
LFunction.lean
File metadata and controls
329 lines (287 loc) · 14.4 KB
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
/-
Copyright (c) 2026 Thomas Browning. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Thomas Browning
-/
module
public import Mathlib.NumberTheory.ArithmeticFunction.Defs
public import Mathlib.RingTheory.PowerSeries.Basic
public import Mathlib.RingTheory.PowerSeries.PiTopology
public import Mathlib.RingTheory.PowerSeries.Substitution
/-!
# Construction of L-functions
This file constructs L-functions as formal Dirichlet series.
## Main definitions
* `ArithmeticFunction.ofPowerSeries q f`: L-function `f(q⁻ˢ)` obtained from a power series `f(T)`.
* `ArithmeticFunction.eulerProduct f`: the Euler product of a family `f i` of Dirichlet series.
## Implementation notes
We take the following route from polynomials to L-functions:
* Starting from a polynomial in `T`, `PowerSeries.invOfUnit` gives the reciporical power series.
* `ofPowerSeries` gives the local Euler factor as a formal Dirichlet series on powers of `q`.
* `eulerProduct` gives the L-function as the formal product of these local Euler factors.
* `LSeries` gives the L-function as an analytic function on the right half-plane of convergence.
For example, the Riemann zeta function `ζ(s)` corresponds to taking `1 - T` at each prime `p`.
For context, here is a diagram of the possible routes from polynomials to L-functions:
T=q⁻ˢ s ∈ ℂ
[polynomials in T] ----> [polynomials in q⁻ˢ] ----> [analytic function in s]
| | |
| (reciprocal) | (reciprocal) | (reciprocal)
v T=q⁻ˢ V s ∈ ℂ V
[power series in T] ----> [power series in q⁻ˢ] ----> [analytic function in s] (the Euler factor)
| | |
| (product) | (product) | (product)
v T=q⁻ˢ V s ∈ ℂ V
[multivariate power series] ----> [Dirichlet series] ----> [L-function in s] (the Euler product)
-/
@[expose] public section
namespace ArithmeticFunction
section PowerSeries
variable {R : Type*}
section CommSemiring
variable [CommSemiring R]
/-- The arithmetic function corresponding to the Dirichlet series `f(q⁻ˢ)`.
For example, if `f = 1 + X + X² + ...` and `q = p`, then `f(q⁻ˢ) = 1 + p⁻ˢ + p⁻²ˢ + ...`.
If `q ≤ 1` then `k ↦ q ^ k` is not injective, so we use the junk value `f.constantCoeff`. -/
noncomputable def ofPowerSeries (q : ℕ) : PowerSeries R →ₐ[R] ArithmeticFunction R where
toFun f := if hq : 1 < q then
⟨Function.extend (q ^ ·) (f.coeff ·) 0, by simp [Nat.ne_zero_of_lt hq]⟩ else
algebraMap R (ArithmeticFunction R) f.constantCoeff
map_zero' := by ext; split_ifs <;> simp [Function.extend]
-- note that `ofPowerSeries.map_one'` relies on the junk value `f.constantCoeff`.
map_one' := by
ext n
split_ifs with hq
· by_cases hn : ∃ k, q ^ k = n
· obtain ⟨a, rfl⟩ := hn
simp [(Nat.pow_right_injective hq).extend_apply, one_apply, hq.ne']
· simp [hn, one_apply_ne (fun H ↦ hn ⟨0, H.symm⟩)]
· simp
map_add' f g := by
ext n
split_ifs with hq
· by_cases h : ∃ a, q ^ a = n
· obtain ⟨a, rfl⟩ := h
simp [(Nat.pow_right_injective hq).extend_apply]
· simp [h]
· by_cases hn : n = 1 <;> simp [hn]
map_mul' f g := by
ext n
split_ifs with hq
· simp_rw [mul_apply, coe_mk]
by_cases hn : ∃ a, q ^ a = n
· obtain ⟨k, rfl⟩ := hn
rw [(Nat.pow_right_injective hq).extend_apply]
have hs : (Finset.antidiagonal k).map (.prodMap ⟨fun k ↦ q ^ k, Nat.pow_right_injective hq⟩
⟨fun k ↦ q ^ k, Nat.pow_right_injective hq⟩) ⊆ (q ^ k).divisorsAntidiagonal :=
Nat.antidiagonal_map_subset_divisorsAntidiagonal_pow hq k
rw [PowerSeries.coeff_mul k f g, ← Finset.sum_subset hs]
· simp [(Nat.pow_right_injective hq).extend_apply]
· intro (a, b) hab h
by_cases ha : ∃ i, q ^ i = a
· by_cases hb : ∃ j, q ^ j = b
· obtain ⟨i, rfl⟩ := ha
obtain ⟨j, rfl⟩ := hb
rw [Nat.mem_divisorsAntidiagonal, ← pow_add, Nat.pow_right_inj hq] at hab
simp_rw [Finset.mem_map, not_exists, not_and, Finset.mem_antidiagonal] at h
simpa using h (i, j) hab.1
· rwa [mul_comm, Function.extend_apply', Pi.zero_apply, zero_mul]
· rwa [Function.extend_apply', Pi.zero_apply, zero_mul]
· rw [Function.extend_apply' _ _ _ hn, Pi.zero_apply, Finset.sum_eq_zero]
intro (a, b) hk
obtain ⟨hab, -⟩ := Nat.mem_divisorsAntidiagonal.mp hk
by_cases ha : ∃ i, q ^ i = a
· by_cases hb : ∃ j, q ^ j = b
· obtain ⟨i, rfl⟩ := ha
obtain ⟨j, rfl⟩ := hb
rw [← pow_add] at hab
exact (hn ⟨i + j, hab⟩).elim
· rwa [mul_comm, Function.extend_apply', Pi.zero_apply, zero_mul]
· rwa [Function.extend_apply', Pi.zero_apply, zero_mul]
· simp
commutes' x := by
ext n
split_ifs with hq
· simp only [Algebra.algebraMap_eq_smul_one, coe_mk]
by_cases hn : ∃ k, q ^ k = n
· obtain ⟨k, rfl⟩ := hn
simp [(Nat.pow_right_injective hq).extend_apply, one_apply, hq.ne']
· rw [Function.extend_apply' _ _ _ hn, Pi.zero_apply, smul_map, one_apply_ne, smul_zero]
contrapose hn
exact ⟨0, by simp [hn]⟩
· simp
theorem ofPowerSeries_apply {q : ℕ} (hq : 1 < q) (f : PowerSeries R) (n : ℕ) :
ofPowerSeries q f n = Function.extend (q ^ ·) (f.coeff ·) 0 n := by
simp [ofPowerSeries, dif_pos hq]
theorem ofPowerSeries_apply_pow {q : ℕ} (hq : 1 < q) (f : PowerSeries R) (k : ℕ) :
ofPowerSeries q f (q ^ k) = f.coeff k := by
rw [ofPowerSeries_apply hq, (Nat.pow_right_injective hq).extend_apply]
theorem ofPowerSeries_apply_zero (q : ℕ) (f : PowerSeries R) : ofPowerSeries q f 0 = 0 := by
simp
@[simp]
-- note that `ofPowerSeries_apply_one` relies on the junk value `f.constantCoeff`.
theorem ofPowerSeries_apply_one (q : ℕ) (f : PowerSeries R) :
ofPowerSeries q f 1 = f.constantCoeff := by
by_cases hq : 1 < q
· rw [← pow_zero q, ofPowerSeries_apply_pow hq, PowerSeries.coeff_zero_eq_constantCoeff]
· simp [ofPowerSeries, dif_neg hq]
end CommSemiring
section CommRing
variable [CommRing R]
/-- In `ArithmeticFunction.ofPowerSeries`, replacing the base `q` with a power `q ^ k` corresponds
to substituting `X` with `X ^ k` in the original power series. -/
theorem ofPowerSeries_pow (q : ℕ) {k : ℕ} (hk : k ≠ 0) (f : PowerSeries R) :
ofPowerSeries (q ^ k) f = ofPowerSeries q (f.subst (PowerSeries.X ^ k)) := by
classical
by_cases hq : 1 < q
· ext n
by_cases hn : ∃ i, q ^ i = n
· obtain ⟨i, rfl⟩ := hn
rw [ofPowerSeries_apply_pow hq, PowerSeries.coeff_subst_X_pow hk]
split_ifs with hn
· obtain ⟨j, rfl⟩ := hn
rw [pow_mul, ofPowerSeries_apply_pow (one_lt_pow' hq hk)]
simp [hk]
· rw [ofPowerSeries_apply (one_lt_pow' hq hk), Function.extend_apply', Pi.zero_apply]
simp_rw [← pow_mul, Nat.pow_right_inj hq, eq_comm, ← dvd_def]
exact hn
· rwa [ofPowerSeries_apply hq, ofPowerSeries_apply (one_lt_pow' hq hk),
Function.extend_apply', Function.extend_apply']
contrapose hn
obtain ⟨i, rfl⟩ := hn
exact ⟨k * i, pow_mul q k i⟩
· simp [ofPowerSeries, hq, hk]
-- todo: generalize to `CommSemiring`
/-- `ArithmeticFunction.ofPowerSeries` produces multiplicative power series. -/
theorem isMultiplicative_ofPowerSeries_of_isPrimePow
(q : ℕ) (hq : IsPrimePow q) (f : PowerSeries R) (hf : f.constantCoeff = 1) :
IsMultiplicative (ofPowerSeries q f) := by
refine ⟨(ofPowerSeries_apply_one q f).trans hf, fun {m n} hmn ↦ ?_⟩
obtain ⟨p, k, hp, hk, rfl⟩ := hq
rw [← Nat.prime_iff] at hp
rw [ofPowerSeries_pow p hk.ne']
by_cases hm : ∃ i, p ^ i = m
· obtain ⟨i, rfl⟩ := hm
by_cases hn : ∃ j, p ^ j = n
· obtain ⟨j, rfl⟩ := hn
cases i
· simp [hk.ne', hf]
· cases j
· simp [hk.ne', hf]
· simp [hp.ne_one] at hmn
· simp_rw [ofPowerSeries_apply hp.one_lt]
rw [Function.extend_apply', Function.extend_apply' _ _ _ hn,
Pi.zero_apply, Pi.zero_apply, mul_zero]
contrapose hn
obtain ⟨j, hj⟩ := hn
obtain ⟨v, -, rfl⟩ := (Nat.dvd_prime_pow hp).mp (Dvd.intro_left _ hj.symm)
exact ⟨v, rfl⟩
· simp_rw [ofPowerSeries_apply hp.one_lt]
rw [Function.extend_apply', Function.extend_apply' _ _ _ hm,
Pi.zero_apply, Pi.zero_apply, zero_mul]
contrapose hm
obtain ⟨i, hi⟩ := hm
obtain ⟨j, -, rfl⟩ := (Nat.dvd_prime_pow hp).mp ⟨n, hi⟩
exact ⟨j, rfl⟩
end CommRing
end PowerSeries
section EulerProduct
open Filter
variable {ι R : Type*} [CommSemiring R]
/-- A private uniform space instance on `ArithmeticFunction R` in order to define `eulerProduct` as
a `tprod`. If `R` is viewed as having the discrete topology, then the resulting topology on
`ArithmeticFunction R` is the topology of pointwise convergence (see `tendsto_iff`).
See `tendsTo_eulerProduct_of_tendsTo` for the outward facing `eulerProduct` API. -/
local instance uniformSpace : UniformSpace (ArithmeticFunction R) :=
letI : UniformSpace R := ⊥
.comap ((↑) : ArithmeticFunction R → (ℕ → R)) inferInstance
/-- A family `f i : ArithmeticFunction R` tends to `g` if and only if for each `n`, the `n`th
coefficient of `f i` is eventually equal to the `n`th coefficient of `g`. If `R` is viewed as
having the discrete topology, then this is the topology of pointwise convergence.
See `tendsTo_eulerProduct_of_tendsTo` for the outward facing `eulerProduct` API. -/
private theorem tendsto_iff
{f : ι → ArithmeticFunction R} {F : Filter ι} {g : ArithmeticFunction R} :
Tendsto f F (nhds g) ↔ ∀ n, ∀ᶠ i in F, f i n = g n := by
let : UniformSpace R := ⊥
have : Topology.IsInducing ((↑) : ArithmeticFunction R → (ℕ → R)) := ⟨rfl⟩
simp [this.tendsto_nhds_iff, tendsto_pi_nhds]
/-- The uniform space structure on arithmetic functions is complete.
See `tendsTo_eulerProduct_of_tendsTo` for the outward facing `eulerProduct` API. -/
local instance : CompleteSpace (ArithmeticFunction R) := by
let : UniformSpace R := ⊥
apply IsUniformInducing.completeSpace ⟨rfl⟩
apply IsClosed.isComplete
have : Set.range ((↑) : ArithmeticFunction R → (ℕ → R)) = {f | f 0 = 0} := by
ext f
exact ⟨by rintro ⟨f, rfl⟩; simp, fun hf ↦ ⟨⟨f, hf⟩, rfl⟩⟩
rw [ArithmeticFunction.range_coe]
apply isClosed_setOf_map_zero
/-- The Euler product of a family of arithmetic functions. Defined as a `tprod`, but see
`tendsTo_eulerProduct_of_tendsTo` for the outward facing `eulerProduct` API. -/
noncomputable def eulerProduct (f : ι → ArithmeticFunction R) : ArithmeticFunction R :=
∏' i, f i
/-- If arithmetic functions `f i` converges to `1` pointwise, then the partial products
`∏ i ∈ s, f i` converge to `eulerProduct f` pointwise. -/
theorem tendsTo_eulerProduct_of_tendsTo (f : ι → ArithmeticFunction R)
(hf : ∀ n, ∀ᶠ i in cofinite, f i n = (1 : ArithmeticFunction R) n) :
∀ n, ∀ᶠ s in atTop, (∏ i ∈ s, f i) n = eulerProduct f n := by
let : UniformSpace R := ⊥
have : IsUniformInducing ((↑) : ArithmeticFunction R → (ℕ → R)) := ⟨rfl⟩
classical
suffices Multipliable f from tendsto_iff.mp this.hasProd
simp_rw [multipliable_iff_cauchySeq_finset, CauchySeq, ← this.cauchy_map_iff,
Filter.map_map, cauchy_map_iff', Pi.uniformity, DiscreteUniformity.eq_principal_setRelId,
tendsto_iInf, tendsto_comap_iff, tendsto_principal, Function.comp_apply, prod_atTop_atTop_eq,
eventually_atTop_prod_self, SetRel.mem_id]
intro n
replace hf : ∀ k ∈ Set.Iic n, ∀ᶠ (x : ι) in cofinite, (f x) k = (1 : ArithmeticFunction R) k :=
fun k hk ↦ hf k
rw [← eventually_all_finite (Set.finite_Iic n), eventually_iff_exists_mem] at hf
obtain ⟨s, hs, hs'⟩ := hf
let t := (mem_cofinite.mp hs).toFinset
refine ⟨t, fun u v hu hv ↦ ?_⟩
rw [← Finset.prod_sdiff hu, ← Finset.prod_sdiff hv]
replace hu : ∀ i ∈ u \ t, i ∈ s := by
intro i hi
rw [Finset.mem_sdiff, Set.Finite.mem_toFinset, Set.notMem_compl_iff] at hi
exact hi.2
replace hv : ∀ i ∈ v \ t, i ∈ s := by
intro i hi
rw [Finset.mem_sdiff, Set.Finite.mem_toFinset, Set.notMem_compl_iff] at hi
exact hi.2
suffices ∀ k ≤ n, (∏ x ∈ u \ t, f x) k = (∏ x ∈ v \ t, f x) k by
rw [mul_apply, mul_apply]
refine Finset.sum_congr rfl fun k hk ↦ ?_
rw [this k.1 (Nat.divisor_le (Nat.fst_mem_divisors_of_mem_antidiagonal hk))]
suffices ∀ w, (∀ i ∈ w, i ∈ s) → ∀ k ≤ n, (∏ x ∈ w, f x) k = (1 : ArithmeticFunction R) k by
intro k hk
rw [this (u \ t) hu k hk, this (v \ t) hv k hk]
intro w hw
induction w using Finset.induction_on
case empty => simp
case insert i w hi hw' =>
intro k hk
rw [← one_mul (1 : ArithmeticFunction R), Finset.prod_insert hi, mul_apply, mul_apply]
refine Finset.sum_congr rfl fun j hj ↦ ?_
have h1 := hs' i (hw i (Finset.mem_insert_self i w)) j.1
((Nat.divisor_le (Nat.fst_mem_divisors_of_mem_antidiagonal hj)).trans hk)
have h2 := hw' (fun i hi ↦ hw i (Finset.mem_insert_of_mem hi)) j.2
((Nat.divisor_le (Nat.snd_mem_divisors_of_mem_antidiagonal hj)).trans hk)
rw [h1, h2]
theorem isMultiplicative_eulerProduct (f : ι → ArithmeticFunction R)
(hf : ∀ i, IsMultiplicative (f i)) : IsMultiplicative (eulerProduct f) := by
by_cases hf' : Multipliable f
· have h (s : Finset ι) : (∏ b ∈ s, f b).IsMultiplicative :=
isMultiplicative_finsetProd f s fun i a ↦ hf i
have key := tendsto_iff.mp hf'.hasProd
refine (forall_and.mp h).imp (fun h ↦ ?_) fun h m n hmn ↦ ?_
· specialize key 1
simp_rw [h] at key
rwa [eventually_const, eq_comm] at key
· replace h s : (∏ b ∈ s, f b) (m * n) = (∏ b ∈ s, f b) m * (∏ b ∈ s, f b) n := h s hmn
have h2 := key (m * n)
simp_rw [h] at h2
exact eventually_const.mp (EventuallyEq.trans (.symm h2) (.mul (key m) (key n)))
· rw [eulerProduct, tprod_eq_one_of_not_multipliable hf']
exact isMultiplicative_one
end EulerProduct
end ArithmeticFunction