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