This repository has been archived by the owner on Jan 30, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 7
/
homspace.pyx
272 lines (219 loc) · 8.84 KB
/
homspace.pyx
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
"Cremona modular symbols"
from __future__ import print_function
include "cysignals/signals.pxi"
from ..eclib cimport mat, vec
from .mat cimport MatrixFactory
from sage.matrix.all import MatrixSpace
from sage.matrix.matrix_integer_sparse cimport Matrix_integer_sparse
from sage.rings.all import ZZ
from sage.rings.integer cimport Integer
cdef MatrixFactory MF = MatrixFactory()
cdef class ModularSymbols:
"""
Class of Cremona Modular Symbols of given level and sign (and weight 2).
EXAMPLES::
sage: M = CremonaModularSymbols(225)
sage: type(M)
<type 'sage.libs.eclib.homspace.ModularSymbols'>
"""
def __init__(self, long level, int sign=0, bint cuspidal=False, int verbose=0):
"""
Called when creating a space of Cremona modular symbols.
INPUT:
- ``level`` (int) -- the level: an integer, at least 2.
- ``sign`` (int, default 0) -- the sign: 0, +1 or -1
- ``cuspidal`` (boolean, default False) -- True for cuspidal homology
- ``verbose`` (int, default 0) -- verbosity level
EXAMPLES::
sage: CremonaModularSymbols(123, sign=1, cuspidal=True)
Cremona Cuspidal Modular Symbols space of dimension 13 for Gamma_0(123) of weight 2 with sign 1
sage: CremonaModularSymbols(123, sign=-1, cuspidal=True)
Cremona Cuspidal Modular Symbols space of dimension 13 for Gamma_0(123) of weight 2 with sign -1
sage: CremonaModularSymbols(123, sign=0, cuspidal=True)
Cremona Cuspidal Modular Symbols space of dimension 26 for Gamma_0(123) of weight 2 with sign 0
sage: CremonaModularSymbols(123, sign=0, cuspidal=False)
Cremona Modular Symbols space of dimension 29 for Gamma_0(123) of weight 2 with sign 0
"""
if not (sign == 0 or sign == 1 or sign == -1):
raise ValueError("sign (= %s) is not supported; use 0, +1 or -1" % sign)
if level <= 1:
raise ValueError("the level (= %s) must be at least 2" % level)
sig_on()
self.H = new homspace(level, sign, cuspidal, verbose)
sig_off()
def __dealloc__(self):
del self.H
def __repr__(self):
"""
String representation of space of Cremona modular symbols.
EXAMPLES:
We test various types of spaces that impact printing::
sage: M = CremonaModularSymbols(37, sign=1)
sage: M.__repr__()
'Cremona Modular Symbols space of dimension 3 for Gamma_0(37) of weight 2 with sign 1'
sage: CremonaModularSymbols(37, cuspidal=True).__repr__()
'Cremona Cuspidal Modular Symbols space of dimension 4 for Gamma_0(37) of weight 2 with sign 0'
"""
return "Cremona %sModular Symbols space of dimension %s for Gamma_0(%s) of weight 2 with sign %s"%(
'Cuspidal ' if self.is_cuspidal() else '',
self.dimension(), self.level(), self.sign())
#cpdef long level(self):
def level(self):
"""
Return the level of this modular symbols space.
EXAMPLES::
sage: M = CremonaModularSymbols(1234, sign=1)
sage: M.level()
1234
"""
return self.H.modulus
#cpdef int dimension(self):
def dimension(self):
"""
Return the dimension of this modular symbols space.
EXAMPLES::
sage: M = CremonaModularSymbols(1234, sign=1)
sage: M.dimension()
156
"""
if self.is_cuspidal():
return self.H.h1cuspdim()
else:
return self.H.h1dim()
def number_of_cusps(self):
r"""
Return the number of cusps for $\Gamma_0(N)$, where $N$ is the
level.
EXAMPLES::
sage: M = CremonaModularSymbols(225)
sage: M.number_of_cusps()
24
"""
return self.H.h1ncusps()
#cpdef int sign(self):
def sign(self):
"""
Return the sign of this Cremona modular symbols space. The sign is either 0, +1 or -1.
EXAMPLES::
sage: M = CremonaModularSymbols(1122, sign=1); M
Cremona Modular Symbols space of dimension 224 for Gamma_0(1122) of weight 2 with sign 1
sage: M.sign()
1
sage: M = CremonaModularSymbols(1122); M
Cremona Modular Symbols space of dimension 433 for Gamma_0(1122) of weight 2 with sign 0
sage: M.sign()
0
sage: M = CremonaModularSymbols(1122, sign=-1); M
Cremona Modular Symbols space of dimension 209 for Gamma_0(1122) of weight 2 with sign -1
sage: M.sign()
-1
"""
return self.H.plusflag
#cpdef bint is_cuspidal(self):
def is_cuspidal(self):
"""
Return whether or not this space is cuspidal.
EXAMPLES::
sage: M = CremonaModularSymbols(1122); M.is_cuspidal()
0
sage: M = CremonaModularSymbols(1122, cuspidal=True); M.is_cuspidal()
1
"""
return self.H.cuspidal
def hecke_matrix(self, long p, dual=False, verbose=False):
"""
Return the matrix of the ``p``-th Hecke operator acting on
this space of modular symbols.
The result of this command is not cached.
INPUT:
- ``p`` -- a prime number
- ``dual`` -- (default: False) whether to compute the Hecke
operator acting on the dual space, i.e., the
transpose of the Hecke operator
- ``verbose`` -- (default: False) print verbose output
OUTPUT:
(matrix) If ``p`` divides the level, the matrix of the
Atkin-Lehner involution `W_p` at ``p``; otherwise the matrix of the
Hecke operator `T_p`,
EXAMPLES::
sage: M = CremonaModularSymbols(37)
sage: t = M.hecke_matrix(2); t
5 x 5 Cremona matrix over Rational Field
sage: print(t.str())
[ 3 0 0 0 0]
[-1 -1 1 1 0]
[ 0 0 -1 0 1]
[-1 1 0 -1 -1]
[ 0 0 1 0 -1]
sage: t.charpoly().factor()
(x - 3) * x^2 * (x + 2)^2
sage: print(M.hecke_matrix(2, dual=True).str())
[ 3 -1 0 -1 0]
[ 0 -1 0 1 0]
[ 0 1 -1 0 1]
[ 0 1 0 -1 0]
[ 0 0 1 -1 -1]
sage: w = M.hecke_matrix(37); w
5 x 5 Cremona matrix over Rational Field
sage: w.charpoly().factor()
(x - 1)^2 * (x + 1)^3
sage: sw = w.sage_matrix_over_ZZ()
sage: st = t.sage_matrix_over_ZZ()
sage: sw^2 == sw.parent()(1)
True
sage: st*sw == sw*st
True
"""
sig_on()
cdef mat M = self.H.heckeop(p, dual, verbose)
sig_off()
return MF.new_matrix(M)
def sparse_Hecke_matrix(self, long p, dual=False, verbose=False):
"""
Return the matrix of the ``p``-th Hecke operator acting on
this space of modular symbols, as a sparse Sage integer matrix.
This is more memory-efficient than creating a Cremona matrix and then
applying sage_matrix_over_ZZ with sparse=True.
The result of this command is not cached.
INPUT:
- ``p`` -- a prime number
- ``dual`` -- (default: False) whether to compute the Hecke
operator acting on the dual space, i.e., the
transpose of the Hecke operator
- ``verbose`` -- (default: False) print verbose output
OUTPUT:
(matrix) If ``p`` divides the level, the matrix of the
Atkin-Lehner involution `W_p` at ``p``; otherwise the matrix of the
Hecke operator `T_p`,
EXAMPLES::
sage: M = CremonaModularSymbols(37)
sage: t = M.sparse_hecke_matrix(2); type(t)
<type 'sage.matrix.matrix_integer_sparse.Matrix_integer_sparse'>
5 x 5 sparse matrix over Integer Ring
sage: print(t)
[ 3 0 0 0 0]
[-1 -1 1 1 0]
[ 0 0 -1 0 1]
[-1 1 0 -1 -1]
[ 0 0 1 0 -1]
sage: M = CremonaModularSymbols(5001)
sage: T = M.sparse_hecke_matrix(2)
sage: U = M.hecke_matrix(2).sage_matrix_over_ZZ(sparse=True)
sage: print T == U
True
"""
cdef long n = self.dimension()
cdef long i=0
cdef long j=0
cdef vec v
cdef Matrix_integer_sparse Ts
Ts = MatrixSpace(ZZ, n, sparse=True).zero_matrix().__copy__()
sig_on()
for i from 1 <= i <= n:
v = self.H.heckeop_col(p, i, verbose)
for j from 1 <= j <= n:
if v[j]:
Ts.set_unsafe(j-1, i-1, Integer(v[j]))
sig_off()
if dual: Ts = Ts.transpose()
return Ts