@@ -3,8 +3,9 @@ Copyright (c) 2024 Chris Birkbeck. All rights reserved.
3
3
Released under Apache 2.0 license as described in the file LICENSE.
4
4
Authors: Chris Birkbeck, David Loeffler
5
5
-/
6
+ import Mathlib.Algebra.EuclideanDomain.Int
6
7
import Mathlib.NumberTheory.ModularForms.SlashInvariantForms
7
- import Mathlib.NumberTheory.ModularForms.CongruenceSubgroups
8
+ import Mathlib.RingTheory.EuclideanDomain
8
9
9
10
/-!
10
11
# Eisenstein Series
@@ -25,52 +26,139 @@ import Mathlib.NumberTheory.ModularForms.CongruenceSubgroups
25
26
26
27
noncomputable section
27
28
28
- open ModularForm UpperHalfPlane Complex Matrix CongruenceSubgroup
29
+ open ModularForm UpperHalfPlane Complex Matrix CongruenceSubgroup Set
29
30
30
31
open scoped MatrixGroups
31
32
32
33
namespace EisensteinSeries
33
34
34
- variable (N : ℕ) (a : Fin 2 → ZMod N)
35
+ variable (N r : ℕ) (a : Fin 2 → ZMod N)
35
36
36
37
section gammaSet_def
37
38
38
- /-- The set of pairs of coprime integers congruent to `a` mod `N`. -/
39
- def gammaSet := {v : Fin 2 → ℤ | (↑) ∘ v = a ∧ IsCoprime (v 0 ) (v 1 )}
39
+ /-- The set of pairs of integers congruent to `a` mod `N` and with `gcd` equal to `r `. -/
40
+ def gammaSet := {v : Fin 2 → ℤ | (↑) ∘ v = a ∧ (v 0 ).gcd (v 1 ) = r }
40
41
41
42
open scoped Function in -- required for scoped `on` notation
42
- lemma pairwise_disjoint_gammaSet : Pairwise (Disjoint on gammaSet N) := by
43
+ lemma pairwise_disjoint_gammaSet : Pairwise (Disjoint on gammaSet N r ) := by
43
44
refine fun u v huv ↦ ?_
44
45
contrapose! huv
45
46
obtain ⟨f, hf⟩ := Set.not_disjoint_iff.mp huv
46
47
exact hf.1 .1 .symm.trans hf.2 .1
47
48
48
49
/-- For level `N = 1`, the gamma sets are all equal. -/
49
- lemma gammaSet_one_eq (a a' : Fin 2 → ZMod 1 ) : gammaSet 1 a = gammaSet 1 a' :=
50
+ lemma gammaSet_one_const (a a' : Fin 2 → ZMod 1 ) : gammaSet 1 r a = gammaSet 1 r a' :=
50
51
congr_arg _ (Subsingleton.elim _ _)
51
52
53
+ /-- For level `N = 1`, the gamma sets simplify to only a `gcd` condition. -/
54
+ lemma gammaSet_one_eq (a : Fin 2 → ZMod 1 ) :
55
+ gammaSet 1 r a = {v : Fin 2 → ℤ | (v 0 ).gcd (v 1 ) = r} := by
56
+ simp [gammaSet, Subsingleton.eq_zero]
57
+
58
+ lemma gammaSet_one_mem_iff (v : Fin 2 → ℤ) : v ∈ gammaSet 1 r 0 ↔ (v 0 ).gcd (v 1 ) = r := by
59
+ simp [gammaSet, Subsingleton.eq_zero]
60
+
52
61
/-- For level `N = 1`, the gamma sets are all equivalent; this is the equivalence. -/
53
- def gammaSet_one_equiv (a a' : Fin 2 → ZMod 1 ) : gammaSet 1 a ≃ gammaSet 1 a' :=
54
- Equiv.setCongr (gammaSet_one_eq a a')
62
+ def gammaSet_one_equiv (a a' : Fin 2 → ZMod 1 ) : gammaSet 1 r a ≃ gammaSet 1 r a' :=
63
+ Equiv.setCongr (gammaSet_one_const r a a')
64
+
65
+ /-- The map from `Fin 2 → ℤ` sending `![a,b]` to `a.gcd b`. -/
66
+ abbrev finGcdMap (v : Fin 2 → ℤ) : ℕ := (v 0 ).gcd (v 1 )
67
+
68
+ lemma finGcdMap_div {r : ℕ} [NeZero r] (v : Fin 2 → ℤ) (hv : finGcdMap v = r) :
69
+ IsCoprime ((v / r) 0 ) ((v / r) 1 ) := by
70
+ rw [← hv]
71
+ apply isCoprime_div_gcd_div_gcd_of_gcd_ne_zero
72
+ have := NeZero.ne r
73
+ aesop
74
+
75
+ lemma finGcdMap_smul {r : ℕ} (a : ℤ) {v : Fin 2 → ℤ} (hv : finGcdMap v = r) :
76
+ finGcdMap (a • v) = a.natAbs * r := by
77
+ simp [finGcdMap, Int.gcd_mul_left, hv]
78
+
79
+ /-- An abbreviation of the map which divides a integer vector by an integer. -/
80
+ abbrev divIntMap (r : ℤ) {m : ℕ} (v : Fin m → ℤ) : Fin m → ℤ := v / r
81
+
82
+ lemma mem_gammaSet_one (v : Fin 2 → ℤ) : v ∈ gammaSet 1 1 0 ↔ IsCoprime (v 0 ) (v 1 ) := by
83
+ rw [gammaSet_one_mem_iff, Int.isCoprime_iff_gcd_eq_one]
84
+
85
+ lemma gammaSet_div_gcd {r : ℕ} {v : Fin 2 → ℤ} (hv : v ∈ (gammaSet 1 r 0 )) (i : Fin 2 ) :
86
+ (r : ℤ) ∣ v i := by
87
+ fin_cases i <;> simp [← hv.2 , Int.gcd_dvd_left, Int.gcd_dvd_right]
88
+
89
+ lemma gammaSet_div_gcd_to_gammaSet10_bijection (r : ℕ) [NeZero r] :
90
+ Set.BijOn (divIntMap r) (gammaSet 1 r 0 ) (gammaSet 1 1 0 ) := by
91
+ refine ⟨?_, ?_, ?_⟩
92
+ · intro x hx
93
+ simp only [divIntMap, mem_gammaSet_one] at *
94
+ exact finGcdMap_div _ hx.2
95
+ · intro x hx v hv hv2
96
+ ext i
97
+ exact (Int.ediv_left_inj (gammaSet_div_gcd hx i) (gammaSet_div_gcd hv i)).mp
98
+ (congr_fun hv2 i)
99
+ · intro x hx
100
+ use r • x
101
+ simp only [nsmul_eq_mul, divIntMap, Int.cast_natCast]
102
+ constructor
103
+ · rw [mem_gammaSet_one, Int.isCoprime_iff_gcd_eq_one] at hx
104
+ exact ⟨Subsingleton.eq_zero _, by simp [Int.gcd_mul_left, hx]⟩
105
+ · ext i
106
+ simp_all [NeZero.ne r]
107
+
108
+ lemma gammaSet_eq_gcd_mul_divIntMap {r : ℕ} {v : Fin 2 → ℤ} (hv : v ∈ gammaSet 1 r 0 ) :
109
+ v = r • (divIntMap r v) := by
110
+ by_cases hr : r = 0
111
+ · have hv := hv.2
112
+ simp only [hr, Fin.isValue, Int.gcd_eq_zero_iff, CharP.cast_eq_zero, zero_smul] at *
113
+ ext i
114
+ fin_cases i <;> simp [hv]
115
+ · ext i
116
+ simp_all [Pi.smul_apply, divIntMap, ← Int.mul_ediv_assoc _ (gammaSet_div_gcd hv i)]
117
+
118
+ /-- The equivalence between `gammaSet 1 r 0` and `gammaSet 1 1 0` for non-zero `r`. -/
119
+ def gammaSetDivGcdEquiv (r : ℕ) [NeZero r] : gammaSet 1 r 0 ≃ gammaSet 1 1 0 :=
120
+ Set.BijOn.equiv _ (gammaSet_div_gcd_to_gammaSet10_bijection r)
121
+
122
+ /-- The equivalence between `(Fin 2 → ℤ)` and `Σ n : ℕ, gammaSet 1 n 0)` . -/
123
+ def gammaSetDivGcdSigmaEquiv : (Fin 2 → ℤ) ≃ (Σ r : ℕ, gammaSet 1 r 0 ) := by
124
+ apply (Equiv.sigmaFiberEquiv finGcdMap).symm.trans
125
+ refine Equiv.sigmaCongrRight fun b => ?_
126
+ apply Equiv.setCongr
127
+ rw [gammaSet_one_eq]
128
+ rfl
129
+
130
+ @[simp]
131
+ lemma gammaSetDivGcdSigmaEquiv_symm_eq (v : Σ r : ℕ, gammaSet 1 r 0 ) :
132
+ (gammaSetDivGcdSigmaEquiv.symm v) = v.2 := rfl
55
133
56
134
end gammaSet_def
57
135
58
- variable {N a}
136
+ variable {N a r} [NeZero r]
59
137
60
138
section gamma_action
61
139
140
+ /-- Right-multiplying a vector by a matrix in `SL(2, ℤ)` doesn't change its gcd. -/
141
+ lemma vecMulSL_gcd {v : Fin 2 → ℤ} (hab : finGcdMap v = r) (A : SL(2 , ℤ)) :
142
+ finGcdMap (v ᵥ* A.1 ) = r := by
143
+ have hvr : v = r • (v / r) := by
144
+ ext i
145
+ refine Eq.symm (Int.mul_ediv_cancel' ?_)
146
+ fin_cases i <;> simp [← hab, Int.gcd_dvd_left, Int.gcd_dvd_right]
147
+ rw [hvr, smul_vecMul]
148
+ simpa using finGcdMap_smul r (Int.isCoprime_iff_gcd_eq_one.mp ((finGcdMap_div v hab).vecMulSL A))
149
+
62
150
/-- Right-multiplying by `γ ∈ SL(2, ℤ)` sends `gammaSet N a` to `gammaSet N (a ᵥ* γ)`. -/
63
- lemma vecMul_SL2_mem_gammaSet {v : Fin 2 → ℤ} (hv : v ∈ gammaSet N a) (γ : SL( 2 , ℤ)) :
64
- v ᵥ* γ ∈ gammaSet N (a ᵥ* γ) := by
65
- refine ⟨?_, hv.2 .vecMulSL γ⟩
151
+ lemma vecMul_SL2_mem_gammaSet {v : Fin 2 → ℤ} (hv : v ∈ gammaSet N r a)
152
+ (γ : SL( 2 , ℤ)) : v ᵥ* γ ∈ gammaSet N r (a ᵥ* γ) := by
153
+ refine ⟨?_, vecMulSL_gcd hv.2 γ⟩
66
154
have := RingHom.map_vecMul (m := Fin 2 ) (n := Fin 2 ) (Int.castRingHom (ZMod N)) γ v
67
155
simp only [eq_intCast, Int.coe_castRingHom] at this
68
156
simp_rw [Function.comp_def, this, hv.1 ]
69
157
simp
70
158
71
159
variable (a) in
72
160
/-- The bijection between `GammaSets` given by multiplying by an element of `SL(2, ℤ)`. -/
73
- def gammaSetEquiv (γ : SL(2 , ℤ)) : gammaSet N a ≃ gammaSet N (a ᵥ* γ) where
161
+ def gammaSetEquiv (γ : SL(2 , ℤ)) : gammaSet N r a ≃ gammaSet N r (a ᵥ* γ) where
74
162
toFun v := ⟨v.1 ᵥ* γ, vecMul_SL2_mem_gammaSet v.2 γ⟩
75
163
invFun v := ⟨v.1 ᵥ* ↑(γ⁻¹), by
76
164
have := vecMul_SL2_mem_gammaSet v.2 γ⁻¹
@@ -106,7 +194,7 @@ end eisSummand
106
194
variable (a)
107
195
108
196
/-- An Eisenstein series of weight `k` and level `Γ(N)`, with congruence condition `a`. -/
109
- def _root_.eisensteinSeries (k : ℤ) (z : ℍ) : ℂ := ∑' x : gammaSet N a, eisSummand k x z
197
+ def _root_.eisensteinSeries (k : ℤ) (z : ℍ) : ℂ := ∑' x : gammaSet N 1 a, eisSummand k x z
110
198
111
199
lemma eisensteinSeries_slash_apply (k : ℤ) (γ : SL(2 , ℤ)) :
112
200
eisensteinSeries a k ∣[k] γ = eisensteinSeries (a ᵥ* γ) k := by
0 commit comments