Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/modular/modsym/ambient.py
8820 views
1
# -*- coding: utf-8 -*-
2
r"""
3
Ambient spaces of modular symbols
4
5
This module defines the following classes. There is an abstract base
6
class ``ModularSymbolsAmbient``, derived from
7
``space.ModularSymbolsSpace`` and ``hecke.AmbientHeckeModule``. As
8
this is an abstract base class, only derived classes should be
9
instantiated. There are five derived classes:
10
11
- ``ModularSymbolsAmbient_wtk_g0``, for modular symbols of general
12
weight `k` for `\Gamma_0(N)`;
13
14
- ``ModularSymbolsAmbient_wt2_g0`` (derived from
15
``ModularSymbolsAmbient_wtk_g0``), for modular symbols of weight 2
16
for `\Gamma_0(N)`;
17
18
- ``ModularSymbolsAmbient_wtk_g1``, for modular symbols of general
19
weight `k` for `\Gamma_1(N)`;
20
21
- ``ModularSymbolsAmbient_wtk_gamma_h``, for modular symbols of
22
general weight `k` for `\Gamma_H`, where `H` is a subgroup of
23
`\ZZ/N\ZZ`;
24
25
- ``ModularSymbolsAmbient_wtk_eps``, for modular symbols of general
26
weight `k` and character `\epsilon`.
27
28
29
30
EXAMPLES:
31
32
We compute a space of modular symbols modulo 2. The dimension is
33
different from that of the corresponding space in characteristic
34
0::
35
36
sage: M = ModularSymbols(11,4,base_ring=GF(2)); M
37
Modular Symbols space of dimension 7 for Gamma_0(11) of weight 4
38
with sign 0 over Finite Field of size 2
39
sage: M.basis()
40
([X*Y,(1,0)], [X*Y,(1,8)], [X*Y,(1,9)], [X^2,(0,1)], [X^2,(1,8)], [X^2,(1,9)], [X^2,(1,10)])
41
sage: M0 = ModularSymbols(11,4,base_ring=QQ); M0
42
Modular Symbols space of dimension 6 for Gamma_0(11) of weight 4
43
with sign 0 over Rational Field
44
sage: M0.basis()
45
([X^2,(0,1)], [X^2,(1,6)], [X^2,(1,7)], [X^2,(1,8)], [X^2,(1,9)], [X^2,(1,10)])
46
47
The characteristic polynomial of the Hecke operator `T_2` has an extra
48
factor `x`.
49
50
::
51
52
sage: M.T(2).matrix().fcp('x')
53
(x + 1)^2 * x^5
54
sage: M0.T(2).matrix().fcp('x')
55
(x - 9)^2 * (x^2 - 2*x - 2)^2
56
"""
57
58
################################################################################
59
# Sage: Open Source Mathematical Software
60
#
61
# Copyright (C) 2005 William Stein <[email protected]>
62
#
63
# Distributed under the terms of the GNU General Public License (GPL)
64
#
65
# This code is distributed in the hope that it will be useful,
66
# but WITHOUT ANY WARRANTY; without even the implied warranty of
67
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
68
# General Public License for more details.
69
#
70
# The full text of the GPL is available at:
71
#
72
# http://www.gnu.org/licenses/
73
################################################################################
74
75
# Sage packages
76
from sage.misc.search import search
77
import sage.misc.latex as latex
78
import sage.misc.misc as misc
79
80
import sage.matrix.matrix_space as matrix_space
81
from sage.matrix.matrix_integer_2x2 import MatrixSpace_ZZ_2x2 as M2Z
82
import sage.modules.free_module_element as free_module_element
83
import sage.modules.free_module as free_module
84
import sage.misc.misc as misc
85
import sage.modular.arithgroup.all as arithgroup
86
import sage.modular.dirichlet as dirichlet
87
import sage.modular.hecke.all as hecke
88
import sage.rings.rational_field as rational_field
89
import sage.rings.integer_ring as integer_ring
90
import sage.rings.all as rings
91
import sage.rings.arith as arith
92
import sage.structure.formal_sum as formal_sum
93
import sage.categories.all as cat
94
from sage.modular.cusps import Cusp
95
import sage.structure.all
96
97
import boundary
98
import element
99
import heilbronn
100
import manin_symbols
101
import modular_symbols
102
import modsym
103
import p1list
104
import relation_matrix
105
import space
106
import subspace
107
108
QQ = rings.Rational
109
ZZ = rings.Integers
110
111
112
class ModularSymbolsAmbient(space.ModularSymbolsSpace, hecke.AmbientHeckeModule):
113
r"""
114
An ambient space of modular symbols for a congruence subgroup of
115
`SL_2(\ZZ)`.
116
117
This class is an abstract base class, so only derived classes
118
should be instantiated.
119
120
INPUT:
121
122
- ``weight`` - an integer
123
- ``group`` - a congruence subgroup.
124
- ``sign`` - an integer, either -1, 0, or 1
125
- ``base_ring`` - a commutative ring
126
- ``custom_init`` - a function that is called with self as input
127
before any computations are done using self; this could be used
128
to set a custom modular symbols presentation.
129
"""
130
def __init__(self, group, weight, sign, base_ring,
131
character=None, custom_init=None):
132
"""
133
Initialize a space of modular symbols.
134
135
INPUT:
136
137
- ``weight`` - an integer
138
139
- ``group`` - a congruence subgroup.
140
141
- ``sign`` - an integer, either -1, 0, or 1
142
143
- ``base_ring`` - a commutative ring
144
145
EXAMPLES::
146
147
sage: ModularSymbols(2,2)
148
Modular Symbols space of dimension 1 for Gamma_0(2) of weight 2 with sign 0 over Rational Field
149
150
"""
151
weight = int(weight)
152
if weight <= 1:
153
raise ValueError("Weight (=%s) Modular symbols of weight <= 1 not defined."%weight)
154
if not arithgroup.is_CongruenceSubgroup(group):
155
raise TypeError("group must be a congruence subgroup")
156
157
sign = int(sign)
158
if not isinstance(base_ring, rings.Ring) and base_ring.is_field():
159
raise TypeError("base_ring must be a commutative ring")
160
161
if character == None and arithgroup.is_Gamma0(group):
162
character = dirichlet.TrivialCharacter(group.level(), base_ring)
163
164
space.ModularSymbolsSpace.__init__(self, group, weight,
165
character, sign, base_ring)
166
167
if custom_init is not None:
168
custom_init(self)
169
170
try:
171
formula = self._dimension_formula()
172
except NotImplementedError:
173
formula = None
174
175
rank = self.rank()
176
if formula != None:
177
assert rank == formula, \
178
"Computed dimension (=%s) of ambient space \"%s\" doesn't match dimension formula (=%s)!\n"%(d, self, formula) + \
179
"ModularSymbolsAmbient: group = %s, weight = %s, sign = %s, base_ring = %s, character = %s"%(
180
group, weight, sign, base_ring, character)
181
182
hecke.AmbientHeckeModule.__init__(self, base_ring, rank, group.level(), weight)
183
184
def __cmp__(self, other):
185
"""
186
Standard comparison function.
187
188
EXAMPLES::
189
190
sage: ModularSymbols(11,2) == ModularSymbols(11,2) # indirect doctest
191
True
192
sage: ModularSymbols(11,2) == ModularSymbols(11,4) # indirect doctest
193
False
194
195
"""
196
if not isinstance(other, space.ModularSymbolsSpace):
197
return cmp(type(self), type(other))
198
if isinstance(other, ModularSymbolsAmbient):
199
return misc.cmp_props(self, other, ['group', 'weight', 'sign', 'base_ring', 'character'])
200
c = cmp(self, other.ambient_hecke_module())
201
if c: return c
202
if self.free_module() == other.free_module():
203
return 0
204
return -1
205
206
def new_submodule(self, p=None):
207
r"""
208
Returns the new or `p`-new submodule of this modular symbols ambient space.
209
210
INPUT:
211
212
213
- ``p`` - (default: None); if not None, return only
214
the `p`-new submodule.
215
216
217
OUTPUT:
218
219
The new or `p`-new submodule of this modular symbols ambient space.
220
221
EXAMPLES::
222
223
sage: ModularSymbols(100).new_submodule()
224
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 31 for Gamma_0(100) of weight 2 with sign 0 over Rational Field
225
sage: ModularSymbols(389).new_submodule()
226
Modular Symbols space of dimension 65 for Gamma_0(389) of weight 2 with sign 0 over Rational Field
227
"""
228
# Check for special cases where the answer is easy.
229
# If not in one of those cases, use the generic code.
230
if self.level().is_prime() and self.weight() == 2:
231
return self
232
return hecke.AmbientHeckeModule.new_submodule(self, p=p)
233
234
def manin_symbols(self):
235
"""
236
Return the list of Manin symbols for this modular symbols ambient space.
237
238
EXAMPLES::
239
240
sage: ModularSymbols(11,2).manin_symbols()
241
Manin Symbol List of weight 2 for Gamma0(11)
242
"""
243
raise NotImplementedError
244
245
def manin_generators(self):
246
"""
247
Return list of all Manin symbols for this space. These are the
248
generators in the presentation of this space by Manin symbols.
249
250
EXAMPLES::
251
252
sage: M = ModularSymbols(2,2)
253
sage: M.manin_generators()
254
[(0,1), (1,0), (1,1)]
255
256
::
257
258
sage: M = ModularSymbols(1,6)
259
sage: M.manin_generators()
260
[[Y^4,(0,0)], [X*Y^3,(0,0)], [X^2*Y^2,(0,0)], [X^3*Y,(0,0)], [X^4,(0,0)]]
261
"""
262
return self._manin_generators
263
264
def manin_basis(self):
265
r"""
266
Return a list of indices into the list of Manin generators (see
267
``self.manin_generators()``) such that those symbols
268
form a basis for the quotient of the `\QQ`-vector
269
space spanned by Manin symbols modulo the relations.
270
271
EXAMPLES::
272
273
sage: M = ModularSymbols(2,2)
274
sage: M.manin_basis()
275
[1]
276
sage: [M.manin_generators()[i] for i in M.manin_basis()]
277
[(1,0)]
278
sage: M = ModularSymbols(6,2)
279
sage: M.manin_basis()
280
[1, 10, 11]
281
sage: [M.manin_generators()[i] for i in M.manin_basis()]
282
[(1,0), (3,1), (3,2)]
283
"""
284
try:
285
return self._manin_basis
286
except AttributeError:
287
self.compute_presentation()
288
return self._manin_basis
289
290
def p1list(self):
291
"""
292
Return a P1list of the level of this modular symbol space.
293
294
EXAMPLES::
295
296
sage: ModularSymbols(11,2).p1list()
297
The projective line over the integers modulo 11
298
"""
299
try:
300
return self.__p1list
301
except AttributeError:
302
self.__p1list = p1list.P1List(self.level())
303
return self.__p1list
304
305
# See the file relation_matrix.py
306
#
307
# def relation_matrix(self):
308
# raise NotImplementedError
309
310
def compute_presentation(self):
311
r"""
312
Compute and cache the presentation of this space.
313
314
EXAMPLES::
315
316
sage: ModularSymbols(11,2).compute_presentation() # no output
317
318
"""
319
B, basis, mod = relation_matrix.compute_presentation(
320
self.manin_symbols(), self.sign(),
321
self.base_ring())
322
self._manin_generators = self.manin_symbols().manin_symbol_list()
323
self._manin_basis = basis
324
self._manin_gens_to_basis = B
325
self._mod2term = mod
326
327
def manin_gens_to_basis(self):
328
r"""
329
Return the matrix expressing the manin symbol generators in terms of the basis.
330
331
EXAMPLES::
332
333
sage: ModularSymbols(11,2).manin_gens_to_basis()
334
[-1 0 0]
335
[ 1 0 0]
336
[ 0 0 0]
337
[ 0 0 1]
338
[ 0 -1 1]
339
[ 0 -1 0]
340
[ 0 0 -1]
341
[ 0 0 -1]
342
[ 0 1 -1]
343
[ 0 1 0]
344
[ 0 0 1]
345
[ 0 0 0]
346
"""
347
try:
348
return self._manin_gens_to_basis
349
except AttributeError:
350
self.compute_presentation()
351
return self._manin_gens_to_basis
352
353
354
#####################################################################
355
# Coercion
356
#####################################################################
357
def __call__(self, x, computed_with_hecke=False):
358
r"""
359
Coerce `x` into this modular symbols space. The result is
360
either an element of self or a subspace of self.
361
362
INPUTS:
363
364
The allowed input types for `x` are as follows:
365
366
367
- ``Vector`` - a vector of the same degree. This
368
defines the corresponding linear combination of the basis of self.
369
370
- ``ManinSymbol`` - a Manin symbol of the same weight
371
as the space
372
373
- ``ModularSymbolsElement`` - a modular symbol whose
374
ambient parent is this space of modular symbols. (TODO: make more
375
sophisticated)
376
377
- 0 - the integer 0; results in the 0 modular symbol.
378
379
- 3-tuple - Given a 3-tuple (i,u,v), returns the modular symbol
380
element defined by the Manin symbol
381
`[X^{i}\cdot Y^{k-2-i}, (u,v)]`, where k is the weight.
382
Note that we must have `0\leq i \leq k-2`.
383
384
- 2-tuple - Given a 2-tuple (u,v), returns the element defined by
385
the Manin symbol `[X^0 \cdot Y^{2-k}, (u,v)]`.
386
387
- 2-elements list - Given a list ``[alpha, beta]``,
388
where `\alpha` and `\beta` are (coercible to)
389
cusps, return the modular symbol `\{\alpha, \beta\}`. When
390
the the weight `k > 2` return
391
`Y^{k-2} \{\alpha, \beta\}`.
392
393
- 3-element list - Given a list ``[i, alpha, beta]``,
394
where `i` is an integer, and `\alpha`,
395
`\beta` are (coercible to) cusps, return the modular symbol
396
`X^i Y^{k-2-i} \{\alpha, \beta\}`.
397
398
If our list is ``[f, alpha, beta]``, where `f`
399
is a homogeneous polynomial in two variables of degree k-2 with
400
integer coefficients, and alpha and beta are cusps, return the
401
corresponding sum of modular symbols as an element of self. So if
402
`f = \sum_{i=0}^{k-2} a_i X^i Y^{k-2-i}`, return
403
`\sum_{i=0}^{k-2} a_i * [ i, alpha, beta ]`.
404
405
EXAMPLES::
406
407
sage: M = ModularSymbols(37,2)
408
409
M(0) is the 0 element of the space::
410
411
sage: M(0)
412
0
413
sage: type(M(0))
414
<class 'sage.modular.modsym.element.ModularSymbolsElement'>
415
416
From a vector of the correct dimension we construct the
417
corresponding linear combination of the basis elements::
418
419
sage: M.dimension()
420
5
421
sage: M.basis()
422
((1,0), (1,23), (1,32), (1,34), (1,35))
423
sage: M(vector([1,2,3,4,5]))
424
(1,0) + 2*(1,23) + 3*(1,32) + 4*(1,34) + 5*(1,35)
425
sage: M(vector([1/2,2/3,3/4,4/5,5/6]))
426
1/2*(1,0) + 2/3*(1,23) + 3/4*(1,32) + 4/5*(1,34) + 5/6*(1,35)
427
428
Manin symbols can be converted to elements of the space::
429
430
sage: from sage.modular.modsym.manin_symbols import ManinSymbol
431
sage: ManinSymbol(M.manin_symbols(),(0,2,3))
432
(2,3)
433
sage: M(ManinSymbol(M.manin_symbols(),(0,2,3)))
434
(1,34) - (1,35)
435
436
However, it is easier to use one of the following forms.
437
Either a 3-tuple `(i,u,v)` or a 2-tuple `(u,v)` with `i=0`
438
assumed::
439
440
sage: M((0,2,3))
441
(1,34) - (1,35)
442
sage: M((2,3))
443
(1,34) - (1,35)
444
445
Or a 3-list `[i,\alpha,\beta]` where `i` is the degree and
446
`\alpha` and `beta` are cusps, or a 2-tuple `[\alpha,\beta]`
447
with `i=0` assumed::
448
449
sage: M([0,Cusp(1/2),Cusp(0)])
450
(1,35)
451
sage: M([Cusp(1/2),Cusp(0)])
452
(1,35)
453
454
455
"""
456
if isinstance(x, free_module_element.FreeModuleElement):
457
if x.degree() != self.dimension():
458
raise TypeError("Incompatible degrees: x has degree %s\
459
but modular symbols space has dimension %s"%(
460
x.degree(), self.dimension()))
461
#if x.parent().base_ring() != self.base_ring():
462
# raise TypeError, "Vector x is over %s, but modular symbols space is over %s."%(
463
# x.parent().base_ring(), self.base_ring())
464
return element.ModularSymbolsElement(self, x)
465
466
elif isinstance(x, (manin_symbols.ManinSymbol, element.ModularSymbolsElement)):
467
return self.element(x)
468
469
elif isinstance(x, modular_symbols.ModularSymbol):
470
return self(x.manin_symbol_rep())
471
472
elif isinstance(x, (int, rings.Integer)) and x==0:
473
return element.ModularSymbolsElement(self, self.free_module()(0))
474
475
elif isinstance(x, tuple):
476
return self.manin_symbol(x)
477
478
elif isinstance(x, formal_sum.FormalSum):
479
return sum([c*self(y) for c, y in x], self(0))
480
481
elif isinstance(x, list):
482
if len(x) == 3 and rings.is_MPolynomial(x[0]):
483
return self.modular_symbol_sum(x)
484
else:
485
return self.modular_symbol(x)
486
487
raise TypeError("No coercion of %s into %s defined."%(x, self))
488
489
490
def change_ring(self, R):
491
r"""
492
Change the base ring to R.
493
494
EXAMPLES::
495
496
sage: ModularSymbols(Gamma1(13), 2).change_ring(GF(17))
497
Modular Symbols space of dimension 15 for Gamma_1(13) of weight 2 with sign 0 and over Finite Field of size 17
498
sage: M = ModularSymbols(DirichletGroup(5).0, 7); MM=M.change_ring(CyclotomicField(8)); MM
499
Modular Symbols space of dimension 6 and level 5, weight 7, character [zeta8^2], sign 0, over Cyclotomic Field of order 8 and degree 4
500
sage: MM.change_ring(CyclotomicField(4)) == M
501
True
502
sage: M.change_ring(QQ)
503
Traceback (most recent call last):
504
...
505
ValueError: cannot coerce element of order 4 into self
506
"""
507
if self.character() is None:
508
return modsym.ModularSymbols(self.group(), self.weight(), self.sign(), R)
509
else:
510
return modsym.ModularSymbols(self.character(), self.weight(), self.sign(), R)
511
512
def base_extend(self, R):
513
r"""
514
Canonically change the base ring to R.
515
516
EXAMPLE::
517
518
sage: M = ModularSymbols(DirichletGroup(5).0, 7); MM = M.base_extend(CyclotomicField(8)); MM
519
Modular Symbols space of dimension 6 and level 5, weight 7, character [zeta8^2], sign 0, over Cyclotomic Field of order 8 and degree 4
520
sage: MM.base_extend(CyclotomicField(4))
521
Traceback (most recent call last):
522
...
523
ValueError: No coercion defined
524
"""
525
if not R.has_coerce_map_from(self.base_ring()):
526
raise ValueError("No coercion defined")
527
else:
528
return self.change_ring(R)
529
530
531
def _action_on_modular_symbols(self, g):
532
r"""
533
Returns the matrix of the action of a 2x2 matrix on this space.
534
535
INPUT:
536
537
``g`` (list) -- `g=[a,b,c,d]` where `a,b,c,d` are integers
538
defining a `2\times2` integer matrix.
539
540
OUTPUT:
541
542
(matrix) The matrix of the action of `g` on this Modular
543
Symbol space, with respect to the standard basis.
544
545
.. note::
546
547
Use _matrix_of_operator_on_modular_symbols for more general
548
operators.
549
550
EXAMPLES::
551
552
sage: M = ModularSymbols(11,4,1)
553
sage: M._action_on_modular_symbols([1,2,3,7])
554
[ 0 0 5/2 -3/2]
555
[ 0 0 5/2 -3/2]
556
[ 0 1 0 0]
557
[ 0 1 -1/2 1/2]
558
559
"""
560
if not isinstance(g, list):
561
raise TypeError("g must be a list")
562
if not len(g) == 4:
563
raise TypeError("g must be a list of length 4")
564
return self._matrix_of_operator_on_modular_symbols(self, [g])
565
566
def manin_symbol(self, x, check=True):
567
r"""
568
Construct a Manin Symbol from the given data.
569
570
INPUT:
571
572
- ``x`` (list) -- either `[u,v]` or `[i,u,v]`, where `0\le
573
i\le k-2` where `k` is the weight, and `u`,`v` are integers
574
defining a valid element of `\mathbb{P}^1(N)`, where `N` is
575
the level.
576
577
OUTPUT:
578
579
(ManinSymbol) the monomial Manin Symbol associated to
580
`[i;(u,v)]`, with `i=0` if not supplied, corresponding to the
581
symbol `[X^i*Y^{k-2-i}, (u,v)]`.
582
583
EXAMPLES::
584
585
sage: M = ModularSymbols(11,4,1)
586
sage: M.manin_symbol([2,5,6])
587
[X^2,(1,10)]
588
"""
589
if check:
590
if len(x) == 2:
591
x = (0,x[0],x[1])
592
if len(x) == 3:
593
# Manin symbol of the form (i, u, v), which corresponds to [X^i*Y^(k-2-i), (u,v)].
594
if x[0] < 0 or x[0] > self.weight()-2:
595
raise ValueError("The first entry of the tuple (=%s)\
596
must be an integer between 0 and k-2 (=%s)."%(
597
x, self.weight()-2))
598
else:
599
raise ValueError("x (=%s) must be of length 2 or 3"%x)
600
# end check
601
602
N = self.level()
603
x = (x[0], x[1]%N, x[2]%N)
604
try:
605
return self.__manin_symbol[x]
606
except AttributeError:
607
self.__manin_symbol = {}
608
except KeyError:
609
pass
610
y = manin_symbols.ManinSymbol(self.manin_symbols(), x)
611
z = self(y)
612
self.__manin_symbol[x] = z
613
return z
614
615
def _modular_symbol_0_to_alpha(self, alpha, i=0):
616
r"""
617
Return the modular symbol `\{0,\alpha\}` in this space.
618
619
INPUT:
620
621
- ``alpha`` (rational or Infinity) -- a cusp
622
623
- ``i`` (int, default 0) -- the degree of the symbol.
624
625
OUTPUT:
626
627
(ModularSymbol) The modular symbol `X^iY^{k-2-i}\{0,\alpha\}`.
628
629
EXAMPLES::
630
631
sage: M = ModularSymbols(11,4,1)
632
sage: M._modular_symbol_0_to_alpha(Cusp(3/5))
633
11*[X^2,(1,7)] + 33*[X^2,(1,9)] - 20*[X^2,(1,10)]
634
sage: M._modular_symbol_0_to_alpha(Cusp(3/5),1)
635
15/2*[X^2,(1,7)] + 35/2*[X^2,(1,9)] - 10*[X^2,(1,10)]
636
sage: M._modular_symbol_0_to_alpha(Cusp(Infinity))
637
-[X^2,(1,10)]
638
sage: M._modular_symbol_0_to_alpha(Cusp(Infinity),1)
639
0
640
"""
641
if alpha.is_infinity():
642
return self.manin_symbol((i,0,1), check=False)
643
v, c = arith.continued_fraction_list(alpha._rational_(), partial_convergents=True)
644
a = self(0)
645
zero = rings.ZZ(0)
646
one = rings.ZZ(1)
647
two = rings.ZZ(2)
648
if self.weight() > two:
649
R = rings.ZZ['X']
650
X = R.gen(0)
651
## need to add first two terms, which aren't necessarily
652
## zero in this case. we do the first here, and the
653
## second in the k=0 case below, so as to avoid code
654
## duplication
655
a += self.manin_symbol((i,0,1), check=False)
656
for k in range(0,len(c)):
657
## matrix entries associated to this partial sum
658
if k == 0:
659
x = c[0][0]
660
y = -1
661
z = 1
662
w = 0
663
else:
664
x = c[k][0]
665
y = c[k-1][0]
666
z = c[k][1]
667
w = c[k-1][1]
668
if k%2 == 0:
669
y = -y
670
w = -w
671
672
## two options here: write out the polynomial directly,
673
## and deal with all the separate cases, or create two
674
## polynomials and then exponentiate and multiply them.
675
## given how fast ntl/flint/etc are, the second may
676
## be faster.
677
678
## method 1: write out solution. this is currently
679
## incorrect, because it ends up doing 0^0 in the sum,
680
## so I'll fix it and do timings soon.
681
## for s in range(0,self.weight()-two+1):
682
## coeff = sum([ binomial(i,t)*binomial(self.weight()-two-i,s-t)*
683
## x**t * y**(i-t) * z**(s-t) *
684
## w**(self.weight()-two-i-s+t) for t in range(0,s) ])
685
## m = coeff * self.manin_symbol((s, y, w), check=False)
686
## a += m
687
688
## method 2
689
p1 = x*X+y
690
p2 = z*X+w
691
if i == 0:
692
p1 = R(one)
693
if (self.weight()-2-i == 0):
694
p2 = R(one)
695
poly = (p1**i) * (p2**(self.weight()-2-i))
696
for s in range(0,self.weight()-1): ## k-2+1 = k-1
697
a += poly[s] * self.manin_symbol((s,z,w), check=False)
698
else:
699
for k in range(1,len(c)):
700
u = c[k][1]
701
v = c[k-1][1]
702
if k % 2 == 0:
703
v = -v
704
x = self.manin_symbol((i, u, v), check=False)
705
a += x
706
return a
707
708
def modular_symbol(self, x, check=True):
709
r"""
710
Create a modular symbol in this space.
711
712
INPUT:
713
714
- ``x`` (list) -- a list of either 2 or 3 entries:
715
716
- 2 entries: `[\alpha, \beta]` where `\alpha` and `\beta`
717
are cusps;
718
719
- 3 entries: `[i, \alpha, \beta]` where `0\le i\le k-2`
720
and `\alpha` and `\beta` are cusps;
721
722
- ``check`` (bool, default True) -- flag that determines
723
whether the input ``x`` needs processing: use check=False
724
for efficiency if the input ``x`` is a list of length 3 whose
725
first entry is an Integer, and whose second and third
726
entries are Cusps (see examples).
727
728
OUTPUT:
729
730
(Modular Symbol) The modular symbol `Y^{k-2}\{\alpha,
731
\beta\}`. or `X^i Y^{k-2-i}\{\alpha,\beta\}`.
732
733
EXAMPLES::
734
735
sage: set_modsym_print_mode('modular')
736
sage: M = ModularSymbols(11)
737
sage: M.modular_symbol([2/11, oo])
738
-{-1/9, 0}
739
sage: M.1
740
{-1/8, 0}
741
sage: M.modular_symbol([-1/8, 0])
742
{-1/8, 0}
743
sage: M.modular_symbol([0, -1/8, 0])
744
{-1/8, 0}
745
sage: M.modular_symbol([10, -1/8, 0])
746
Traceback (most recent call last):
747
...
748
ValueError: The first entry of the tuple (=[10, -1/8, 0]) must be an integer between 0 and k-2 (=0).
749
750
::
751
752
sage: N = ModularSymbols(6,4)
753
sage: set_modsym_print_mode('manin')
754
sage: N([1,Cusp(-1/4),Cusp(0)])
755
17/2*[X^2,(2,3)] - 9/2*[X^2,(2,5)] + 15/2*[X^2,(3,1)] - 15/2*[X^2,(3,2)]
756
sage: N([1,Cusp(-1/2),Cusp(0)])
757
1/2*[X^2,(2,3)] + 3/2*[X^2,(2,5)] + 3/2*[X^2,(3,1)] - 3/2*[X^2,(3,2)]
758
759
Use check=False for efficiency if the input x is a list of length 3
760
whose first entry is an Integer, and whose second and third entries
761
are cusps::
762
763
sage: M.modular_symbol([0, Cusp(2/11), Cusp(oo)], check=False)
764
-(1,9)
765
766
::
767
768
sage: set_modsym_print_mode() # return to default.
769
"""
770
771
if check:
772
if len(x) == 2:
773
x = [0,x[0],x[1]]
774
elif len(x) == 3:
775
if x[0] < 0 or x[0] > self.weight()-2:
776
raise ValueError("The first entry of the tuple (=%s)\
777
must be an integer between 0 and k-2 (=%s)."%(
778
x, self.weight()-2))
779
else:
780
raise ValueError("x (=%s) must be of length 2 or 3"%x)
781
i = rings.Integer(x[0])
782
alpha = Cusp(x[1])
783
beta = Cusp(x[2])
784
else:
785
i = x[0]
786
alpha = x[1]
787
beta = x[2]
788
789
# Compute {0,beta} - {0,alpha}
790
a = self._modular_symbol_0_to_alpha(alpha, i)
791
b = self._modular_symbol_0_to_alpha(beta, i)
792
return b - a
793
794
def modular_symbol_sum(self, x, check=True):
795
r"""
796
Construct a modular symbol sum.
797
798
INPUT:
799
800
- ``x`` (list) -- `[f, \alpha, \beta]` where `f =
801
\sum_{i=0}^{k-2} a_i X^i Y^{k-2-i}` is a homogeneous
802
polynomial over `\ZZ` of degree `k` and `\alpha` and `\beta`
803
are cusps.
804
805
- ``check`` (bool, default True) -- if True check the validity
806
of the input tuple ``x``
807
808
OUTPUT:
809
810
The sum `\sum_{i=0}^{k-2} a_i [ i, \alpha, \beta ]` as an
811
element of this modular symbol space.
812
813
EXAMPLES:
814
815
sage: M = ModularSymbols(11,4)
816
sage: R.<X,Y>=QQ[]
817
sage: M.modular_symbol_sum([X*Y,Cusp(0),Cusp(Infinity)])
818
-3/14*[X^2,(1,6)] + 1/14*[X^2,(1,7)] - 1/14*[X^2,(1,8)] + 1/2*[X^2,(1,9)] - 2/7*[X^2,(1,10)]
819
"""
820
if check:
821
if len(x) != 3:
822
raise ValueError("%s must have length 3"%x)
823
f = x[0]
824
R = self.base_ring()['X','Y']
825
X = R.gen(0)
826
try:
827
f = R(f)
828
except TypeError:
829
raise ValueError("f must be coercible to a polynomial \
830
over %s"%self.base_ring())
831
if (not f.is_homogeneous()) or (f.degree() != self.weight()-2):
832
raise ValueError("f must be a homogeneous polynomial of degree k-2")
833
alpha = Cusp(x[1])
834
beta = Cusp(x[2])
835
else:
836
f = x[0]
837
R = self.base_ring()
838
X = R.gen(0)
839
alpha = x[1]
840
beta = x[2]
841
842
s = self(0)
843
844
for term in f.monomials():
845
deg = term.degree(X)
846
a = self._modular_symbol_0_to_alpha(alpha, deg)
847
b = self._modular_symbol_0_to_alpha(beta, deg)
848
s += f.monomial_coefficient(term) * (b-a)
849
850
return s
851
852
853
def _compute_dual_hecke_matrix(self, n):
854
r"""
855
Return the matrix of the dual Hecke operator `T(n)`.
856
857
INPUT:
858
859
- ``n`` (int) -- a positive integer
860
861
OUTPUT:
862
863
(matrix) The matrix of the dual od `T(n)`.
864
865
EXAMPLES::
866
867
sage: M = ModularSymbols(11,4,1)
868
sage: M._compute_dual_hecke_matrix(5)
869
[126 0 0 0]
870
[ 2 63 38 22]
871
[ 11 33 82 121]
872
[-13 30 6 -17]
873
"""
874
return self.hecke_matrix(n).transpose()
875
876
def _compute_hecke_matrix_prime(self, p, rows=None):
877
"""
878
Return the matrix of the Hecke operator `T(p)`.
879
880
INPUT:
881
882
- ``p`` (int) -- a prime number.
883
884
- ``rows`` (list or None (default)) -- if not None, a list of
885
the rows which should be computed; otherwise the complete
886
matrix will be computed,
887
888
.. note::
889
890
`p` does not have to be, prime despite the function name.
891
892
OUTPUT:
893
894
(matrix) The matrix of the Hecke operator `T(p)` on this
895
space, with respect to its standard basis.
896
897
ALGORITHM:
898
899
Use Heilbronn-Cremona matrices if `p` is prime, else use
900
Heilbronn-Merel matrices.
901
902
EXAMPLES:
903
904
We first compute some examples for Gamma0(N)::
905
906
sage: m = ModularSymbols(2, weight=4)
907
sage: m._compute_hecke_matrix_prime(2).charpoly('x')
908
x^2 - 9*x + 8
909
910
::
911
912
sage: m = ModularSymbols(1,weight=12)
913
sage: m._compute_hecke_matrix_prime(2).charpoly('x')
914
x^3 - 2001*x^2 - 97776*x - 1180224
915
sage: m._compute_hecke_matrix_prime(13).charpoly('x')
916
x^3 - 1792159238562*x^2 - 2070797989680255444*x - 598189440899986203208472
917
918
::
919
920
sage: m = ModularSymbols(1,weight=12, sign=-1)
921
sage: m._compute_hecke_matrix_prime(5)
922
[4830]
923
sage: m._compute_hecke_matrix_prime(23)
924
[18643272]
925
926
::
927
928
sage: m = ModularSymbols(3,4)
929
sage: m._compute_hecke_matrix_prime(2).charpoly('x')
930
x^2 - 18*x + 81
931
932
::
933
934
sage: m = ModularSymbols(6,4)
935
sage: m._compute_hecke_matrix_prime(2).charpoly('x')
936
x^6 - 14*x^5 + 29*x^4 + 172*x^3 - 124*x^2 - 320*x + 256
937
sage: m._compute_hecke_matrix_prime(3).charpoly('x')
938
x^6 - 50*x^5 + 511*x^4 + 3012*x^3 - 801*x^2 - 9234*x + 6561
939
940
::
941
942
sage: m = ModularSymbols(15,4, sign=-1)
943
sage: m._compute_hecke_matrix_prime(3).charpoly('x')
944
x^4 - 2*x^3 + 18*x^2 + 18*x - 243
945
946
::
947
948
sage: m = ModularSymbols(6,4)
949
sage: m._compute_hecke_matrix_prime(7).charpoly('x')
950
x^6 - 1344*x^5 + 666240*x^4 - 140462080*x^3 + 8974602240*x^2 + 406424518656*x + 3584872677376
951
952
::
953
954
sage: m = ModularSymbols(4,4)
955
sage: m._compute_hecke_matrix_prime(3).charpoly('x')
956
x^3 - 84*x^2 + 2352*x - 21952
957
958
We now compute some examples for modular symbols on Gamma1(N)::
959
960
sage: m = ModularSymbols(Gamma1(13),2, sign=-1)
961
sage: m._compute_hecke_matrix_prime(2).charpoly('x')
962
x^2 + 3*x + 3
963
964
The following is an example with odd weight::
965
966
sage: m = ModularSymbols(Gamma1(5),3)
967
sage: m._compute_hecke_matrix_prime(2).charpoly('x')
968
x^4 - 10*x^3 + 50*x^2 - 170*x + 289
969
970
This example has composite conductor and weight2 dividing the
971
conductor and nontrivial sign::
972
973
sage: m = ModularSymbols(Gamma1(9),3, sign=1)
974
sage: m._compute_hecke_matrix_prime(3).charpoly('x')
975
x^6 + 3*x^4 - 19*x^3 + 24*x^2 - 9*x
976
977
In some situations we do not need all the rows of the result, and can thereby save time::
978
979
sage: m = ModularSymbols(1,weight=12)
980
sage: m._compute_hecke_matrix_prime(2)
981
[ -24 0 0]
982
[ 0 -24 0]
983
[4860 0 2049]
984
sage: m._compute_hecke_matrix_prime(2,rows=[0,1])
985
[-24 0 0]
986
[ 0 -24 0]
987
sage: m._compute_hecke_matrix_prime(2,rows=[1,2])
988
[ 0 -24 0]
989
[4860 0 2049]
990
"""
991
# note -- p doesn't have to be prime despite the function name
992
p = int(rings.Integer(p)) # go through Integer so p = 2.5 gives an error.
993
if isinstance(rows, list):
994
rows = tuple(rows)
995
try:
996
return self._hecke_matrices[(p,rows)]
997
except AttributeError:
998
self._hecke_matrices = {}
999
except KeyError:
1000
pass
1001
tm = misc.verbose("Computing Hecke operator T_%s"%p)
1002
1003
if arith.is_prime(p):
1004
H = heilbronn.HeilbronnCremona(p)
1005
else:
1006
H = heilbronn.HeilbronnMerel(p)
1007
1008
B = self.manin_basis()
1009
if not rows is None:
1010
B = [B[i] for i in rows]
1011
cols = []
1012
mod2term = self._mod2term
1013
R = self.manin_gens_to_basis()
1014
K = self.base_ring()
1015
W = R.new_matrix(nrows=len(B), ncols = R.nrows())
1016
syms = self.manin_symbols()
1017
n = len(syms)
1018
j = 0
1019
for i in B:
1020
for h in H:
1021
entries = syms.apply(i,h)
1022
for k, x in entries:
1023
f, s = mod2term[k]
1024
if s != 0:
1025
W[j,f] = W[j,f] + s*K(x)
1026
j += 1
1027
tm = misc.verbose("start matrix multiply",tm)
1028
if hasattr(W, '_matrix_times_matrix_dense'):
1029
Tp = W._matrix_times_matrix_dense(R)
1030
misc.verbose("done matrix multiply and computing Hecke operator",tm)
1031
else:
1032
Tp = W * R
1033
tm = misc.verbose("done matrix multiply",tm)
1034
Tp = Tp.dense_matrix()
1035
misc.verbose("done making Hecke operator matrix dense",tm)
1036
self._hecke_matrices[(p,rows)] = Tp
1037
return Tp
1038
1039
1040
def __heilbronn_operator(self, M, H, t=1):
1041
r"""
1042
Return the matrix function to the space `M` defined by `H`, `t`.
1043
1044
.. note::
1045
1046
Users will instead use the simpler interface defined, for
1047
example, by ``hecke_matrix()`` (see examples).
1048
1049
INPUT:
1050
1051
1052
- ``M`` (ModularSymbols) -- codomain (a space of modular
1053
symbols);
1054
1055
- ``H`` (list) -- a list of matrices in `M_2(\ZZ)`;
1056
1057
- ``t`` (int, default 1) -- an integer.
1058
1059
1060
OUTPUT:
1061
1062
(free module morphism) A function from the Modular Symbol
1063
space to the Modular Symbol space `M` defined by `t` and the
1064
matrices in `H`.
1065
1066
EXAMPLES::
1067
1068
sage: M = ModularSymbols(37,2)
1069
sage: M._ModularSymbolsAmbient__heilbronn_operator(M,HeilbronnCremona(3))
1070
Hecke module morphism Heilbronn operator(The Cremona-Heilbronn matrices of determinant 3,1) defined by the matrix
1071
[ 4 0 0 0 -1]
1072
[ 0 -1 2 2 -2]
1073
[ 0 2 -1 2 0]
1074
[ 0 0 0 -3 2]
1075
[ 0 0 0 0 1]
1076
Domain: Modular Symbols space of dimension 5 for Gamma_0(37) of weight ...
1077
Codomain: Modular Symbols space of dimension 5 for Gamma_0(37) of weight ...
1078
1079
sage: M.hecke_matrix(3)
1080
[ 4 0 0 0 -1]
1081
[ 0 -1 2 2 -2]
1082
[ 0 2 -1 2 0]
1083
[ 0 0 0 -3 2]
1084
[ 0 0 0 0 1]
1085
1086
1087
"""
1088
1089
MS = matrix_space.MatrixSpace(self.base_ring(), self.dimension(), M.dimension())
1090
hom = self.Hom(M)
1091
if self.dimension() == 0 or M.dimension() == 0:
1092
A = MS(0)
1093
phi = hom(A, "Heilbronn operator(%s,%s)"%(H,t))
1094
return phi
1095
1096
rows = []
1097
B = self.manin_basis()
1098
syms = self.manin_symbols()
1099
k = self.weight()
1100
for n in B:
1101
z = M(0)
1102
i, u, v = syms[n]
1103
# We apply each Heilbronn matrix to the
1104
# Manin symbol [X^i*Y^(k-2-i), (u,v)]
1105
for h in H:
1106
# Apply h to the polynomial part
1107
(a,b,c,d) = tuple(h)
1108
# P gives the ordered coefficients of (a*X+b*Y)^i*(c*X+d*Y)^(j-i)
1109
P = manin_symbols.apply_to_monomial(i, k-2, a,b,c,d)
1110
# Apply h to the (u,v) part of the Manin symbol
1111
(uu,vv) = (u*a+v*c, u*b+v*d)
1112
1113
# For the generalized Heilbronn operator, we through away any
1114
# symbols for which the (u,v) part of the symbol doesn't have
1115
# both entries divisible by t.
1116
if t != 1:
1117
if uu%t != 0 or vv%t != 0:
1118
continue
1119
uu = uu//t
1120
vv = vv//t
1121
1122
# Now coerce each Manin symbol
1123
#
1124
# P[m]*[X^m*Y^(k-2-m), (uu,vv)], for m=0,...,len(P)
1125
#
1126
# into the image space M and add that to z.
1127
# Note that we coerce in Manin symbols as tuples.
1128
for m in range(len(P)):
1129
x = M((m,uu,vv))
1130
z += x*P[m]
1131
1132
rows.append(z.element())
1133
1134
A = MS(rows)
1135
return hom(A, "Heilbronn operator(%s,%s)"%(H,t))
1136
1137
def _repr_(self):
1138
r"""
1139
String representation of this Modular Symbols space.
1140
1141
EXAMPLES::
1142
1143
sage: m = ModularSymbols(1,weight=12)
1144
sage: m # indirect doctest
1145
Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field
1146
"""
1147
return "Modular Symbols space of dimension %s and weight %s for %s with sign %s and character %s over %s"%(
1148
self.dimension(), self.weight(), self.group(), self.sign(), self.character()._repr_short_(), self.base_ring())
1149
1150
def _latex_(self):
1151
r"""
1152
Latex representation of this Modular Symbols space.
1153
1154
EXAMPLES::
1155
1156
sage: m = ModularSymbols(11,weight=12)
1157
sage: latex(m) # indirect doctest
1158
\mathrm{ModSym}_{12}(\Gamma_0(11),\left[1\right];\Bold{Q})
1159
1160
sage: chi = DirichletGroup(7).0
1161
sage: m = ModularSymbols(chi)
1162
sage: latex(m)
1163
\mathrm{ModSym}_{2}(\Gamma_1(7),\left[\zeta_{6}\right];\Bold{Q}(\zeta_{6}))
1164
1165
"""
1166
return "\\mathrm{ModSym}_{%s}(%s,%s;%s)"%(self.weight(),
1167
latex.latex(self.group()),
1168
latex.latex(list(self.character().values_on_gens())),
1169
latex.latex(self.base_ring()))
1170
1171
def _matrix_of_operator_on_modular_symbols(self, codomain, R):
1172
r"""
1173
Returns the matrix of a modular symbols operator.
1174
1175
.. note::
1176
1177
Users will usually instead use the simpler interface
1178
defined, for example, by ``hecke_matrix()`` (see examples),
1179
though this function allows one to compute much more
1180
general operators.
1181
1182
INPUT:
1183
1184
- ``codomain`` - space of modular symbols
1185
1186
- ``R`` (list) -- a list of lists `[a,b,c,d]` of length 4,
1187
which we view as elements of `GL_2(`QQ)`.
1188
1189
1190
OUTPUT:
1191
1192
-- (matrix) The matrix of the operator
1193
1194
.. math::
1195
1196
x \mapsto \sum_{g in R} g.x,
1197
1198
1199
where `g.x` is the formal linear fractional transformation on modular
1200
symbols, with respect to the standard basis.
1201
1202
EXAMPLES::
1203
1204
sage: M = ModularSymbols(37,2)
1205
sage: M._matrix_of_operator_on_modular_symbols(M,HeilbronnCremona(3))
1206
[ 4 0 0 0 0]
1207
[ 0 -3 1 1 0]
1208
[ 0 3 0 5 -2]
1209
[ 0 -3 1 -5 3]
1210
[ 0 0 2 3 -3]
1211
1212
"""
1213
rows = []
1214
for b in self.basis():
1215
v = formal_sum.FormalSum(0, check=False)
1216
for c, x in b.modular_symbol_rep():
1217
for g in R:
1218
y = x.apply(g)
1219
v += y*c
1220
w = codomain(v).element()
1221
rows.append(w)
1222
M = matrix_space.MatrixSpace(self.base_ring(), len(rows), codomain.degree(), sparse=False)
1223
return M(rows)
1224
1225
def _compute_atkin_lehner_matrix(self, d):
1226
r"""
1227
Return the matrix of the Atkin-Lehner involution `W_d`.
1228
1229
INPUT:
1230
1231
- ``d`` (int) -- an integer that divides the level.
1232
1233
OUTPUT:
1234
1235
(matrix) The matrix of the involution `W_d` with respect to
1236
the standard basis.
1237
1238
EXAMPLES: An example at level 29::
1239
1240
sage: M = ModularSymbols((DirichletGroup(29,QQ).0), 2,1); M
1241
Modular Symbols space of dimension 4 and level 29, weight 2, character [-1], sign 1, over Rational Field
1242
sage: w = M._compute_atkin_lehner_matrix(29)
1243
sage: w^2 == 1
1244
True
1245
sage: w.fcp()
1246
(x - 1)^2 * (x + 1)^2
1247
1248
This doesn't work since the character has order 2::
1249
1250
sage: M = ModularSymbols((DirichletGroup(13).0), 2,1); M
1251
Modular Symbols space of dimension 0 and level 13, weight 2, character [zeta12], sign 1, over Cyclotomic Field of order 12 and degree 4
1252
sage: M._compute_atkin_lehner_matrix(13)
1253
Traceback (most recent call last):
1254
...
1255
ValueError: Atkin-Lehner only leaves space invariant when character is trivial or quadratic. In general it sends M_k(chi) to M_k(1/chi)
1256
1257
Note that Atkin-Lehner does make sense on `\Gamma_1(13)`,
1258
but doesn't commute with the Hecke operators::
1259
1260
sage: M = ModularSymbols(Gamma1(13),2)
1261
sage: w = M.atkin_lehner_operator(13).matrix()
1262
sage: t = M.T(2).matrix()
1263
sage: t*w == w*t
1264
False
1265
sage: w^2 == 1
1266
True
1267
"""
1268
chi = self.character()
1269
if chi is not None and chi.order() > 2:
1270
raise ValueError("Atkin-Lehner only leaves space invariant when character is trivial or quadratic. In general it sends M_k(chi) to M_k(1/chi)")
1271
1272
N = self.level()
1273
k = self.weight()
1274
R = self.base_ring()
1275
if N%d != 0:
1276
raise ValueError("d must divide N")
1277
1278
g, x, y = arith.xgcd(d, -N//d)
1279
g = [d*x, y, N, d]
1280
A = self._action_on_modular_symbols(g)
1281
scale = R(d)**(1 - k//2)
1282
Wmat = scale * A
1283
return Wmat
1284
1285
def boundary_map(self):
1286
r"""
1287
Return the boundary map to the corresponding space of boundary modular
1288
symbols.
1289
1290
EXAMPLES::
1291
1292
sage: ModularSymbols(20,2).boundary_map()
1293
Hecke module morphism boundary map defined by the matrix
1294
[ 1 -1 0 0 0 0]
1295
[ 0 1 -1 0 0 0]
1296
[ 0 1 0 -1 0 0]
1297
[ 0 0 0 -1 1 0]
1298
[ 0 1 0 -1 0 0]
1299
[ 0 0 1 -1 0 0]
1300
[ 0 1 0 0 0 -1]
1301
Domain: Modular Symbols space of dimension 7 for Gamma_0(20) of weight ...
1302
Codomain: Space of Boundary Modular Symbols for Congruence Subgroup Gamma0(20) ...
1303
sage: type(ModularSymbols(20,2).boundary_map())
1304
<class 'sage.modular.hecke.morphism.HeckeModuleMorphism_matrix'>
1305
"""
1306
try:
1307
return self.__boundary_map
1308
except AttributeError:
1309
# compute boundary map
1310
B = self.boundary_space()
1311
I = [B(b) for b in self.basis()]
1312
W = matrix_space.MatrixSpace(self.base_ring(), len(I), B.rank(), sparse=True)
1313
1314
# Note -- the underlying elements have degree the number of distinct
1315
# cusps known when the element was computed. This isn't constant,
1316
# so we pad the elements.
1317
E = [x.element() for x in I]
1318
zero = self.base_ring()(0)
1319
n = int(B.dimension())
1320
E = sum([ list(x) + [zero]*(n - len(x)) for x in E ], [])
1321
1322
A = W( E )
1323
H = cat.Hom(self, B)
1324
self.__boundary_map = H(A, "boundary map")
1325
return self.__boundary_map
1326
1327
def cusps(self):
1328
r"""
1329
Return the set of cusps for this modular symbols space.
1330
1331
EXAMPLES::
1332
1333
sage: ModularSymbols(20,2).cusps()
1334
[Infinity, 0, -1/4, 1/5, -1/2, 1/10]
1335
"""
1336
try:
1337
return self.__cusps
1338
except AttributeError:
1339
f = self.boundary_map()
1340
B = f.codomain()
1341
C = B._known_cusps()
1342
self.__cusps = C
1343
return C
1344
1345
def boundary_space(self):
1346
r"""
1347
Return the subspace of boundary modular symbols of this modular symbols ambient space.
1348
1349
EXAMPLES::
1350
1351
sage: M = ModularSymbols(20, 2)
1352
sage: B = M.boundary_space(); B
1353
Space of Boundary Modular Symbols for Congruence Subgroup Gamma0(20) of weight 2 and over Rational Field
1354
sage: M.cusps()
1355
[Infinity, 0, -1/4, 1/5, -1/2, 1/10]
1356
sage: M.dimension()
1357
7
1358
sage: B.dimension()
1359
6
1360
"""
1361
raise NotImplementedError
1362
1363
def cuspidal_submodule(self):
1364
"""
1365
The cuspidal submodule of this modular symbols ambient space.
1366
1367
EXAMPLES::
1368
1369
sage: M = ModularSymbols(12,2,0,GF(5)) ; M
1370
Modular Symbols space of dimension 5 for Gamma_0(12) of weight 2 with sign 0 over Finite Field of size 5
1371
sage: M.cuspidal_submodule()
1372
Modular Symbols subspace of dimension 0 of Modular Symbols space of dimension 5 for Gamma_0(12) of weight 2 with sign 0 over Finite Field of size 5
1373
sage: ModularSymbols(1,24,-1).cuspidal_submodule()
1374
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 2 for Gamma_0(1) of weight 24 with sign -1 over Rational Field
1375
1376
The cuspidal submodule of the cuspidal submodule is itself::
1377
1378
sage: M = ModularSymbols(389)
1379
sage: S = M.cuspidal_submodule()
1380
sage: S.cuspidal_submodule() is S
1381
True
1382
"""
1383
try:
1384
return self.__cuspidal_submodule
1385
except AttributeError:
1386
try:
1387
if self.__is_cuspidal:
1388
return self
1389
except AttributeError:
1390
pass
1391
S = self.boundary_map().kernel()
1392
S._set_is_cuspidal(True)
1393
S._is_full_hecke_module = True
1394
## We know the cuspidal subspace is stable, so
1395
## if it's one-dimensional, it must be simple
1396
if S.dimension() == 1:
1397
S._is_simple = True
1398
if self.base_ring().characteristic() == 0:
1399
d = self._cuspidal_submodule_dimension_formula()
1400
if not d is None:
1401
assert d == S.dimension(), "According to dimension formulas the cuspidal subspace of \"%s\" has dimension %s; however, computing it using modular symbols we obtained %s, so there is a bug (please report!)."%(self, d, S.dimension())
1402
self.__cuspidal_submodule = S
1403
return self.__cuspidal_submodule
1404
1405
def _degeneracy_raising_matrix(self, M, t):
1406
r"""
1407
Return the matrix of the level-raising degeneracy map from self to M,
1408
of index t. This is calculated by composing the level-raising matrix
1409
for `t = 1` with a Hecke operator.
1410
1411
INPUT:
1412
1413
- ``M`` (int) -- a space of modular symbols whose level is an integer
1414
multiple of the the level of self
1415
1416
- ``t`` (int) -- a positive integer dividing the quotient of the two
1417
levels.
1418
1419
OUTPUT:
1420
1421
(matrix) The matrix of the degeneracy map of index `t` from this space
1422
of level `N` to the space `M` (of level a multiple of `N`). Here `t` is
1423
a divisor of the quotient.
1424
1425
EXAMPLES::
1426
1427
sage: A = ModularSymbols(11, 2); B = ModularSymbols(22, 2)
1428
sage: A._degeneracy_raising_matrix(B, 1)
1429
[ 1 0 0 0 0 -1 -1]
1430
[ 0 1 0 -3 1 1 -1]
1431
[ 0 1 1 -1 -1 0 0]
1432
sage: A._degeneracy_raising_matrix(B, 2)
1433
[ 2 0 0 0 1 0 -1]
1434
[ 0 0 -1 3 -1 -1 1]
1435
[ 0 -1 -1 1 0 1 -1]
1436
1437
Check that :trac:`13198` is fixed::
1438
1439
sage: M22 = ModularSymbols(Gamma1(22), sign=1)
1440
sage: M2 = ModularSymbols(Gamma1(2))
1441
sage: d1 = M2.degeneracy_map(M22,1)
1442
sage: d2 = M2.degeneracy_map(M22,11)
1443
sage: M22.hecke_matrix(17).restrict((d1.image() + d2.image()).free_module())
1444
[18 0]
1445
[ 0 18]
1446
sage: S = M22.cuspidal_submodule()
1447
sage: S.new_submodule().intersection(S.old_submodule()) == S.zero_submodule()
1448
True
1449
"""
1450
if t == 1:
1451
return self._degeneracy_raising_matrix_1(M)
1452
else:
1453
# use Hecke operator and t=1 case.
1454
d1 = self.degeneracy_map(M, 1).matrix()
1455
T = M.hecke_matrix(t)
1456
return (~self.base_ring()(t)) * d1 * T
1457
1458
def _degeneracy_raising_matrix_1(self, M):
1459
r"""
1460
Return the matrix of the degeneracy map to the given level
1461
(which must be a multiple of the level of self).
1462
1463
.. note::
1464
1465
Not implemented in the base class, only in the derived classes.
1466
1467
EXAMPLES::
1468
1469
sage: M = ModularSymbols(37,4)
1470
sage: M._degeneracy_raising_matrix_1(ModularSymbols(74, 4))
1471
20 x 58 dense matrix over Rational Field
1472
"""
1473
raise NotImplementedError
1474
1475
def _degeneracy_lowering_matrix(self, M, t):
1476
r"""
1477
Return the matrix of the level-lowering degeneracy map from self to M.
1478
1479
INPUT:
1480
1481
- ``M`` -- a modular symbols space whose level divides the level of
1482
self
1483
1484
- ``t`` (int) -- a positive integer dividing the quotient of the
1485
levels.
1486
1487
OUTPUT:
1488
1489
(matrix) The matrix of the degeneracy map from this space to the space
1490
`M` of index `t`, where `t` is a divisor of the quotient of the levels
1491
of self and `M`.
1492
1493
EXAMPLES::
1494
1495
sage: M = ModularSymbols(22,2)
1496
sage: M._degeneracy_lowering_matrix(ModularSymbols(11, 2), 2)
1497
[ 1 0 0]
1498
[ 0 1 -1]
1499
[ 0 0 -1]
1500
[ 0 1 0]
1501
[ 0 0 0]
1502
[-1 0 1]
1503
[-1 0 0]
1504
"""
1505
# Use Proposition 2.6.15 in Merel's 1585 paper (or Prop 15 in
1506
# electronic version of that paper).
1507
H = heilbronn.HeilbronnMerel(t)
1508
return self.__heilbronn_operator(M,H,t).matrix()
1509
1510
def rank(self):
1511
"""
1512
Returns the rank of this modular symbols ambient space.
1513
1514
OUTPUT:
1515
1516
(int) The rank of this space of modular symbols.
1517
1518
EXAMPLES::
1519
1520
sage: M = ModularSymbols(389)
1521
sage: M.rank()
1522
65
1523
1524
::
1525
1526
sage: ModularSymbols(11,sign=0).rank()
1527
3
1528
sage: ModularSymbols(100,sign=0).rank()
1529
31
1530
sage: ModularSymbols(22,sign=1).rank()
1531
5
1532
sage: ModularSymbols(1,12).rank()
1533
3
1534
sage: ModularSymbols(3,4).rank()
1535
2
1536
sage: ModularSymbols(8,6,sign=-1).rank()
1537
3
1538
"""
1539
try:
1540
return self.__rank
1541
except AttributeError:
1542
self.__rank = len(self.manin_basis())
1543
return self.__rank
1544
1545
def eisenstein_submodule(self):
1546
"""
1547
Return the Eisenstein submodule of this space of modular symbols.
1548
1549
EXAMPLES::
1550
1551
sage: ModularSymbols(20,2).eisenstein_submodule()
1552
Modular Symbols subspace of dimension 5 of Modular Symbols space of dimension 7 for Gamma_0(20) of weight 2 with sign 0 over Rational Field
1553
"""
1554
try:
1555
return self.__eisenstein_submodule
1556
except AttributeError:
1557
self.__eisenstein_submodule = self.cuspidal_submodule().complement()
1558
return self.__eisenstein_submodule
1559
1560
def element(self, x):
1561
"""
1562
Creates and returns an element of self from a modular symbol, if
1563
possible.
1564
1565
INPUT:
1566
1567
1568
- ``x`` - an object of one of the following types:
1569
ModularSymbol, ManinSymbol.
1570
1571
1572
OUTPUT:
1573
1574
ModularSymbol - a modular symbol with parent self.
1575
1576
EXAMPLES::
1577
1578
sage: M = ModularSymbols(11,4,1)
1579
sage: M.T(3)
1580
Hecke operator T_3 on Modular Symbols space of dimension 4 for Gamma_0(11) of weight 4 with sign 1 over Rational Field
1581
sage: M.T(3)(M.0)
1582
28*[X^2,(0,1)] + 2*[X^2,(1,7)] - [X^2,(1,9)] - [X^2,(1,10)]
1583
sage: M.T(3)(M.0).element()
1584
(28, 2, -1, -1)
1585
"""
1586
if isinstance(x, manin_symbols.ManinSymbol):
1587
if not x.parent().weight() == self.weight():
1588
raise ArithmeticError("incompatible weights: Manin symbol\
1589
has weight %s, but modular symbols space has weight %s"%(
1590
x.parent().weight(), self.weight()))
1591
t = self.manin_symbols().index(x.tuple())
1592
if isinstance(t, tuple):
1593
i, scalar = t
1594
v = self.manin_gens_to_basis().row(i) * scalar
1595
else:
1596
v = self.manin_gens_to_basis().row(t)
1597
return element.ModularSymbolsElement(self, v)
1598
1599
elif isinstance(x, element.ModularSymbolsElement):
1600
M = x.parent()
1601
if M.ambient_hecke_module() != self:
1602
# TODO -- sometimes do something more sophisticated here.
1603
raise TypeError("Modular symbol (%s) does not lie in this space."%x)
1604
return self(x.element())
1605
1606
else:
1607
raise ValueError("Cannot create element of %s from %s."%(x,self))
1608
1609
def dual_star_involution_matrix(self):
1610
"""
1611
Return the matrix of the dual star involution, which is induced by
1612
complex conjugation on the linear dual of modular symbols.
1613
1614
EXAMPLES::
1615
1616
sage: ModularSymbols(20,2).dual_star_involution_matrix()
1617
[1 0 0 0 0 0 0]
1618
[0 1 0 0 0 0 0]
1619
[0 0 0 0 1 0 0]
1620
[0 0 0 1 0 0 0]
1621
[0 0 1 0 0 0 0]
1622
[0 0 0 0 0 1 0]
1623
[0 0 0 0 0 0 1]
1624
"""
1625
try:
1626
return self.__dual_star_involution_matrix
1627
except AttributeError:
1628
pass
1629
self.__dual_star_involution_matrix = self.star_involution().matrix().transpose()
1630
return self.__dual_star_involution_matrix
1631
1632
def factorization(self):
1633
r"""
1634
Returns a list of pairs `(S,e)` where `S` is spaces
1635
of modular symbols and self is isomorphic to the direct sum of the
1636
`S^e` as a module over the *anemic* Hecke algebra adjoin
1637
the star involution. The cuspidal `S` are all simple, but
1638
the Eisenstein factors need not be simple.
1639
1640
EXAMPLES::
1641
1642
sage: ModularSymbols(Gamma0(22), 2).factorization()
1643
(Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field)^2 *
1644
(Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field)^2 *
1645
(Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 7 for Gamma_0(22) of weight 2 with sign 0 over Rational Field)
1646
1647
::
1648
1649
sage: ModularSymbols(1,6,0,GF(2)).factorization()
1650
(Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 2 for Gamma_0(1) of weight 6 with sign 0 over Finite Field of size 2) *
1651
(Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 2 for Gamma_0(1) of weight 6 with sign 0 over Finite Field of size 2)
1652
1653
::
1654
1655
sage: ModularSymbols(18,2).factorization()
1656
(Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 7 for Gamma_0(18) of weight 2 with sign 0 over Rational Field) *
1657
(Modular Symbols subspace of dimension 5 of Modular Symbols space of dimension 7 for Gamma_0(18) of weight 2 with sign 0 over Rational Field)
1658
1659
::
1660
1661
sage: M = ModularSymbols(DirichletGroup(38,CyclotomicField(3)).0^2, 2, +1); M
1662
Modular Symbols space of dimension 7 and level 38, weight 2, character [zeta3], sign 1, over Cyclotomic Field of order 3 and degree 2
1663
sage: M.factorization() # long time (about 8 seconds)
1664
(Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 7 and level 38, weight 2, character [zeta3], sign 1, over Cyclotomic Field of order 3 and degree 2) *
1665
(Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 7 and level 38, weight 2, character [zeta3], sign 1, over Cyclotomic Field of order 3 and degree 2) *
1666
(Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 7 and level 38, weight 2, character [zeta3], sign 1, over Cyclotomic Field of order 3 and degree 2) *
1667
(Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 7 and level 38, weight 2, character [zeta3], sign 1, over Cyclotomic Field of order 3 and degree 2)
1668
"""
1669
1670
## EXAMPLES:
1671
## sage: M = ModularSymbols(Gamma0(22), 2); M
1672
## Modular Symbols space of dimension 7 for Gamma_0(22) of weight 2 with sign 0 over Rational Field
1673
## sage: M.factorization():
1674
## ... print b.dimension(), b.level(), e
1675
## 1 11 2
1676
## 1 11 2
1677
## 1 11 2
1678
## 1 22 1
1679
1680
## An example with sign 1:
1681
## sage: M = ModularSymbols(Gamma0(22), 2, sign=1); M
1682
## Modular Symbols space of dimension 5 for Gamma_0(22) of weight 2 with sign 1 over Rational Field
1683
## sage: for b, e in M.factorization():
1684
## ... print b.dimension(), b.level(), e
1685
## 1 11 2
1686
## 1 11 2
1687
## 1 22 1
1688
1689
## An example for Gamma1:
1690
## sage: M = ModularSymbols(Gamma1(26), 2, sign=1); M
1691
## Modular Symbols space of dimension 33 for Gamma_1(26) of weight 2 with sign 1 and over Rational Field
1692
## sage: for b, e in M.factorization():
1693
## ... print b.dimension(), b.level(), e
1694
## 1 13 2
1695
## 1 13 2
1696
## 1 13 2
1697
## 2 13 2
1698
## 2 13 2
1699
## 2 13 2
1700
## 2 13 2
1701
## 2 13 2
1702
## 1 26 1
1703
## 1 26 1
1704
## 1 26 1
1705
## 2 26 1
1706
## 2 26 1
1707
1708
## An example with level divisible by a square:
1709
## sage: M = ModularSymbols(Gamma0(2*9),2); M
1710
## ???
1711
## sage: for b, e in M.factorization():
1712
## ... print b.dimension(), b.level(), e
1713
## ???
1714
try:
1715
return self._factorization
1716
except AttributeError:
1717
pass
1718
1719
try:
1720
if self._is_simple:
1721
return [self]
1722
except AttributeError:
1723
pass
1724
1725
D = []
1726
1727
# Treat the cuspidal and eisenstein parts separately. The
1728
# cuspidal part is very straightforward because of
1729
# Atkin-Lehner-Li theory. The eisenstein part is trickier,
1730
# because of E2 and that the new and old Eisenstein subspaces
1731
# can intersect (e.g., they do for M_2(Gamma_0(6))), even
1732
# in a way that involves forms other than E_2 (i.e., twists
1733
# of E2).
1734
1735
# 1. Cuspidal part -- compute the factors and their multiplicities
1736
# using Atkin-Lehner-Li.
1737
1738
# 2. Eisenstein part -- just call normal decomposition.
1739
1740
# In the special case of weight 2 we have to do a bunch of
1741
# annoying extra work below to deal with the Eisenstein series E_2.
1742
k = self.weight()
1743
1744
## If the characteristic of the base ring is 2,
1745
## the star involution is the identity, so we
1746
## want to avoid adding each cuspidal submodule
1747
## twice.
1748
if self.base_ring().characteristic() == 2:
1749
skip_minus = True
1750
else:
1751
skip_minus = False
1752
1753
# The cuspidal part
1754
# We only run through spaces of level a multiple of the conductor of the character, which
1755
# we compute below, or set to 1 in case of Gamma_H or Gamma_1
1756
chi = self.character()
1757
cond = 1 if chi is None else chi.conductor()
1758
# Now actually run through the divisor levels, taking only the ones with that are
1759
# a multiple of the conductor.
1760
for d in reversed(arith.divisors(self.level())):
1761
if d%cond != 0: continue
1762
n = arith.number_of_divisors(self.level() // d)
1763
M = self.modular_symbols_of_level(d)
1764
N = M.new_submodule().cuspidal_submodule().decomposition()
1765
for A in N:
1766
if self.sign() == 0:
1767
V = A.plus_submodule()
1768
V._is_simple = True
1769
D.append((V,n))
1770
if skip_minus:
1771
continue
1772
V = A.minus_submodule()
1773
V._is_simple = True
1774
D.append((V,n))
1775
else:
1776
A._is_simple = True
1777
D.append((A,n))
1778
# The eisenstein part
1779
for E in self.eisenstein_submodule().decomposition(anemic=True):
1780
D.append((E,1))
1781
1782
r = self.dimension()
1783
s = sum([A.rank()*mult for A, mult in D])
1784
D = sage.structure.all.Factorization(D, cr=True, sort=False)
1785
D.sort(_cmp = cmp)
1786
assert r == s, "bug in factorization -- self has dimension %s, but sum of dimensions of factors is %s\n%s"%(r, s, D)
1787
self._factorization = D
1788
return self._factorization
1789
1790
factor = factorization
1791
1792
def is_cuspidal(self):
1793
r"""
1794
Returns True if this space is cuspidal, else False.
1795
1796
EXAMPLES::
1797
1798
sage: M = ModularSymbols(20,2)
1799
sage: M.is_cuspidal()
1800
False
1801
sage: S = M.cuspidal_subspace()
1802
sage: S.is_cuspidal()
1803
True
1804
sage: S = M.eisenstein_subspace()
1805
sage: S.is_cuspidal()
1806
False
1807
"""
1808
try:
1809
return self.__is_cuspidal
1810
except AttributeError:
1811
S = self.ambient_hecke_module().cuspidal_submodule()
1812
self.__is_cuspidal = (S.dimension() == self.dimension())
1813
return self.__is_cuspidal
1814
1815
def is_eisenstein(self):
1816
r"""
1817
Returns True if this space is Eisenstein, else False.
1818
1819
EXAMPLES::
1820
1821
sage: M = ModularSymbols(20,2)
1822
sage: M.is_eisenstein()
1823
False
1824
sage: S = M.eisenstein_submodule()
1825
sage: S.is_eisenstein()
1826
True
1827
sage: S = M.cuspidal_subspace()
1828
sage: S.is_eisenstein()
1829
False
1830
"""
1831
try:
1832
return self.__is_eisenstein
1833
except AttributeError:
1834
S = self.ambient_hecke_module().eisenstein_submodule()
1835
self.__is_eisenstein = self.dimension()==S.dimension()
1836
return self.__is_eisenstein
1837
1838
def manin_symbols_basis(self):
1839
"""
1840
A list of Manin symbols that form a basis for the ambient space
1841
self. INPUT:
1842
1843
1844
- ``ModularSymbols self`` - an ambient space of
1845
modular symbols
1846
1847
1848
OUTPUT:
1849
1850
1851
- ``list`` - a list of 2-tuples (if the weight is 2)
1852
or 3-tuples, which represent the Manin symbols basis for self.
1853
1854
1855
EXAMPLES::
1856
1857
sage: m = ModularSymbols(23)
1858
sage: m.manin_symbols_basis()
1859
[(1,0), (1,17), (1,19), (1,20), (1,21)]
1860
sage: m = ModularSymbols(6, weight=4, sign=-1)
1861
sage: m.manin_symbols_basis()
1862
[[X^2,(2,1)]]
1863
"""
1864
s = self.manin_symbols()
1865
return [s.manin_symbol(i) for i in self.manin_basis()]
1866
1867
1868
def modular_symbols_of_sign(self, sign):
1869
r"""
1870
Returns a space of modular symbols with the same defining
1871
properties (weight, level, etc.) as this space except with given
1872
sign.
1873
1874
INPUT:
1875
1876
- ``sign`` (int) -- A sign (`+1`, `-1` or `0`).
1877
1878
OUTPUT:
1879
1880
(ModularSymbolsAmbient) A space of modular symbols with the
1881
same defining properties (weight, level, etc.) as this space
1882
except with given sign.
1883
1884
EXAMPLES::
1885
1886
sage: M = ModularSymbols(Gamma0(11),2,sign=0)
1887
sage: M
1888
Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field
1889
sage: M.modular_symbols_of_sign(-1)
1890
Modular Symbols space of dimension 1 for Gamma_0(11) of weight 2 with sign -1 over Rational Field
1891
sage: M = ModularSymbols(Gamma1(11),2,sign=0)
1892
sage: M.modular_symbols_of_sign(-1)
1893
Modular Symbols space of dimension 1 for Gamma_1(11) of weight 2 with sign -1 and over Rational Field
1894
"""
1895
if sign == self.sign():
1896
return self
1897
return modsym.ModularSymbols(self.group(), self.weight(), sign=sign, base_ring=self.base_ring())
1898
1899
1900
def modular_symbols_of_weight(self, k):
1901
r"""
1902
Returns a space of modular symbols with the same defining
1903
properties (weight, sign, etc.) as this space except with weight
1904
`k`.
1905
1906
INPUT:
1907
1908
- ``k`` (int) -- A positive integer.
1909
1910
OUTPUT:
1911
1912
(ModularSymbolsAmbient) A space of modular symbols with the
1913
same defining properties (level, sign) as this space
1914
except with given weight.
1915
1916
EXAMPLES::
1917
1918
sage: M = ModularSymbols(Gamma1(6),2,sign=0)
1919
sage: M.modular_symbols_of_weight(3)
1920
Modular Symbols space of dimension 4 for Gamma_1(6) of weight 3 with sign 0 and over Rational Field
1921
"""
1922
if k == self.weight():
1923
return self
1924
return modsym.ModularSymbols(self.group(), weight=k, sign=self.sign(), base_ring=self.base_ring())
1925
1926
def _compute_sign_submodule(self, sign, compute_dual=True):
1927
r"""
1928
Return the subspace of self that is fixed under the star
1929
involution.
1930
1931
INPUT:
1932
1933
1934
- ``sign`` - int (either -1 or +1)
1935
1936
- ``compute_dual`` - bool (default: True) also
1937
compute dual subspace. This are useful for many algorithms.
1938
1939
1940
OUTPUT:
1941
1942
A subspace of modular symbols
1943
1944
EXAMPLES::
1945
1946
sage: ModularSymbols(1,12,0,GF(5)).minus_submodule() ## indirect doctest
1947
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Finite Field of size 5
1948
"""
1949
S = self.star_involution().matrix() - self.base_ring()(sign)
1950
V = S.kernel()
1951
if compute_dual:
1952
Vdual = S.transpose().kernel()
1953
M = self.submodule(V, Vdual, check=False)
1954
else:
1955
M = self.submodule(V, check=False)
1956
M._set_sign(sign)
1957
return M
1958
1959
def star_involution(self):
1960
r"""
1961
Return the star involution on this modular symbols space.
1962
1963
OUTPUT:
1964
1965
(matrix) The matrix of the star involution on this space,
1966
which is induced by complex conjugation on modular symbols,
1967
with respect to the standard basis.
1968
1969
EXAMPLES::
1970
1971
sage: ModularSymbols(20,2).star_involution()
1972
Hecke module morphism Star involution on Modular Symbols space of dimension 7 for Gamma_0(20) of weight 2 with sign 0 over Rational Field defined by the matrix
1973
[1 0 0 0 0 0 0]
1974
[0 1 0 0 0 0 0]
1975
[0 0 0 0 1 0 0]
1976
[0 0 0 1 0 0 0]
1977
[0 0 1 0 0 0 0]
1978
[0 0 0 0 0 1 0]
1979
[0 0 0 0 0 0 1]
1980
Domain: Modular Symbols space of dimension 7 for Gamma_0(20) of weight ...
1981
Codomain: Modular Symbols space of dimension 7 for Gamma_0(20) of weight ...
1982
"""
1983
try:
1984
return self.__star_involution
1985
except AttributeError:
1986
pass
1987
S = self.__heilbronn_operator(self, [[-1,0, 0,1]], 1)
1988
S.name("Star involution on %s"%self)
1989
self.__star_involution = S
1990
return self.__star_involution
1991
1992
def _compute_diamond_matrix(self, d):
1993
r"""
1994
Return the diamond bracket d operator on this modular symbols space.
1995
1996
INPUT:
1997
1998
- `d` -- integer
1999
2000
OUTPUT:
2001
2002
- ``matrix`` - the matrix of the diamond bracket operator
2003
on this space.
2004
2005
EXAMPLES::
2006
2007
sage: e = kronecker_character(7)
2008
sage: M = ModularSymbols(e,2,sign=1)
2009
sage: D = M.diamond_bracket_operator(5); D
2010
Diamond bracket operator <5> on Modular Symbols space ...
2011
sage: D.matrix() # indirect doctest
2012
[-1 0 0 0]
2013
[ 0 -1 0 0]
2014
[ 0 0 -1 0]
2015
[ 0 0 0 -1]
2016
sage: [M.diamond_bracket_operator(d).matrix()[0,0] for d in [0..6]]
2017
[0, 1, 0, 1, 0, -1, 0]
2018
sage: [e(d) for d in [0..6]]
2019
[0, 1, 0, 1, 0, -1, 0]
2020
2021
We test that the sign issue at #8620 is fixed::
2022
2023
sage: M = Newforms(Gamma1(13),names = 'a')[0].modular_symbols(sign=0)
2024
sage: M.diamond_bracket_operator(4).matrix()
2025
[ 0 0 1 -1]
2026
[-1 -1 0 1]
2027
[-1 -1 0 0]
2028
[ 0 -1 1 -1]
2029
2030
We check that the result is correctly normalised for weight > 2::
2031
2032
sage: ModularSymbols(Gamma1(13), 5).diamond_bracket_operator(6).charpoly().factor()
2033
(x^2 + 1)^8 * (x^4 - x^2 + 1)^10
2034
"""
2035
return self.__heilbronn_operator(self, [[d,0, 0,d]], 1).matrix() * d**(2 - self.weight())
2036
2037
def submodule(self, M, dual_free_module=None, check=True):
2038
r"""
2039
Return the submodule with given generators or free module `M`.
2040
2041
INPUT:
2042
2043
2044
- ``M`` - either a submodule of this ambient free module, or
2045
generators for a submodule;
2046
2047
- ``dual_free_module`` (bool, default None) -- this may be
2048
useful to speed up certain calculations; it is the
2049
corresponding submodule of the ambient dual module;
2050
2051
- ``check`` (bool, default True) -- if True, check that `M` is
2052
a submodule, i.e. is invariant under all Hecke operators.
2053
2054
OUTPUT:
2055
2056
A subspace of this modular symbol space.
2057
2058
EXAMPLES::
2059
2060
sage: M = ModularSymbols(11)
2061
sage: M.submodule([M.0])
2062
Traceback (most recent call last):
2063
...
2064
ValueError: The submodule must be invariant under all Hecke operators.
2065
sage: M.eisenstein_submodule().basis()
2066
((1,0) - 1/5*(1,9),)
2067
sage: M.basis()
2068
((1,0), (1,8), (1,9))
2069
sage: M.submodule([M.0 - 1/5*M.2])
2070
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field
2071
2072
.. note::
2073
2074
It would make more sense to only check that `M` is invariant
2075
under the Hecke operators with index coprime to the level.
2076
Unfortunately, I do not know a reasonable algorithm for
2077
determining whether a module is invariant under just the
2078
anemic Hecke algebra, since I do not know an analogue of
2079
the Sturm bound for the anemic Hecke algebra. - William
2080
Stein, 2007-07-27
2081
"""
2082
if check:
2083
if not free_module.is_FreeModule(M):
2084
V = self.free_module()
2085
if not isinstance(M, (list,tuple)):
2086
M = M.gens()
2087
M = V.span([V(x.element()) for x in M])
2088
return subspace.ModularSymbolsSubspace(self, M, dual_free_module=dual_free_module, check=check)
2089
2090
def twisted_winding_element(self, i, eps):
2091
r"""
2092
Return the twisted winding element of given degree and character.
2093
2094
INPUT:
2095
2096
- ``i`` (int) -- an integer, `0\le i\le k-2` where `k` is the weight.
2097
2098
- ``eps`` (character) -- a Dirichlet character
2099
2100
OUTPUT:
2101
2102
(modular symbol) The so-called 'twisted winding element':
2103
2104
.. math::
2105
2106
\sum_{a \in (\ZZ/m\ZZ)^\times} \varepsilon(a) * [ i, 0, a/m ].
2107
2108
.. note::
2109
2110
This will only work if the base ring of the modular symbol
2111
space contains the character values.
2112
2113
EXAMPLES::
2114
2115
sage: eps = DirichletGroup(5)[2]
2116
sage: K = eps.base_ring()
2117
sage: M = ModularSymbols(37,2,0,K)
2118
sage: M.twisted_winding_element(0,eps)
2119
2*(1,23) - 2*(1,32) + 2*(1,34)
2120
2121
"""
2122
2123
if not dirichlet.is_DirichletCharacter(eps):
2124
raise TypeError("eps must be a Dirichlet character.")
2125
if (i < 0) or (i > self.weight()-2):
2126
raise ValueError("i must be between 0 and k-2.")
2127
2128
m = eps.modulus()
2129
s = self(0)
2130
2131
for a in ([ x for x in range(1,m) if rings.gcd(x,m) == 1 ]):
2132
s += eps(a) * self.modular_symbol([i, Cusp(0), Cusp(a/m)])
2133
2134
return s
2135
2136
######################################################################
2137
# Z-module of integral modular symbols.
2138
#######################################################################
2139
def integral_structure(self, algorithm='default'):
2140
r"""
2141
Return the `\ZZ`-structure of this modular symbols
2142
space, generated by all integral modular symbols.
2143
2144
INPUT:
2145
2146
2147
- ``algorithm`` - string (default: 'default' - choose
2148
heuristically)
2149
2150
- ``'pari'`` - use pari for the HNF computation
2151
2152
- ``'padic'`` - use p-adic algorithm (only good for
2153
dense case)
2154
2155
2156
ALGORITHM: It suffices to consider lattice generated by the free
2157
generating symbols `X^iY^{k-2-i}.(u,v)` after quotienting
2158
out by the `S` (and `I`) relations, since the
2159
quotient by these relations is the same over any ring.
2160
2161
EXAMPLES: In weight 2 the rational basis is often integral.
2162
2163
::
2164
2165
sage: M = ModularSymbols(11,2)
2166
sage: M.integral_structure()
2167
Free module of degree 3 and rank 3 over Integer Ring
2168
Echelon basis matrix:
2169
[1 0 0]
2170
[0 1 0]
2171
[0 0 1]
2172
2173
This is rarely the case in higher weight::
2174
2175
sage: M = ModularSymbols(6,4)
2176
sage: M.integral_structure()
2177
Free module of degree 6 and rank 6 over Integer Ring
2178
Echelon basis matrix:
2179
[ 1 0 0 0 0 0]
2180
[ 0 1 0 0 0 0]
2181
[ 0 0 1/2 1/2 1/2 1/2]
2182
[ 0 0 0 1 0 0]
2183
[ 0 0 0 0 1 0]
2184
[ 0 0 0 0 0 1]
2185
2186
Here is an example involving `\Gamma_1(N)`.
2187
2188
::
2189
2190
sage: M = ModularSymbols(Gamma1(5),6)
2191
sage: M.integral_structure()
2192
Free module of degree 10 and rank 10 over Integer Ring
2193
Echelon basis matrix:
2194
[ 1 0 0 0 0 0 0 0 0 0]
2195
[ 0 1 0 0 0 0 0 0 0 0]
2196
[ 0 0 1/102 0 5/204 1/136 23/24 3/17 43/136 69/136]
2197
[ 0 0 0 1/48 0 1/48 23/24 1/6 1/8 17/24]
2198
[ 0 0 0 0 1/24 0 23/24 1/3 1/6 1/2]
2199
[ 0 0 0 0 0 1/24 23/24 1/3 11/24 5/24]
2200
[ 0 0 0 0 0 0 1 0 0 0]
2201
[ 0 0 0 0 0 0 0 1/2 0 1/2]
2202
[ 0 0 0 0 0 0 0 0 1/2 1/2]
2203
[ 0 0 0 0 0 0 0 0 0 1]
2204
"""
2205
if not self.base_ring() == rational_field.RationalField():
2206
raise NotImplementedError
2207
2208
try:
2209
return self.__integral_structure
2210
except AttributeError:
2211
pass
2212
2213
# The attribute _mod2term is set by self.compute_presentation().
2214
# It is a list of pairs (n, c), such that the ith element of the list
2215
# is equivalent to c times the n-th basis Manin symbol.
2216
G = set([i for i, _ in self._mod2term])
2217
2218
# Now G is a set of integer i such that these integers gives
2219
# indices of Manin symbols that together generate the integral
2220
# structure. We next obtain the corresponding list of elements
2221
# by passing to the quotient by the remaining relations
2222
# via the _manin_gens_to_basis attribute.
2223
2224
# Next we take each element of X, which gives a linear combination
2225
# of the basis of the underlying vector space of self, and compute
2226
# the Z-module they span.
2227
2228
G = list(G)
2229
G.sort()
2230
B = self._manin_gens_to_basis.matrix_from_rows(list(G)).dense_matrix()
2231
B, d = B._clear_denom()
2232
if algorithm == 'default':
2233
# pari is much better in the weight 2 case when the input
2234
# matrix is extremely sparse; the p-adic algorithm is
2235
# terrible in the sparse case.
2236
if self.weight() == 2:
2237
algorithm = 'pari'
2238
else:
2239
algorithm = 'padic'
2240
if algorithm == 'pari':
2241
B = B.echelon_form(algorithm='pari', include_zero_rows=False)
2242
elif algorithm == 'padic':
2243
B = B.echelon_form(algorithm='padic', include_zero_rows=False)
2244
else:
2245
raise ValueError("unknown algorithm '%s'"%algorithm)
2246
W = B.row_module()
2247
if d != 1:
2248
W = W.scale(1/d)
2249
self.__integral_structure = W
2250
assert W.rank() == self.rank(), "there is a bug in computing integral structure on modular symbols"
2251
return self.__integral_structure
2252
2253
######################################################################
2254
# Eigenvalues
2255
#######################################################################
2256
def compact_newform_eigenvalues(self, v, names='alpha'):
2257
r"""
2258
Return compact systems of eigenvalues for each Galois conjugacy
2259
class of cuspidal newforms in this ambient space.
2260
2261
INPUT:
2262
2263
2264
- ``v`` - list of positive integers
2265
2266
2267
OUTPUT:
2268
2269
2270
- ``list`` - of pairs (E, x), where E\*x is a vector
2271
with entries the eigenvalues `a_n` for
2272
`n \in v`.
2273
2274
2275
EXAMPLES::
2276
2277
sage: M = ModularSymbols(43,2,1)
2278
sage: X = M.compact_newform_eigenvalues(prime_range(10))
2279
sage: X[0][0] * X[0][1]
2280
(-2, -2, -4, 0)
2281
sage: X[1][0] * X[1][1]
2282
(alpha1, -alpha1, -alpha1 + 2, alpha1 - 2)
2283
2284
::
2285
2286
sage: M = ModularSymbols(DirichletGroup(24,QQ).1,2,sign=1)
2287
sage: M.compact_newform_eigenvalues(prime_range(10),'a')
2288
[([-1/2 -1/2]
2289
[ 1/2 -1/2]
2290
[ -1 1]
2291
[ -2 0], (1, -2*a0 - 1))]
2292
sage: a = M.compact_newform_eigenvalues([1..10],'a')[0]
2293
sage: a[0]*a[1]
2294
(1, a0, a0 + 1, -2*a0 - 2, -2*a0 - 2, -a0 - 2, -2, 2*a0 + 4, -1, 2*a0 + 4)
2295
sage: M = ModularSymbols(DirichletGroup(13).0^2,2,sign=1)
2296
sage: M.compact_newform_eigenvalues(prime_range(10),'a')
2297
[([ -zeta6 - 1]
2298
[ 2*zeta6 - 2]
2299
[-2*zeta6 + 1]
2300
[ 0], (1))]
2301
sage: a = M.compact_newform_eigenvalues([1..10],'a')[0]
2302
sage: a[0]*a[1]
2303
(1, -zeta6 - 1, 2*zeta6 - 2, zeta6, -2*zeta6 + 1, -2*zeta6 + 4, 0, 2*zeta6 - 1, -zeta6, 3*zeta6 - 3)
2304
"""
2305
if self.sign() == 0:
2306
raise ValueError("sign must be nonzero")
2307
v = list(v)
2308
2309
# Get decomposition of this space
2310
D = self.cuspidal_submodule().new_subspace().decomposition()
2311
for A in D:
2312
# since sign is zero and we're on the new cuspidal subspace
2313
# each factor is definitely simple.
2314
A._is_simple = True
2315
B = [A.dual_free_module().basis_matrix().transpose() for A in D]
2316
2317
# Normalize the names strings.
2318
names = ['%s%s'%(names,i) for i in range(len(B))]
2319
2320
# Find an integer i such that the i-th columns of the basis for the
2321
# dual modules corresponding to the factors in D are all nonzero.
2322
nz = None
2323
for i in range(self.dimension()):
2324
# Decide if this i works, i.e., ith row of every element of B is nonzero.
2325
bad = False
2326
for C in B:
2327
if C.row(i) == 0:
2328
# i is bad.
2329
bad = True
2330
continue
2331
if bad: continue
2332
# It turns out that i is not bad.
2333
nz = i
2334
break
2335
2336
if nz is not None:
2337
R = self.hecke_images(nz, v)
2338
return [(R*m, D[i].dual_eigenvector(names=names[i], lift=False, nz=nz)) for i, m in enumerate(B)]
2339
else:
2340
# No single i works, so we do something less uniform.
2341
ans = []
2342
cache = {}
2343
for i in range(len(D)):
2344
nz = D[i]._eigen_nonzero()
2345
if nz in cache:
2346
R = cache[nz]
2347
else:
2348
R = self.hecke_images(nz, v)
2349
cache[nz] = R
2350
ans.append((R*B[i], D[i].dual_eigenvector(names=names[i], lift=False, nz=nz)))
2351
return ans
2352
2353
2354
class ModularSymbolsAmbient_wtk_g0(ModularSymbolsAmbient):
2355
r"""
2356
Modular symbols for `\Gamma_0(N)` of integer weight
2357
`k > 2` over the field `F`.
2358
2359
For weight `2`, it is faster to use ``ModularSymbols_wt2_g0``.
2360
2361
INPUT:
2362
2363
2364
- ``N`` - int, the level
2365
2366
- ``k`` - integer weight = 2.
2367
2368
- ``sign`` - int, either -1, 0, or 1
2369
2370
- ``F`` - field
2371
2372
2373
EXAMPLES::
2374
2375
sage: ModularSymbols(1,12)
2376
Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field
2377
sage: ModularSymbols(1,12, sign=1).dimension()
2378
2
2379
sage: ModularSymbols(15,4, sign=-1).dimension()
2380
4
2381
sage: ModularSymbols(6,6).dimension()
2382
10
2383
sage: ModularSymbols(36,4).dimension()
2384
36
2385
"""
2386
def __init__(self, N, k, sign, F, custom_init=None):
2387
r"""
2388
Initialize a space of modular symbols of weight `k` for
2389
`\Gamma_0(N)`, over `\QQ`.
2390
2391
For weight `2`, it is faster to use
2392
``ModularSymbols_wt2_g0``.
2393
2394
INPUT:
2395
2396
2397
- ``N`` - int, the level
2398
2399
- ``k`` - integer weight = 2.
2400
2401
- ``sign`` - int, either -1, 0, or 1
2402
2403
- ``F`` - field
2404
2405
2406
EXAMPLES::
2407
2408
sage: ModularSymbols(1,12)
2409
Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field
2410
sage: ModularSymbols(1,12, sign=1).dimension()
2411
2
2412
sage: ModularSymbols(15,4, sign=-1).dimension()
2413
4
2414
sage: ModularSymbols(6,6).dimension()
2415
10
2416
sage: ModularSymbols(36,4).dimension()
2417
36
2418
"""
2419
N = int(N)
2420
k = int(k)
2421
sign = int(sign)
2422
if not sign in [-1,0,1]:
2423
raise TypeError("sign must be an int in [-1,0,1]")
2424
2425
ModularSymbolsAmbient.__init__(self, weight=k, group=arithgroup.Gamma0(N),
2426
sign=sign, base_ring=F, custom_init=custom_init)
2427
2428
2429
def _dimension_formula(self):
2430
r"""
2431
Return the dimension of this space using the formula.
2432
2433
EXAMPLES::
2434
2435
sage: M = ModularSymbols(37,6)
2436
sage: M.dimension()
2437
32
2438
sage: M._dimension_formula()
2439
32
2440
"""
2441
if self.base_ring().characteristic() == 0:
2442
N, k, sign = self.level(), self.weight(), self.sign()
2443
if sign != 0: return None
2444
if k%2 == 1:
2445
return 0
2446
elif k > 2:
2447
return 2*self.group().dimension_cusp_forms(k) + self.group().ncusps()
2448
else:
2449
return 2*self.group().dimension_cusp_forms(k) + self.group().ncusps() - 1
2450
else:
2451
raise NotImplementedError
2452
2453
def _repr_(self):
2454
r"""
2455
Return the string representation of this Modular Symbols space.
2456
2457
EXAMPLES::
2458
2459
sage: M = ModularSymbols(37,6)
2460
sage: M # indirect doctest
2461
Modular Symbols space of dimension 32 for Gamma_0(37) of weight 6 with sign 0 over Rational Field
2462
"""
2463
return ("Modular Symbols space of dimension %s for Gamma_0(%s) of weight %s with sign %s " + \
2464
"over %s")%(self.dimension(), self.level(),self.weight(), self.sign(),
2465
self.base_ring())
2466
2467
def _cuspidal_submodule_dimension_formula(self):
2468
r"""
2469
Return the dimension of the cuspidal subspace, using the formula.
2470
2471
EXAMPLES::
2472
2473
sage: M = ModularSymbols(37,4)
2474
sage: M.cuspidal_subspace().dimension()
2475
18
2476
sage: M._cuspidal_submodule_dimension_formula()
2477
18
2478
"""
2479
if self.base_ring().characteristic() == 0:
2480
N, k, sign = self.level(), self.weight(), self.sign()
2481
if sign == 0:
2482
m = 2
2483
else:
2484
m = 1
2485
return m * self.group().dimension_cusp_forms(k)
2486
else:
2487
raise NotImplementedError
2488
2489
2490
def _degeneracy_raising_matrix_1(self, M):
2491
r"""
2492
Return the matrix of the degeneracy map (with t = 1) to level
2493
`N`, where `N` is a multiple of the level.
2494
2495
INPUT:
2496
2497
- ``M`` -- A space of Gamma0 modular symbols of the same weight as
2498
self, with level an integer multiple of the level of self.
2499
2500
OUTPUT:
2501
2502
(matrix) The matrix of the degeneracy raising map to `M`.
2503
2504
EXAMPLES::
2505
2506
sage: M = ModularSymbols(37,4)
2507
sage: M._degeneracy_raising_matrix_1(ModularSymbols(74, 4))
2508
20 x 58 dense matrix over Rational Field
2509
sage: M.dimension()
2510
20
2511
sage: ModularSymbols(74,4).dimension()
2512
58
2513
"""
2514
level = int(M.level())
2515
N = self.level()
2516
2517
# 1. Find coset representatives H for Gamma_0(M.level()) \ Gamma_0(self.level())
2518
# (need to be careful in some small levels, cf. #13198)
2519
2520
if arithgroup.is_Gamma0(M.group()):
2521
H = arithgroup.degeneracy_coset_representatives_gamma0(level, N, 1)
2522
elif arithgroup.is_Gamma1(M.group()):
2523
H = arithgroup.degeneracy_coset_representatives_gamma1(level, N, 1)
2524
else:
2525
raise NotImplementedError("Degeneracy raising maps not implemented for GammaH levels")
2526
2527
# 2. The map is
2528
# [P,pi(g)] |--> sum_{h in H} [P, pi(h*g)]
2529
#
2530
MS = matrix_space.MatrixSpace(self.base_ring(), self.dimension(), M.dimension())
2531
if self.dimension() == 0 or M.dimension() == 0:
2532
return MS(0)
2533
rows = []
2534
B = self.manin_basis()
2535
syms = self.manin_symbols()
2536
k = self.weight()
2537
G = M2Z()
2538
H = [G(h) for h in H]
2539
for n in B:
2540
z = M(0)
2541
s = syms.manin_symbol(n)
2542
g = G(list(s.lift_to_sl2z(N)))
2543
i = s.i
2544
# We apply each matrix in H according to the above formula
2545
for h in H:
2546
hg = h*g
2547
z += M((i, hg[1,0], hg[1,1]))
2548
rows.append(z.element())
2549
2550
A = MS(rows)
2551
return A
2552
2553
2554
def _cuspidal_new_submodule_dimension_formula(self):
2555
r"""
2556
Return the dimension of the new cuspidal subspace, via the formula.
2557
2558
EXAMPLES::
2559
2560
sage: M = ModularSymbols(100,2)
2561
sage: M._cuspidal_new_submodule_dimension_formula()
2562
2
2563
sage: M.cuspidal_subspace().new_subspace().dimension()
2564
2
2565
"""
2566
if self.base_ring().characteristic() == 0:
2567
N, k, sign = self.level(), self.weight(), self.sign()
2568
if sign == 0:
2569
m = 2
2570
else:
2571
m = 1
2572
return m * self.group().dimension_new_cusp_forms(k)
2573
else:
2574
raise NotImplementedError
2575
2576
def boundary_space(self):
2577
r"""
2578
Return the space of boundary modular symbols for this space.
2579
2580
EXAMPLES::
2581
2582
sage: M = ModularSymbols(100,2)
2583
sage: M.boundary_space()
2584
Space of Boundary Modular Symbols for Congruence Subgroup Gamma0(100) of weight 2 and over Rational Field
2585
"""
2586
try:
2587
return self.__boundary_space
2588
except AttributeError:
2589
pass
2590
self.__boundary_space = boundary.BoundarySpace_wtk_g0(
2591
self.level(), self.weight(), self.sign(), self.base_ring())
2592
return self.__boundary_space
2593
2594
def manin_symbols(self):
2595
r"""
2596
Return the Manin symbol list of this modular symbol space.
2597
2598
EXAMPLES::
2599
2600
sage: M = ModularSymbols(100,4)
2601
sage: M.manin_symbols()
2602
Manin Symbol List of weight 4 for Gamma0(100)
2603
sage: len(M.manin_symbols())
2604
540
2605
"""
2606
try:
2607
return self.__manin_symbols
2608
except AttributeError:
2609
self.__manin_symbols = manin_symbols.ManinSymbolList_gamma0(
2610
level=self.level(), weight=self.weight())
2611
return self.__manin_symbols
2612
2613
def modular_symbols_of_level(self, N):
2614
r"""
2615
Returns a space of modular symbols with the same parameters as
2616
this space except with level `N`.
2617
2618
INPUT:
2619
2620
- ``N`` (int) -- a positive integer.
2621
2622
OUTPUT:
2623
2624
(Modular Symbol space) A space of modular symbols with the
2625
same defining properties (weight, sign, etc.) as this space
2626
except with level `N`.
2627
2628
For example, if self is the space of modular symbols of weight `2`
2629
for `\Gamma_0(22)`, and level is `11`, then this function returns
2630
the modular symbol space of weight `2` for `\Gamma_0(11)`.
2631
2632
EXAMPLES::
2633
2634
sage: M = ModularSymbols(11)
2635
sage: M.modular_symbols_of_level(22)
2636
Modular Symbols space of dimension 7 for Gamma_0(22) of weight 2 with sign 0 over Rational Field
2637
sage: M = ModularSymbols(Gamma1(6))
2638
sage: M.modular_symbols_of_level(12)
2639
Modular Symbols space of dimension 9 for Gamma_1(12) of weight 2 with sign 0 and over Rational Field
2640
"""
2641
return modsym.ModularSymbols(arithgroup.Gamma0(rings.Integer(N)),
2642
self.weight(), sign=self.sign(),
2643
base_ring=self.base_ring())
2644
2645
2646
def _hecke_images(self, i, v):
2647
"""
2648
Return matrix whose rows are the images of the `i`-th
2649
standard basis vector under the Hecke operators `T_p` for
2650
all integers in `v`.
2651
2652
INPUT:
2653
2654
2655
- ``i`` - nonnegative integer
2656
2657
- ``v`` - a list of positive integer
2658
2659
2660
OUTPUT:
2661
2662
2663
- ``matrix`` - whose rows are the Hecke images
2664
2665
2666
EXAMPLES::
2667
2668
sage: M = ModularSymbols(11,4,1)
2669
sage: M._hecke_images(0,[1,2,3,4])
2670
[ 1 0 0 0]
2671
[ 9 0 1 -1]
2672
[28 2 -1 -1]
2673
[73 2 5 -7]
2674
sage: M.T(1)(M.0).element()
2675
(1, 0, 0, 0)
2676
sage: M.T(2)(M.0).element()
2677
(9, 0, 1, -1)
2678
sage: M.T(3)(M.0).element()
2679
(28, 2, -1, -1)
2680
sage: M.T(4)(M.0).element()
2681
(73, 2, 5, -7)
2682
sage: M = ModularSymbols(12,4)
2683
sage: M._hecke_images(0,[1,2,3,4])
2684
[ 1 0 0 0 0 0 0 0 0 0 0 0]
2685
[ 8 1 -1 -2 2 2 -3 1 -2 3 -1 0]
2686
[ 27 4 -4 -8 8 10 -14 4 -9 14 -5 0]
2687
[ 64 10 -10 -20 20 26 -36 10 -24 38 -14 0]
2688
sage: M.T(1)(M.0).element()
2689
(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
2690
sage: M.T(2)(M.0).element()
2691
(8, 1, -1, -2, 2, 2, -3, 1, -2, 3, -1, 0)
2692
sage: M.T(3)(M.0).element()
2693
(27, 4, -4, -8, 8, 10, -14, 4, -9, 14, -5, 0)
2694
sage: M.T(4)(M.0).element()
2695
(64, 10, -10, -20, 20, 26, -36, 10, -24, 38, -14, 0)
2696
"""
2697
# Find basis vector for ambient space such that it is not in
2698
# the kernel of the dual space corresponding to self.
2699
c = self.manin_generators()[self.manin_basis()[i]]
2700
N = self.level()
2701
return heilbronn.hecke_images_gamma0_weight_k(c.u,c.v, c.i, N, self.weight(),
2702
v, self.manin_gens_to_basis())
2703
2704
class ModularSymbolsAmbient_wt2_g0(ModularSymbolsAmbient_wtk_g0):
2705
r"""
2706
Modular symbols for `\Gamma_0(N)` of integer weight `2` over the field
2707
`F`.
2708
2709
INPUT:
2710
2711
- ``N`` - int, the level
2712
2713
- ``sign`` - int, either -1, 0, or 1
2714
2715
2716
OUTPUT:
2717
2718
The space of modular symbols of weight `2`, trivial character, level
2719
`N` and given sign.
2720
2721
EXAMPLES::
2722
2723
sage: ModularSymbols(Gamma0(12),2)
2724
Modular Symbols space of dimension 5 for Gamma_0(12) of weight 2 with sign 0 over Rational Field
2725
"""
2726
def __init__(self, N, sign, F, custom_init=None):
2727
"""
2728
Initialize a space of modular symbols. INPUT:
2729
2730
INPUT:
2731
2732
- ``N`` - int, the level
2733
2734
- ``sign`` - int, either -1, 0, or 1
2735
2736
2737
OUTPUT:
2738
2739
The space of modular symbols of weight 2, trivial character,
2740
level N and given sign.
2741
2742
EXAMPLES::
2743
2744
sage: M = ModularSymbols(Gamma0(12),2)
2745
"""
2746
ModularSymbolsAmbient_wtk_g0.__init__(self,
2747
N=N, k=2, sign=sign, F=F,
2748
custom_init=custom_init)
2749
2750
def _dimension_formula(self):
2751
r"""
2752
Return the dimension of this space using the formula.
2753
2754
EXAMPLES::
2755
2756
sage: M = ModularSymbols(37,6)
2757
sage: M.dimension()
2758
32
2759
sage: M._dimension_formula()
2760
32
2761
"""
2762
if self.base_ring().characteristic() == 0:
2763
N, sign = self.level(), self.sign()
2764
if sign != 0: return None
2765
return 2*self.group().dimension_cusp_forms(2) + self.group().ncusps() - 1
2766
else:
2767
raise NotImplementedError
2768
2769
def _cuspidal_submodule_dimension_formula(self):
2770
r"""
2771
Return the dimension of the cuspidal subspace, using the formula.
2772
2773
EXAMPLES::
2774
2775
sage: M = ModularSymbols(37,4)
2776
sage: M.cuspidal_subspace().dimension()
2777
18
2778
sage: M._cuspidal_submodule_dimension_formula()
2779
18
2780
"""
2781
if self.base_ring().characteristic() == 0:
2782
if self.sign() == 0:
2783
m = 2
2784
else:
2785
m = 1
2786
return m * self.group().dimension_cusp_forms(2)
2787
else:
2788
raise NotImplementedError
2789
2790
def _cuspidal_new_submodule_dimension_formula(self):
2791
r"""
2792
Return the dimension of the new cuspidal subspace, via the formula.
2793
2794
EXAMPLES:
2795
2796
sage: M = ModularSymbols(100,2)
2797
sage: M._cuspidal_new_submodule_dimension_formula()
2798
2
2799
sage: M.cuspidal_subspace().new_subspace().dimension()
2800
2
2801
"""
2802
if self.base_ring().characteristic() == 0:
2803
if self.sign() == 0:
2804
m = 2
2805
else:
2806
m = 1
2807
return m * self.group().dimension_new_cusp_forms(2)
2808
else:
2809
raise NotImplementedError
2810
2811
2812
def _compute_hecke_matrix_prime(self, p, rows=None):
2813
r"""
2814
Compute and return the matrix of the `p`-th Hecke operator.
2815
2816
EXAMPLES::
2817
2818
sage: m = ModularSymbols(37,2)
2819
sage: m._compute_hecke_matrix_prime(2).charpoly('x')
2820
x^5 + x^4 - 8*x^3 - 12*x^2
2821
"""
2822
# note -- p doesn't have to be prime.
2823
if isinstance(rows, list):
2824
rows = tuple(rows)
2825
try:
2826
return self._hecke_matrices[(p,rows)]
2827
except AttributeError:
2828
self._hecke_matrices = {}
2829
except KeyError:
2830
pass
2831
tm = misc.verbose("Computing Hecke operator T_%s"%p)
2832
2833
H = heilbronn.HeilbronnCremona(p)
2834
##H = heilbronn.HeilbronnMerel(p)
2835
B = self.manin_basis()
2836
if not rows is None:
2837
B = [B[i] for i in rows]
2838
2839
cols = []
2840
N = self.level()
2841
P1 = self.p1list()
2842
mod2term = self._mod2term
2843
R = self.manin_gens_to_basis()
2844
W = R.new_matrix(nrows=len(B), ncols = R.nrows()) # the 0 with given number of rows and cols.
2845
j = 0
2846
tm = misc.verbose("Matrix non-reduced", tm)
2847
for i in B:
2848
# The following step is where most of the time is spent.
2849
c,d = P1[i]
2850
v = H.apply(c,d, N)
2851
2852
# v is now a list of pairs ((c,d),m), where m is the
2853
# number of times that (c,d) appears in the image of x
2854
# under the matrices in H. Also, the pairs (c,d) are
2855
# normalized.
2856
# Let ind(c,d) denote the index of the normalized pair
2857
# (c,d) in the fixed ordered list of elements of
2858
# P1(Z/NZ). Then the list of pairs (ind(c,d), m)
2859
# obtained from the above list defines a sparse vector
2860
# s, and the image of x under T_p is the product
2861
# of s with the matrix R defined above.
2862
for z, m in v:
2863
k = P1.index_of_normalized_pair(z[0],z[1])
2864
if k != -1:
2865
f, s = mod2term[k]
2866
if s != 0:
2867
W[j,f] = W[j,f] + s*m
2868
j += 1
2869
tm = misc.verbose("done making non-reduced matrix",tm)
2870
misc.verbose("start matrix-matrix (%s x %s) times (%s x %s) multiply to get Tp"%(W.nrows(), W.ncols(),
2871
R.nrows(), R.ncols()))
2872
if hasattr(W, '_matrix_times_matrix_dense'):
2873
Tp = W._matrix_times_matrix_dense(R)
2874
misc.verbose("done matrix multiply and computing Hecke operator",tm)
2875
else:
2876
Tp = W * R
2877
tm = misc.verbose("done multiplying",tm)
2878
Tp = Tp.dense_matrix()
2879
misc.verbose("done making hecke operator dense",tm)
2880
if rows is None:
2881
self._hecke_matrices[(p,rows)] = Tp
2882
return Tp
2883
2884
def boundary_space(self):
2885
r"""
2886
Return the space of boundary modular symbols for this space.
2887
2888
EXAMPLES::
2889
2890
sage: M = ModularSymbols(100,2)
2891
sage: M.boundary_space()
2892
Space of Boundary Modular Symbols for Congruence Subgroup Gamma0(100) of weight 2 and over Rational Field
2893
"""
2894
try:
2895
return self.__boundary_space
2896
except AttributeError:
2897
pass
2898
self.__boundary_space = boundary.BoundarySpace_wtk_g0(
2899
self.level(), self.weight(), self.sign(), self.base_ring())
2900
return self.__boundary_space
2901
2902
def _hecke_image_of_ith_basis_vector(self, n, i):
2903
"""
2904
Return `T_n(e_i)`, where `e_i` is the
2905
`i`th basis vector of this ambient space.
2906
2907
INPUT:
2908
2909
2910
- ``n`` - an integer which should be prime.
2911
2912
2913
OUTPUT:
2914
2915
2916
- ``modular symbol`` - element of this ambient space
2917
2918
2919
EXAMPLES::
2920
2921
sage: M = ModularSymbols(43,2,1)
2922
sage: M._hecke_image_of_ith_basis_vector(2, 0)
2923
3*(1,0) - 2*(1,33)
2924
sage: M.hecke_operator(2)(M.0)
2925
3*(1,0) - 2*(1,33)
2926
sage: M._hecke_image_of_ith_basis_vector(6, 1)
2927
-2*(1,33)
2928
sage: M.hecke_operator(6)(M.1)
2929
-2*(1,33)
2930
"""
2931
c = self.manin_generators()[self.manin_basis()[i]]
2932
N = self.level()
2933
I = heilbronn.hecke_images_gamma0_weight2(c.u,c.v,N,[n], self.manin_gens_to_basis())
2934
return self(I[0])
2935
2936
def _hecke_images(self, i, v):
2937
"""
2938
Return images of the `i`-th standard basis vector under the
2939
Hecke operators `T_p` for all integers in `v`.
2940
2941
INPUT:
2942
2943
2944
- ``i`` - nonnegative integer
2945
2946
- ``v`` - a list of positive integer
2947
2948
2949
OUTPUT:
2950
2951
2952
- ``matrix`` - whose rows are the Hecke images
2953
2954
2955
EXAMPLES::
2956
2957
sage: M = ModularSymbols(46,2,-1)
2958
sage: M._hecke_images(1,[3,4,5,6])
2959
[ 0 1 -2 2 0]
2960
[ 2 -3 0 0 1]
2961
[ 0 -2 2 -2 0]
2962
[-5 3 -1 1 0]
2963
sage: v = M.basis()[1]
2964
sage: M.T(3)(v).element()
2965
(0, 1, -2, 2, 0)
2966
sage: M.T(4)(v).element()
2967
(2, -3, 0, 0, 1)
2968
sage: M.T(5)(v).element()
2969
(0, -2, 2, -2, 0)
2970
sage: M.T(6)(v).element()
2971
(-5, 3, -1, 1, 0)
2972
"""
2973
# Find basis vector for ambient space such that it is not in
2974
# the kernel of the dual space corresponding to self.
2975
c = self.manin_generators()[self.manin_basis()[i]]
2976
N = self.level()
2977
return heilbronn.hecke_images_gamma0_weight2(c.u,c.v,N, v, self.manin_gens_to_basis())
2978
2979
2980
class ModularSymbolsAmbient_wtk_g1(ModularSymbolsAmbient):
2981
r"""
2982
INPUT:
2983
2984
2985
- ``level`` - int, the level
2986
2987
- ``weight`` - int, the weight = 2
2988
2989
- ``sign`` - int, either -1, 0, or 1
2990
2991
- ``F`` - field
2992
2993
2994
EXAMPLES::
2995
2996
sage: ModularSymbols(Gamma1(17),2)
2997
Modular Symbols space of dimension 25 for Gamma_1(17) of weight 2 with sign 0 and over Rational Field
2998
sage: [ModularSymbols(Gamma1(7),k).dimension() for k in [2,3,4,5]]
2999
[5, 8, 12, 16]
3000
3001
::
3002
3003
sage: ModularSymbols(Gamma1(7),3)
3004
Modular Symbols space of dimension 8 for Gamma_1(7) of weight 3 with sign 0 and over Rational Field
3005
"""
3006
3007
def __init__(self, level, weight, sign, F, custom_init=None):
3008
r"""
3009
Initialize a space of modular symbols for Gamma1(N).
3010
3011
INPUT:
3012
3013
3014
- ``level`` - int, the level
3015
3016
- ``weight`` - int, the weight = 2
3017
3018
- ``sign`` - int, either -1, 0, or 1
3019
3020
- ``F`` - field
3021
3022
3023
EXAMPLES::
3024
3025
sage: ModularSymbols(Gamma1(17),2)
3026
Modular Symbols space of dimension 25 for Gamma_1(17) of weight 2 with sign 0 and over Rational Field
3027
sage: [ModularSymbols(Gamma1(7),k).dimension() for k in [2,3,4,5]]
3028
[5, 8, 12, 16]
3029
3030
::
3031
3032
sage: M = ModularSymbols(Gamma1(7),3)
3033
"""
3034
ModularSymbolsAmbient.__init__(self,
3035
weight=weight,
3036
group=arithgroup.Gamma1(level),
3037
sign=sign,
3038
base_ring=F,
3039
custom_init=custom_init)
3040
3041
3042
def _dimension_formula(self):
3043
r"""
3044
Return the dimension of this space using the formula.
3045
3046
EXAMPLES::
3047
3048
sage: M = ModularSymbols(Gamma1(7),6)
3049
sage: M.dimension()
3050
20
3051
sage: M._dimension_formula()
3052
20
3053
"""
3054
if self.base_ring().characteristic() != 0:
3055
raise NotImplementedError
3056
level, weight, sign = self.level(), self.weight(), self.sign()
3057
if sign != 0: return None
3058
d = 2*self.group().dimension_cusp_forms(weight) + self.group().ncusps()
3059
if level == 1 and weight%2 == 1:
3060
return 0
3061
if weight == 2:
3062
return d - 1
3063
if weight % 2 == 0:
3064
return d
3065
3066
# TODO: I don't know a formula for dim ModSym_k(Gamma_1(N)) for odd k!!!
3067
3068
return None
3069
3070
def _repr_(self):
3071
r"""
3072
Return a string representation of this space.
3073
3074
EXAMPLES::
3075
3076
sage: M = ModularSymbols(Gamma1(7),3)
3077
sage: M # indirect doctest
3078
Modular Symbols space of dimension 8 for Gamma_1(7) of weight 3 with sign 0 and over Rational Field
3079
"""
3080
return ("Modular Symbols space of dimension %s for Gamma_1(%s) of weight %s with sign %s " + \
3081
"and over %s")%(self.dimension(), self.level(),self.weight(),
3082
self.sign(), self.base_ring())
3083
3084
def _cuspidal_submodule_dimension_formula(self):
3085
r"""
3086
Return the dimension of the cuspidal subspace, using the formula.
3087
3088
EXAMPLES::
3089
3090
sage: M = ModularSymbols(Gamma1(11),4)
3091
sage: M.cuspidal_subspace().dimension()
3092
20
3093
sage: M._cuspidal_submodule_dimension_formula()
3094
20
3095
"""
3096
if self.sign() == 0:
3097
m = 2
3098
else:
3099
m = 1
3100
return m * self.group().dimension_cusp_forms(self.weight())
3101
3102
def _cuspidal_new_submodule_dimension_formula(self):
3103
r"""
3104
Return the dimension of the new cuspidal subspace, via the formula.
3105
3106
EXAMPLES:
3107
3108
sage: M = ModularSymbols(Gamma1(22),2)
3109
sage: M._cuspidal_new_submodule_dimension_formula()
3110
8
3111
sage: M.cuspidal_subspace().new_subspace().dimension()
3112
8
3113
"""
3114
if self.sign() == 0:
3115
m = 2
3116
else:
3117
m = 1
3118
return m * self.group().dimension_new_cusp_forms(self.weight())
3119
3120
3121
def _compute_hecke_matrix_prime_power(self, p, r):
3122
r"""
3123
Compute and return the matrix of the Hecke operator `T(p^r)`.
3124
3125
EXAMPLES::
3126
3127
sage: m = ModularSymbols(Gamma1(11),2)
3128
sage: m._compute_hecke_matrix_prime_power(3,4).charpoly('x')
3129
x^11 - 291*x^10 + 30555*x^9 - 1636145*x^8 + 59637480*x^7 + 1983040928*x^6 - 401988683888*x^5 - 14142158875680*x^4 + 3243232720819520*x^3 - 103658398669404480*x^2 + 197645665452381696*x - 97215957397309696
3130
"""
3131
return self._compute_hecke_matrix_prime(p**r)
3132
3133
def _degeneracy_raising_matrix_1(self, M):
3134
r"""
3135
Return the matrix of the degeneracy raising map to `M`.
3136
3137
INPUT:
3138
3139
- ``M`` -- an ambient space of Gamma1 modular symbols, of level a
3140
multiple of the level of self
3141
3142
OUTPUT:
3143
3144
(matrix) The matrix of the degeneracy raising matrix to the higher level.
3145
3146
EXAMPLES::
3147
3148
sage: M = ModularSymbols(Gamma1(7),3)
3149
sage: N = ModularSymbols(Gamma1(21), 3)
3150
sage: M._degeneracy_raising_matrix_1(N)
3151
8 x 64 dense matrix over Rational Field
3152
sage: M.dimension()
3153
8
3154
sage: N.dimension()
3155
64
3156
"""
3157
level = int(M.level())
3158
N = self.level()
3159
3160
# 1. Find coset representatives H for Gamma_1(M.level()) \ Gamma_1(self.level())
3161
H = arithgroup.degeneracy_coset_representatives_gamma1(M.level(), N, 1)
3162
# 2. The map is
3163
# [P,pi(g)] |--> sum_{h in H} [P, pi(h*g)]
3164
#
3165
MS = matrix_space.MatrixSpace(self.base_ring(), self.dimension(), M.dimension())
3166
if self.dimension() == 0 or M.dimension() == 0:
3167
return MS(0)
3168
rows = []
3169
B = self.manin_basis()
3170
syms = self.manin_symbols()
3171
k = self.weight()
3172
G = matrix_space.MatrixSpace(integer_ring.IntegerRing(),2)
3173
H = [G(h) for h in H]
3174
for n in B:
3175
z = M(0)
3176
s = syms.manin_symbol(n)
3177
g = G(list(s.lift_to_sl2z(N)))
3178
i = s.i
3179
# We apply each matrix in H according to the above formula
3180
for h in H:
3181
hg = h*g
3182
z += M((i, hg[1,0], hg[1,1]))
3183
rows.append(z.element())
3184
3185
A = MS(rows)
3186
return A
3187
3188
def boundary_space(self):
3189
r"""
3190
Return the space of boundary modular symbols for this space.
3191
3192
EXAMPLES::
3193
3194
sage: M = ModularSymbols(100,2)
3195
sage: M.boundary_space()
3196
Space of Boundary Modular Symbols for Congruence Subgroup Gamma0(100) of weight 2 and over Rational Field
3197
"""
3198
try:
3199
return self.__boundary_space
3200
except AttributeError:
3201
pass
3202
self.__boundary_space = boundary.BoundarySpace_wtk_g1(
3203
self.level(), self.weight(), self.sign(), self.base_ring())
3204
return self.__boundary_space
3205
3206
def manin_symbols(self):
3207
r"""
3208
Return the Manin symbol list of this modular symbol space.
3209
3210
EXAMPLES::
3211
3212
sage: M = ModularSymbols(Gamma1(30),4)
3213
sage: M.manin_symbols()
3214
Manin Symbol List of weight 4 for Gamma1(30)
3215
sage: len(M.manin_symbols())
3216
1728
3217
"""
3218
try:
3219
return self.__manin_symbols
3220
except AttributeError:
3221
self.__manin_symbols = manin_symbols.ManinSymbolList_gamma1(
3222
level=self.level(), weight=self.weight())
3223
return self.__manin_symbols
3224
3225
3226
def modular_symbols_of_level(self, N):
3227
r"""
3228
Returns a space of modular symbols with the same parameters as
3229
this space except with level `N`.
3230
3231
INPUT:
3232
3233
- ``N`` (int) -- a positive integer.
3234
3235
OUTPUT:
3236
3237
(Modular Symbol space) A space of modular symbols with the
3238
same defining properties (weight, sign, etc.) as this space
3239
except with level `N`.
3240
3241
For example, if self is the space of modular symbols of weight `2`
3242
for `\Gamma_0(22)`, and level is `11`, then this function returns
3243
the modular symbol space of weight `2` for `\Gamma_0(11)`.
3244
3245
EXAMPLES::
3246
3247
sage: M = ModularSymbols(Gamma1(30),4); M
3248
Modular Symbols space of dimension 144 for Gamma_1(30) of weight 4 with sign 0 and over Rational Field
3249
sage: M.modular_symbols_of_level(22)
3250
Modular Symbols space of dimension 90 for Gamma_1(22) of weight 4 with sign 0 and over Rational Field
3251
"""
3252
return modsym.ModularSymbols(arithgroup.Gamma1(N), self.weight(),self.sign(), self.base_ring())
3253
3254
class ModularSymbolsAmbient_wtk_gamma_h(ModularSymbolsAmbient):
3255
def __init__(self, group, weight, sign, F, custom_init=None):
3256
r"""
3257
Initialize a space of modular symbols for `\Gamma_H(N)`.
3258
3259
INPUT:
3260
3261
3262
- ``group`` - a congruence subgroup
3263
`\Gamma_H(N)`.
3264
3265
- ``weight`` - int, the weight = 2
3266
3267
- ``sign`` - int, either -1, 0, or 1
3268
3269
- ``F`` - field
3270
3271
3272
EXAMPLES::
3273
3274
sage: ModularSymbols(GammaH(15,[4]),2)
3275
Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(15) with H generated by [4] of weight 2 with sign 0 and over Rational Field
3276
"""
3277
ModularSymbolsAmbient.__init__(self,
3278
weight=weight, group=group,
3279
sign=sign, base_ring=F, custom_init=custom_init)
3280
3281
def _dimension_formula(self):
3282
r"""
3283
Return None: we have no dimension formulas for `\Gamma_H(N)` spaces.
3284
3285
EXAMPLES::
3286
3287
sage: M = ModularSymbols(GammaH(15,[4]),2)
3288
sage: M.dimension()
3289
9
3290
sage: M._dimension_formula()
3291
"""
3292
return None
3293
3294
def _repr_(self):
3295
r"""
3296
Return a string representation of this space.
3297
3298
EXAMPLES::
3299
3300
sage: M = ModularSymbols(GammaH(15,[4]),2)
3301
sage: M # indirect doctest
3302
Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(15) with H generated by [4] of weight 2 with sign 0 and over Rational Field
3303
"""
3304
return ("Modular Symbols space of dimension %s for %s of weight %s with sign %s " + \
3305
"and over %s")%(self.dimension(), self.group(),self.weight(),
3306
self.sign(), self.base_ring())
3307
3308
def _cuspidal_submodule_dimension_formula(self):
3309
r"""
3310
Return None: we have no dimension formulas for `\Gamma_H(N)` spaces.
3311
3312
EXAMPLES::
3313
3314
sage: ModularSymbols(GammaH(15,[4]),2)._cuspidal_submodule_dimension_formula() is None
3315
True
3316
3317
"""
3318
return None
3319
3320
def _cuspidal_new_submodule_dimension_formula(self):
3321
r"""
3322
Return None: we have no dimension formulas for `\Gamma_H(N)` spaces.
3323
3324
EXAMPLES::
3325
3326
sage: ModularSymbols(GammaH(15,[4]),2)._cuspidal_new_submodule_dimension_formula() is None
3327
True
3328
"""
3329
return None
3330
3331
def _compute_hecke_matrix_prime_power(self, p, r):
3332
r"""
3333
Return matrix of a prime-power Hecke operator.
3334
3335
EXAMPLES::
3336
3337
sage: M = ModularSymbols(GammaH(15,[4]),2)
3338
sage: M._compute_hecke_matrix_prime_power(2, 3)
3339
[10 0 5 0 1 0 0 4 0]
3340
[ 0 10 0 0 -4 -5 0 -1 6]
3341
[ 5 0 10 0 -4 0 0 -1 0]
3342
[ 0 0 0 5 -7 0 10 -3 4]
3343
[ 0 0 0 0 -1 0 0 -4 0]
3344
[ 0 -5 0 0 -1 10 0 -4 -6]
3345
[ 0 0 0 10 -3 0 5 -7 -4]
3346
[ 0 0 0 0 -4 0 0 -1 0]
3347
[ 0 0 0 0 0 0 0 0 3]
3348
sage: M.hecke_matrix(7)^2 == M.hecke_matrix(49) + 7 * M.diamond_bracket_operator(7).matrix() # indirect doctest
3349
True
3350
"""
3351
return self._compute_hecke_matrix_prime(p**r)
3352
3353
def _degeneracy_raising_matrix_1(self, level):
3354
r"""
3355
Return matrix of a degeneracy raising map.
3356
3357
EXAMPLES::
3358
3359
sage: ModularSymbols(GammaH(15,[4]),2)._degeneracy_raising_matrix_1(ModularSymbols(GammaH(30, [19]), 2))
3360
Traceback (most recent call last):
3361
...
3362
NotImplementedError
3363
"""
3364
raise NotImplementedError
3365
3366
def boundary_space(self):
3367
r"""
3368
Return the space of boundary modular symbols for this space.
3369
3370
EXAMPLES::
3371
3372
sage: M = ModularSymbols(GammaH(15,[4]),2)
3373
sage: M.boundary_space()
3374
Boundary Modular Symbols space for Congruence Subgroup Gamma_H(15) with H generated by [4] of weight 2 over Rational Field
3375
"""
3376
try:
3377
return self.__boundary_space
3378
except AttributeError:
3379
pass
3380
self.__boundary_space = boundary.BoundarySpace_wtk_gamma_h(
3381
self.group(), self.weight(), self.sign(), self.base_ring())
3382
return self.__boundary_space
3383
3384
def manin_symbols(self):
3385
r"""
3386
Return the Manin symbol list of this modular symbol space.
3387
3388
EXAMPLES::
3389
3390
sage: M = ModularSymbols(GammaH(15,[4]),2)
3391
sage: M.manin_symbols()
3392
Manin Symbol List of weight 2 for Congruence Subgroup Gamma_H(15) with H generated by [4]
3393
sage: len(M.manin_symbols())
3394
96
3395
"""
3396
try:
3397
return self.__manin_symbols
3398
except AttributeError:
3399
self.__manin_symbols = manin_symbols.ManinSymbolList_gamma_h(
3400
group=self.group(), weight=self.weight())
3401
return self.__manin_symbols
3402
3403
def modular_symbols_of_level(self, N):
3404
r"""
3405
Returns a space of modular symbols with the same parameters as
3406
this space except with level `N`, which should be either a divisor or a
3407
multiple of the level of self.
3408
3409
TESTS::
3410
3411
sage: M = ModularSymbols(GammaH(15,[7]),6)
3412
sage: M.modular_symbols_of_level(5)
3413
Modular Symbols space of dimension 4 for Gamma_0(5) of weight 6 with sign 0 over Rational Field
3414
sage: M.modular_symbols_of_level(30)
3415
Traceback (most recent call last):
3416
...
3417
ValueError: N (=30) should be a factor of the level of this space (=15)
3418
sage: M.modular_symbols_of_level(73)
3419
Traceback (most recent call last):
3420
...
3421
ValueError: N (=73) should be a factor of the level of this space (=15)
3422
"""
3423
if self.level() % N == 0:
3424
return modsym.ModularSymbols(self.group().restrict(N), self.weight(), self.sign(), self.base_ring())
3425
# We deliberately don't allow N to be a multiple of the level here,
3426
# because there are many possibilities for what H could be at the
3427
# higher level (and we don't implement the degeneracy raising maps
3428
# anyway)
3429
else:
3430
raise ValueError("N (=%s) should be a factor of the level\
3431
of this space (=%s)" % (N, self.level()))
3432
3433
3434
class ModularSymbolsAmbient_wtk_eps(ModularSymbolsAmbient):
3435
def __init__(self, eps, weight, sign, base_ring, custom_init=None):
3436
"""
3437
Space of modular symbols with given weight, character, base ring and
3438
sign.
3439
3440
INPUT:
3441
3442
3443
- ``eps`` - dirichlet.DirichletCharacter, the
3444
"Nebentypus" character.
3445
3446
- ``weight`` - int, the weight = 2
3447
3448
- ``sign`` - int, either -1, 0, or 1
3449
3450
- ``base_ring`` - the base ring. It must be possible to change the ring
3451
of the character to this base ring (not always canonically).
3452
3453
3454
EXAMPLES::
3455
3456
sage: eps = DirichletGroup(4).gen(0)
3457
sage: eps.order()
3458
2
3459
sage: ModularSymbols(eps, 2)
3460
Modular Symbols space of dimension 0 and level 4, weight 2, character [-1], sign 0, over Rational Field
3461
sage: ModularSymbols(eps, 3)
3462
Modular Symbols space of dimension 2 and level 4, weight 3, character [-1], sign 0, over Rational Field
3463
3464
We next create a space with character of order bigger than 2.
3465
3466
::
3467
3468
sage: eps = DirichletGroup(5).gen(0)
3469
sage: eps # has order 4
3470
Dirichlet character modulo 5 of conductor 5 mapping 2 |--> zeta4
3471
sage: ModularSymbols(eps, 2).dimension()
3472
0
3473
sage: ModularSymbols(eps, 3).dimension()
3474
2
3475
3476
Here is another example::
3477
3478
sage: G, e = DirichletGroup(5).objgen()
3479
sage: M = ModularSymbols(e,3)
3480
sage: loads(M.dumps()) == M
3481
True
3482
"""
3483
level = eps.modulus()
3484
ModularSymbolsAmbient.__init__(self,
3485
weight = weight,
3486
group = arithgroup.Gamma1(level),
3487
sign = sign,
3488
base_ring = base_ring,
3489
character = eps.change_ring(base_ring),
3490
custom_init=custom_init)
3491
3492
def _repr_(self):
3493
r"""
3494
Return a string representation of this space.
3495
3496
EXAMPLES::
3497
3498
sage: G, e = DirichletGroup(5).objgen()
3499
sage: M = ModularSymbols(e,3)
3500
sage: M # indirect doctest
3501
Modular Symbols space of dimension 2 and level 5, weight 3, character [zeta4], sign 0, over Cyclotomic Field of order 4 and degree 2
3502
"""
3503
return ("Modular Symbols space of dimension %s and level %s, weight %s, character %s, sign %s, " + \
3504
"over %s")%(self.dimension(), self.level(), self.weight(),
3505
self.character()._repr_short_(), self.sign(), self.base_ring())
3506
3507
3508
def _cuspidal_submodule_dimension_formula(self):
3509
r"""
3510
Return the dimension for the cuspidal subspace of this space, given by the formula.
3511
3512
EXAMPLES::
3513
3514
sage: G, e = DirichletGroup(50).objgen()
3515
sage: M = ModularSymbols(e^2,2)
3516
sage: M.dimension()
3517
16
3518
sage: M._cuspidal_submodule_dimension_formula()
3519
12
3520
"""
3521
if self.base_ring().characteristic() != 0:
3522
raise NotImplementedError
3523
if self.sign() == 0:
3524
m = 2
3525
else:
3526
m = 1
3527
return m * self.group().dimension_cusp_forms(self.weight(), eps=self.character())
3528
3529
def _cuspidal_new_submodule_dimension_formula(self):
3530
r"""
3531
Return the dimension for the new cuspidal subspace of this space, given by the formula.
3532
3533
EXAMPLES::
3534
3535
sage: G, e = DirichletGroup(50).objgen()
3536
sage: M = ModularSymbols(e,3)
3537
sage: M.dimension()
3538
30
3539
sage: M._cuspidal_new_submodule_dimension_formula()
3540
10
3541
"""
3542
if self.base_ring().characteristic() != 0:
3543
raise NotImplementedError
3544
if self.sign() == 0:
3545
m = 2
3546
else:
3547
m = 1
3548
return m * self.group().dimension_new_cusp_forms(self.weight(), eps=self.character())
3549
3550
def _matrix_of_operator_on_modular_symbols(self, codomain, R, character_twist=False):
3551
"""
3552
INPUT:
3553
3554
3555
- ``self`` - this space of modular symbols
3556
3557
- ``codomain`` - space of modular symbols
3558
3559
- ``R`` - list of lists [a,b,c,d] of length 4, which
3560
we view as elements of GL_2(Q).
3561
3562
3563
OUTPUT: a matrix, which represents the operator
3564
3565
.. math::
3566
3567
x \mapsto \sum_{g in R} g.x
3568
3569
3570
where g.x is the formal linear fractional transformation on modular
3571
symbols.
3572
3573
EXAMPLES::
3574
3575
sage: G, e = DirichletGroup(5).objgen()
3576
sage: M = ModularSymbols(e,3)
3577
sage: M.dimension()
3578
2
3579
sage: M._matrix_of_operator_on_modular_symbols(M,HeilbronnCremona(3))
3580
[ 6 6]
3581
[ 0 10]
3582
3583
"""
3584
eps = self.character()
3585
rows = []
3586
for b in self.basis():
3587
v = formal_sum.FormalSum(0, check=False)
3588
for c, x in b.modular_symbol_rep():
3589
for g in R:
3590
y = x.apply(g)
3591
if character_twist:
3592
v += y*c*eps(g[0])
3593
else:
3594
v += y*c
3595
w = codomain(v).element()
3596
rows.append(w)
3597
M = matrix_space.MatrixSpace(self.base_ring(), len(rows), codomain.degree(), sparse=False)
3598
return M(rows)
3599
3600
def _degeneracy_raising_matrix_1(self, M):
3601
r"""
3602
Return the matrix of the degeneracy raising map to ``M``, which should
3603
be a space of modular symbols with level a multiple of the level of
3604
self and with compatible character.
3605
3606
INPUT:
3607
3608
- ``M`` -- a space of modular symbols with character, whose level
3609
should be an integer multiple of the level of self, and whose
3610
character should be the Dirichlet character at that level obtained by
3611
extending the character of self.
3612
3613
The input is *not* sanity-checked in any way -- use with care!
3614
3615
OUTPUT:
3616
3617
(matrix) The matrix of the degeneracy raising matrix to the higher level.
3618
3619
EXAMPLES::
3620
3621
sage: eps = DirichletGroup(4).gen(0)
3622
sage: M = ModularSymbols(eps, 3); M
3623
Modular Symbols space of dimension 2 and level 4, weight 3, character [-1], sign 0, over Rational Field
3624
sage: M._degeneracy_raising_matrix_1(ModularSymbols(eps.extend(20), 3))
3625
[ 1 0 0 0 -1 -1 3 1 0 2 -3 0]
3626
[ 0 5 1 -2 -3 3 0 4 -1 5 -7 -1]
3627
"""
3628
level = int(M.level())
3629
N = self.level()
3630
3631
# 1. Find coset representatives H for Gamma_0(M.level()) \ Gamma_0(self.level())
3632
H = arithgroup.degeneracy_coset_representatives_gamma0(M.level(), N, 1)
3633
# 2. The map is
3634
# [P,pi(g)] |--> sum_{h in H} [P, pi(h*g)]
3635
#
3636
MS = matrix_space.MatrixSpace(self.base_ring(), self.dimension(), M.dimension())
3637
if self.dimension() == 0 or M.dimension() == 0:
3638
return MS(0)
3639
rows = []
3640
B = self.manin_basis()
3641
syms = self.manin_symbols()
3642
k = self.weight()
3643
G = matrix_space.MatrixSpace(integer_ring.IntegerRing(),2)
3644
H = [G(h) for h in H]
3645
eps = self.character() # note: in my thesis I twisted by eps^(-1), which is definitely a mistake
3646
# since twisting by eps gives the right answer and by eps^(-1) does not.
3647
for n in B:
3648
z = M(0)
3649
s = syms.manin_symbol(n)
3650
g = G(list(s.lift_to_sl2z(N)))
3651
i = s.i
3652
# We apply each matrix in H according to the above formula
3653
for h in H:
3654
hg = h*g
3655
z += eps(h[0,0])*M((i, hg[1,0], hg[1,1]))
3656
rows.append(z.element())
3657
A = MS(rows)
3658
return A
3659
3660
def _dimension_formula(self):
3661
r"""
3662
Return None: we have no dimension formula for `\Gamma_H(N)` spaces.
3663
3664
EXAMPLES::
3665
3666
sage: eps = DirichletGroup(5).gen(0)
3667
sage: M = ModularSymbols(eps, 2)
3668
sage: M.dimension()
3669
0
3670
sage: M._dimension_formula()
3671
"""
3672
return None
3673
3674
def boundary_space(self):
3675
r"""
3676
Return the space of boundary modular symbols for this space.
3677
3678
EXAMPLES::
3679
3680
sage: eps = DirichletGroup(5).gen(0)
3681
sage: M = ModularSymbols(eps, 2)
3682
sage: M.boundary_space()
3683
Boundary Modular Symbols space of level 5, weight 2, character [zeta4] and dimension 0 over Cyclotomic Field of order 4 and degree 2
3684
"""
3685
try:
3686
return self.__boundary_space
3687
except AttributeError:
3688
pass
3689
self.__boundary_space = boundary.BoundarySpace_wtk_eps(
3690
self.character(), self.weight(), self.sign())
3691
return self.__boundary_space
3692
3693
def manin_symbols(self):
3694
r"""
3695
Return the Manin symbol list of this modular symbol space.
3696
3697
EXAMPLES::
3698
3699
sage: eps = DirichletGroup(5).gen(0)
3700
sage: M = ModularSymbols(eps, 2)
3701
sage: M.manin_symbols()
3702
Manin Symbol List of weight 2 for Gamma1(5) with character [zeta4]
3703
sage: len(M.manin_symbols())
3704
6
3705
"""
3706
try:
3707
return self.__manin_symbols
3708
except AttributeError:
3709
self.__manin_symbols = manin_symbols.ManinSymbolList_character(
3710
character=self.character(), weight=self.weight())
3711
return self.__manin_symbols
3712
3713
def modular_symbols_of_level(self, N):
3714
r"""
3715
Returns a space of modular symbols with the same parameters as
3716
this space except with level `N`.
3717
3718
INPUT:
3719
3720
- ``N`` (int) -- a positive integer.
3721
3722
OUTPUT:
3723
3724
(Modular Symbol space) A space of modular symbols with the
3725
same defining properties (weight, sign, etc.) as this space
3726
except with level `N`.
3727
3728
EXAMPLES::
3729
3730
sage: eps = DirichletGroup(5).gen(0)
3731
sage: M = ModularSymbols(eps, 2); M
3732
Modular Symbols space of dimension 0 and level 5, weight 2, character [zeta4], sign 0, over Cyclotomic Field of order 4 and degree 2
3733
sage: M.modular_symbols_of_level(15)
3734
Modular Symbols space of dimension 0 and level 15, weight 2, character [1, zeta4], sign 0, over Cyclotomic Field of order 4 and degree 2
3735
"""
3736
if self.level() % N == 0:
3737
eps = self.character().restrict(N)
3738
elif N % self.level() == 0:
3739
eps = self.character().extend(N)
3740
else:
3741
raise ValueError("The level N (=%s) must be a divisor or multiple of the modulus of the character (=%s)"%(N, self.level()))
3742
return modsym.ModularSymbols(eps, self.weight(), self.sign(), self.base_ring())
3743
3744
def modular_symbols_of_sign(self, sign):
3745
r"""
3746
Returns a space of modular symbols with the same defining
3747
properties (weight, level, etc.) as this space except with given
3748
sign.
3749
3750
INPUT:
3751
3752
- ``sign`` (int) -- A sign (`+1`, `-1` or `0`).
3753
3754
OUTPUT:
3755
3756
(ModularSymbolsAmbient) A space of modular symbols with the
3757
same defining properties (weight, level, etc.) as this space
3758
except with given sign.
3759
3760
EXAMPLES::
3761
3762
sage: eps = DirichletGroup(5).gen(0)
3763
sage: M = ModularSymbols(eps, 2); M
3764
Modular Symbols space of dimension 0 and level 5, weight 2, character [zeta4], sign 0, over Cyclotomic Field of order 4 and degree 2
3765
sage: M.modular_symbols_of_sign(0) == M
3766
True
3767
sage: M.modular_symbols_of_sign(+1)
3768
Modular Symbols space of dimension 0 and level 5, weight 2, character [zeta4], sign 1, over Cyclotomic Field of order 4 and degree 2
3769
sage: M.modular_symbols_of_sign(-1)
3770
Modular Symbols space of dimension 0 and level 5, weight 2, character [zeta4], sign -1, over Cyclotomic Field of order 4 and degree 2
3771
3772
"""
3773
return modsym.ModularSymbols(self.character(), self.weight(), sign, self.base_ring())
3774
3775
def modular_symbols_of_weight(self, k):
3776
r"""
3777
Returns a space of modular symbols with the same defining
3778
properties (weight, sign, etc.) as this space except with weight
3779
`k`.
3780
3781
INPUT:
3782
3783
- ``k`` (int) -- A positive integer.
3784
3785
OUTPUT:
3786
3787
(ModularSymbolsAmbient) A space of modular symbols with the
3788
same defining properties (level, sign) as this space
3789
except with given weight.
3790
3791
EXAMPLES::
3792
3793
sage: eps = DirichletGroup(5).gen(0)
3794
sage: M = ModularSymbols(eps, 2); M
3795
Modular Symbols space of dimension 0 and level 5, weight 2, character [zeta4], sign 0, over Cyclotomic Field of order 4 and degree 2
3796
sage: M.modular_symbols_of_weight(3)
3797
Modular Symbols space of dimension 2 and level 5, weight 3, character [zeta4], sign 0, over Cyclotomic Field of order 4 and degree 2
3798
sage: M.modular_symbols_of_weight(2) == M
3799
True
3800
"""
3801
return modsym.ModularSymbols(self.character(), k, self.sign(), self.base_ring())
3802
3803
def _hecke_images(self, i, v):
3804
"""
3805
Return images of the `i`-th standard basis vector under the
3806
Hecke operators `T_p` for all integers in `v`.
3807
3808
INPUT:
3809
3810
3811
- ``i`` - nonnegative integer
3812
3813
- ``v`` - a list of positive integer
3814
3815
3816
OUTPUT:
3817
3818
3819
- ``matrix`` - whose rows are the Hecke images
3820
3821
EXAMPLES::
3822
3823
sage: G, e = DirichletGroup(50,QQ).objgen()
3824
sage: M = ModularSymbols(e^2,2)
3825
sage: M.dimension()
3826
15
3827
sage: M._hecke_images(8,range(1,5))
3828
[ 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0]
3829
[ 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0]
3830
[ 0 1 0 2 0 -1 1 1 0 0 0 0 0 0 0]
3831
[ 0 1 1 -1 -1 0 -1 1 1 0 1 2 0 -2 2]
3832
3833
3834
"""
3835
if self.weight() != 2:
3836
raise NotImplementedError("hecke images only implemented when the weight is 2")
3837
chi = self.character()
3838
# Find basis vector for ambient space such that it is not in
3839
# the kernel of the dual space corresponding to self.
3840
c = self.manin_generators()[self.manin_basis()[i]]
3841
N = self.level()
3842
if chi.order() > 2:
3843
return heilbronn.hecke_images_nonquad_character_weight2(c.u,c.v,N,
3844
v, chi, self.manin_gens_to_basis())
3845
else:
3846
return heilbronn.hecke_images_quad_character_weight2(c.u,c.v,N,
3847
v, chi, self.manin_gens_to_basis())
3848
raise NotImplementedError
3849
3850