Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/hecke/hecke_operator.py
4072 views
1
"""
2
Hecke operators
3
"""
4
5
#*****************************************************************************
6
# Copyright (C) 2004 William Stein <[email protected]>
7
#
8
# Distributed under the terms of the GNU General Public License (GPL)
9
#
10
# This code is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
# General Public License for more details.
14
#
15
# The full text of the GPL is available at:
16
#
17
# http://www.gnu.org/licenses/
18
#*****************************************************************************
19
20
21
22
import sage.algebras.algebra_element
23
from sage.categories.homset import End
24
import sage.rings.arith as arith
25
from sage.rings.integer import Integer
26
27
import algebra
28
import morphism
29
30
31
def is_HeckeOperator(x):
32
r"""
33
Return True if x is of type HeckeOperator.
34
35
EXAMPLES::
36
37
sage: from sage.modular.hecke.hecke_operator import is_HeckeOperator
38
sage: M = ModularSymbols(Gamma0(7), 4)
39
sage: is_HeckeOperator(M.T(3))
40
True
41
sage: is_HeckeOperator(M.T(3) + M.T(5))
42
False
43
"""
44
return isinstance(x, HeckeOperator)
45
46
def is_HeckeAlgebraElement(x):
47
r"""
48
Return True if x is of type HeckeAlgebraElement.
49
50
EXAMPLES::
51
52
sage: from sage.modular.hecke.hecke_operator import is_HeckeAlgebraElement
53
sage: M = ModularSymbols(Gamma0(7), 4)
54
sage: is_HeckeAlgebraElement(M.T(3))
55
True
56
sage: is_HeckeAlgebraElement(M.T(3) + M.T(5))
57
True
58
"""
59
return isinstance(x, HeckeAlgebraElement)
60
61
class HeckeAlgebraElement(sage.algebras.algebra_element.AlgebraElement):
62
r"""
63
Base class for elements of Hecke algebras.
64
"""
65
def __init__(self, parent):
66
r"""
67
Create an element of a Hecke algebra.
68
69
EXAMPLES::
70
71
sage: R = ModularForms(Gamma0(7), 4).hecke_algebra()
72
sage: sage.modular.hecke.hecke_operator.HeckeAlgebraElement(R) # please don't do this!
73
Generic element of a structure
74
"""
75
if not algebra.is_HeckeAlgebra(parent):
76
raise TypeError, "parent (=%s) must be a Hecke algebra"%parent
77
sage.algebras.algebra_element.AlgebraElement.__init__(self, parent)
78
79
def domain(self):
80
r"""
81
The domain of this operator. This is the Hecke module associated to the
82
parent Hecke algebra.
83
84
EXAMPLE::
85
86
sage: R = ModularForms(Gamma0(7), 4).hecke_algebra()
87
sage: sage.modular.hecke.hecke_operator.HeckeAlgebraElement(R).domain()
88
Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) of weight 4 over Rational Field
89
"""
90
91
return self.parent().module()
92
93
def codomain(self):
94
r"""
95
The codomain of this operator. This is the Hecke module associated to the
96
parent Hecke algebra.
97
98
EXAMPLE::
99
100
sage: R = ModularForms(Gamma0(7), 4).hecke_algebra()
101
sage: sage.modular.hecke.hecke_operator.HeckeAlgebraElement(R).codomain()
102
Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) of weight 4 over Rational Field
103
"""
104
return self.parent().module()
105
106
def hecke_module_morphism(self):
107
"""
108
Return the endomorphism of Hecke modules defined by the matrix
109
attached to this Hecke operator.
110
111
EXAMPLES::
112
113
sage: M = ModularSymbols(Gamma1(13))
114
sage: t = M.hecke_operator(2)
115
sage: t
116
Hecke operator T_2 on Modular Symbols space of dimension 15 for Gamma_1(13) of weight 2 with sign 0 and over Rational Field
117
sage: t.hecke_module_morphism()
118
Hecke module morphism T_2 defined by the matrix
119
[ 2 1 0 0 0 0 0 0 0 0 0 0 0 0 -1]
120
[ 0 2 0 1 0 0 0 -1 0 0 0 0 0 0 0]
121
[ 0 0 2 0 0 1 -1 1 0 -1 0 1 -1 0 0]
122
[ 0 0 0 2 1 0 1 0 0 0 1 -1 0 0 0]
123
[ 0 0 1 0 2 0 0 0 0 1 -1 0 0 0 1]
124
[ 1 0 0 0 0 2 0 0 0 0 0 0 1 0 0]
125
[ 0 0 0 0 0 0 0 1 -1 1 -1 0 -1 1 1]
126
[ 0 0 0 0 0 0 0 -1 1 1 0 0 -1 1 0]
127
[ 0 0 0 0 0 0 -1 -1 0 1 -1 -1 1 0 -1]
128
[ 0 0 0 0 0 0 -2 0 2 -2 0 2 -2 1 -1]
129
[ 0 0 0 0 0 0 0 0 2 -1 1 0 0 1 -1]
130
[ 0 0 0 0 0 0 -1 1 2 -1 1 0 -2 2 0]
131
[ 0 0 0 0 0 0 0 0 1 1 0 -1 0 0 0]
132
[ 0 0 0 0 0 0 -1 1 1 0 1 1 -1 0 0]
133
[ 0 0 0 0 0 0 2 0 0 0 2 -1 0 1 -1]
134
Domain: Modular Symbols space of dimension 15 for Gamma_1(13) of weight ...
135
Codomain: Modular Symbols space of dimension 15 for Gamma_1(13) of weight ...
136
"""
137
try:
138
return self.__hecke_module_morphism
139
except AttributeError:
140
T = self.matrix()
141
M = self.domain()
142
H = End(M)
143
if isinstance(self, HeckeOperator):
144
name = "T_%s"%self.index()
145
else:
146
name = ""
147
self.__hecke_module_morphism = morphism.HeckeModuleMorphism_matrix(H, T, name)
148
return self.__hecke_module_morphism
149
150
def _add_(self, other):
151
"""
152
Add self to other.
153
154
EXAMPLES::
155
156
sage: M = ModularSymbols(11)
157
sage: t = M.hecke_operator(2)
158
sage: t
159
Hecke operator T_2 on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field
160
sage: t + t # indirect doctest
161
Hecke operator on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field defined by:
162
[ 6 0 -2]
163
[ 0 -4 0]
164
[ 0 0 -4]
165
166
We can also add Hecke operators with different indexes::
167
168
sage: M = ModularSymbols(Gamma1(6),4)
169
sage: t2 = M.hecke_operator(2); t3 = M.hecke_operator(3)
170
sage: t2 + t3
171
Hecke operator on Modular Symbols space of dimension 6 for Gamma_1(6) of weight 4 with sign 0 and over Rational Field defined by:
172
[ 35 0 0 -8/7 24/7 -16/7]
173
[ 4 28 0 19/7 -57/7 38/7]
174
[ 18 0 9 -40/7 22/7 18/7]
175
[ 0 18 4 -22/7 -18/7 54/7]
176
[ 0 18 4 13/7 -53/7 54/7]
177
[ 0 18 4 13/7 -18/7 19/7]
178
sage: (t2 - t3).charpoly('x')
179
x^6 + 36*x^5 + 104*x^4 - 3778*x^3 + 7095*x^2 - 3458*x
180
"""
181
return self.parent()(self.matrix() + other.matrix(), check=False)
182
183
def __call__(self, x):
184
"""
185
Apply this Hecke operator to `x`.
186
187
EXAMPLES::
188
189
sage: M = ModularSymbols(11); t2 = M.hecke_operator(2)
190
sage: t2(M.gen(0))
191
3*(1,0) - (1,9)
192
193
::
194
195
sage: t2 = M.hecke_operator(2); t3 = M.hecke_operator(3)
196
sage: t3(t2(M.gen(0)))
197
12*(1,0) - 2*(1,9)
198
sage: (t3*t2)(M.gen(0))
199
12*(1,0) - 2*(1,9)
200
"""
201
T = self.hecke_module_morphism()
202
return T(x)
203
204
def __rmul__(self, left):
205
"""
206
EXAMPLES::
207
208
sage: M = ModularSymbols(11); t2 = M.hecke_operator(2)
209
sage: 2*t2
210
Hecke operator on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field defined by:
211
[ 6 0 -2]
212
[ 0 -4 0]
213
[ 0 0 -4]
214
"""
215
return self.parent()(left * self.matrix())
216
217
def _sub_(self, other):
218
"""
219
Compute the difference of self and other, where other has already been
220
coerced into the parent of self.
221
222
EXAMPLES::
223
224
sage: M = ModularSymbols(Gamma1(6),4)
225
sage: t2 = M.hecke_operator(2); t3 = M.hecke_operator(3)
226
sage: t2 - t3 # indirect doctest
227
Hecke operator on Modular Symbols space of dimension 6 for Gamma_1(6) of weight 4 with sign 0 and over Rational Field defined by:
228
[ -19 0 0 4/7 -12/7 8/7]
229
[ 4 -26 0 -17/7 51/7 -34/7]
230
[ -18 0 7 -12/7 -6/7 18/7]
231
[ 0 -18 4 -16/7 34/7 -18/7]
232
[ 0 -18 4 -23/7 41/7 -18/7]
233
[ 0 -18 4 -23/7 34/7 -11/7]
234
"""
235
return self.parent()(self.matrix() - other.matrix(), check=False)
236
237
def apply_sparse(self, x):
238
"""
239
Apply this Hecke operator to x, where we avoid computing the matrix
240
of x if possible.
241
242
EXAMPLES::
243
244
sage: M = ModularSymbols(11)
245
sage: T = M.hecke_operator(23)
246
sage: T.apply_sparse(M.gen(0))
247
24*(1,0) - 5*(1,9)
248
"""
249
if x not in self.domain():
250
raise TypeError, "x (=%s) must be in %s"%(x, self.domain())
251
# Generic implementation which doesn't actually do anything
252
# special regarding sparseness. Override this for speed.
253
T = self.hecke_module_morphism()
254
return T(x)
255
256
def charpoly(self, var='x'):
257
"""
258
Return the characteristic polynomial of this Hecke operator.
259
260
INPUT:
261
262
263
- ``var`` - string (default: 'x')
264
265
266
OUTPUT: a monic polynomial in the given variable.
267
268
EXAMPLES::
269
270
sage: M = ModularSymbols(Gamma1(6),4)
271
sage: M.hecke_operator(2).charpoly('x')
272
x^6 - 14*x^5 + 29*x^4 + 172*x^3 - 124*x^2 - 320*x + 256
273
"""
274
return self.matrix().charpoly(var)
275
276
def decomposition(self):
277
"""
278
Decompose the Hecke module under the action of this Hecke
279
operator.
280
281
EXAMPLES::
282
283
sage: M = ModularSymbols(11)
284
sage: t2 = M.hecke_operator(2)
285
sage: t2.decomposition()
286
[
287
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,
288
Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field
289
]
290
291
::
292
293
sage: M = ModularSymbols(33, sign=1).new_submodule()
294
sage: T = M.hecke_operator(2)
295
sage: T.decomposition()
296
[
297
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field,
298
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field
299
]
300
"""
301
try:
302
return self.__decomposition
303
except AttributeError:
304
pass
305
if isinstance(self, HeckeOperator) and \
306
arith.gcd(self.index(), self.domain().level()) == 1:
307
D = self.hecke_module_morphism().decomposition(is_diagonalizable=True)
308
else:
309
# TODO: There are other weaker hypotheses that imply diagonalizability.
310
D = self.hecke_module_morphism().decomposition()
311
D.sort()
312
D.set_immutable()
313
self.__decomposition = D
314
return D
315
316
def det(self):
317
"""
318
Return the determinant of this Hecke operator.
319
320
EXAMPLES::
321
322
sage: M = ModularSymbols(23)
323
sage: T = M.hecke_operator(3)
324
sage: T.det()
325
100
326
"""
327
return self.hecke_module_morphism().det()
328
329
def fcp(self, var='x'):
330
"""
331
Return the factorization of the characteristic polynomial of this
332
Hecke operator.
333
334
EXAMPLES::
335
336
sage: M = ModularSymbols(23)
337
sage: T = M.hecke_operator(3)
338
sage: T.fcp('x')
339
(x - 4) * (x^2 - 5)^2
340
"""
341
return self.hecke_module_morphism().fcp(var)
342
343
def image(self):
344
"""
345
Return the image of this Hecke operator.
346
347
EXAMPLES::
348
349
sage: M = ModularSymbols(23)
350
sage: T = M.hecke_operator(3)
351
sage: T.fcp('x')
352
(x - 4) * (x^2 - 5)^2
353
sage: T.image()
354
Modular Symbols subspace of dimension 5 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field
355
sage: (T-4).image()
356
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field
357
sage: (T**2-5).image()
358
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field
359
"""
360
return self.hecke_module_morphism().image()
361
362
def kernel(self):
363
"""
364
Return the kernel of this Hecke operator.
365
366
EXAMPLES::
367
368
sage: M = ModularSymbols(23)
369
sage: T = M.hecke_operator(3)
370
sage: T.fcp('x')
371
(x - 4) * (x^2 - 5)^2
372
sage: T.kernel()
373
Modular Symbols subspace of dimension 0 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field
374
sage: (T-4).kernel()
375
Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field
376
sage: (T**2-5).kernel()
377
Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field
378
"""
379
return self.hecke_module_morphism().kernel()
380
381
def trace(self):
382
"""
383
Return the trace of this Hecke operator.
384
385
::
386
387
sage: M = ModularSymbols(1,12)
388
sage: T = M.hecke_operator(2)
389
sage: T.trace()
390
2001
391
"""
392
return self.hecke_module_morphism().trace()
393
394
def __getitem__(self, ij):
395
"""
396
EXAMPLE::
397
398
sage: M = ModularSymbols(1,12)
399
sage: T = M.hecke_operator(2).matrix_form()
400
sage: T[0,0]
401
-24
402
"""
403
return self.matrix()[ij]
404
405
406
class HeckeAlgebraElement_matrix(HeckeAlgebraElement):
407
r"""
408
An element of the Hecke algebra represented by a matrix.
409
"""
410
def __init__(self, parent, A):
411
r"""
412
Initialise an element from a matrix. This *must* be over the base ring
413
of self and have the right size.
414
415
This is a bit overkill as similar checks will be performed by the call
416
and coerce methods of the parent of self, but it can't hurt to be
417
paranoid. Any fancy coercion / base_extension / etc happens there, not
418
here.
419
420
TESTS::
421
422
sage: T = ModularForms(Gamma0(7), 4).hecke_algebra()
423
sage: M = sage.modular.hecke.hecke_operator.HeckeAlgebraElement_matrix(T, matrix(QQ,3,[2,3,0,1,2,3,7,8,9])); M
424
Hecke operator on Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) of weight 4 over Rational Field defined by:
425
[2 3 0]
426
[1 2 3]
427
[7 8 9]
428
sage: loads(dumps(M)) == M
429
True
430
sage: sage.modular.hecke.hecke_operator.HeckeAlgebraElement_matrix(T, matrix(Integers(2),3,[2,3,0,1,2,3,7,8,9]))
431
Traceback (most recent call last):
432
...
433
TypeError: base ring of matrix (Ring of integers modulo 2) does not match base ring of space (Rational Field)
434
sage: sage.modular.hecke.hecke_operator.HeckeAlgebraElement_matrix(T, matrix(QQ,2,[2,3,0,1]))
435
Traceback (most recent call last):
436
...
437
TypeError: A must be a square matrix of rank 3
438
"""
439
HeckeAlgebraElement.__init__(self, parent)
440
if not sage.matrix.all.is_Matrix(A):
441
raise TypeError, "A must be a matrix"
442
if not A.base_ring() == self.parent().base_ring():
443
raise TypeError, "base ring of matrix (%s) does not match base ring of space (%s)" % (A.base_ring(), self.parent().base_ring())
444
if not A.nrows() == A.ncols() == self.parent().module().rank():
445
raise TypeError, "A must be a square matrix of rank %s" % self.parent().module().rank()
446
self.__matrix = A
447
448
def __cmp__(self, other):
449
r"""
450
Compare self to other, where the coercion model has already ensured
451
that other has the same parent as self.
452
453
EXAMPLES::
454
455
sage: T = ModularForms(SL2Z, 12).hecke_algebra()
456
sage: m = T(matrix(QQ, 2, [1,2,0,1]), check=False); n = T.hecke_operator(14)
457
sage: m == n
458
False
459
sage: m == n.matrix_form()
460
False
461
sage: n.matrix_form() == T(matrix(QQ, 2, [4051542498456, 384163586352000, 0, 401856]), check=False)
462
True
463
"""
464
if not isinstance(other, HeckeAlgebraElement_matrix):
465
if isinstance(other, HeckeOperator):
466
return cmp(self, other.matrix_form())
467
else:
468
raise RuntimeError, "Bug in coercion code" # can't get here.
469
return cmp(self.__matrix, other.__matrix)
470
471
def _repr_(self):
472
r"""
473
String representation of self.
474
475
EXAMPLES::
476
477
sage: M = ModularSymbols(1,12)
478
sage: M.hecke_operator(2).matrix_form()._repr_()
479
'Hecke operator on Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field defined by:\n[ -24 0 0]\n[ 0 -24 0]\n[4860 0 2049]'
480
sage: ModularForms(Gamma0(100)).hecke_operator(4).matrix_form()._repr_()
481
'Hecke operator on Modular Forms space of dimension 24 for Congruence Subgroup Gamma0(100) of weight 2 over Rational Field defined by:\n24 x 24 dense matrix over Rational Field'
482
"""
483
return "Hecke operator on %s defined by:\n%s"%(self.parent().module(), self.__matrix)
484
485
def _latex_(self):
486
r"""
487
Latex representation of self (just prints the matrix)
488
489
EXAMPLE::
490
491
sage: M = ModularSymbols(1,12)
492
sage: M.hecke_operator(2).matrix_form()._latex_()
493
'\\left(\\begin{array}{rrr}\n-24 & 0 & 0 \\\\\n0 & -24 & 0 \\\\\n4860 & 0 & 2049\n\\end{array}\\right)'
494
"""
495
return self.__matrix._latex_()
496
497
def matrix(self):
498
"""
499
Return the matrix that defines this Hecke algebra element.
500
501
EXAMPLES::
502
503
sage: M = ModularSymbols(1,12)
504
sage: T = M.hecke_operator(2).matrix_form()
505
sage: T.matrix()
506
[ -24 0 0]
507
[ 0 -24 0]
508
[4860 0 2049]
509
"""
510
return self.__matrix
511
512
def _mul_(self, other):
513
r"""
514
Multiply self by other (which has already been coerced into an element
515
of the parent of self).
516
517
EXAMPLES::
518
519
sage: M = ModularSymbols(1,12)
520
sage: T = M.hecke_operator(2).matrix_form()
521
sage: T * T # indirect doctest
522
Hecke operator on Modular Symbols space of dimension 3 for Gamma_0(1) of weight 12 with sign 0 over Rational Field defined by:
523
[ 576 0 0]
524
[ 0 576 0]
525
[9841500 0 4198401]
526
"""
527
return self.parent()(other.matrix() * self.matrix(), check=False)
528
529
530
class DiamondBracketOperator(HeckeAlgebraElement_matrix):
531
r"""
532
The diamond bracket operator `\langle d \rangle` for some `d \in \ZZ /
533
N\ZZ` (which need not be a unit, although if it is not, the operator will
534
be zero).
535
"""
536
def __init__(self, parent, d):
537
r"""
538
Standard init function.
539
540
EXAMPLE::
541
542
sage: M = ModularSymbols(Gamma1(5),6)
543
sage: d = M.diamond_bracket_operator(2); d # indirect doctest
544
Diamond bracket operator <2> on Modular Symbols space of dimension 10 for Gamma_1(5) of weight 6 with sign 0 and over Rational Field
545
sage: type(d)
546
<class 'sage.modular.hecke.hecke_operator.DiamondBracketOperator'>
547
sage: d.matrix()
548
[ 0 1 0 0 0 0 0 0 0 0]
549
[ 1 0 0 0 0 0 0 0 0 0]
550
[ 0 0 0 0 0 0 0 1 0 0]
551
[ 0 0 -8/17 -1 14/17 11/17 0 -8/17 14/17 11/17]
552
[ 0 0 0 0 0 0 0 0 1 0]
553
[ 0 0 0 0 0 0 0 0 0 1]
554
[ 0 0 16/17 0 -11/17 12/17 -1 16/17 -11/17 12/17]
555
[ 0 0 1 0 0 0 0 0 0 0]
556
[ 0 0 0 0 1 0 0 0 0 0]
557
[ 0 0 0 0 0 1 0 0 0 0]
558
sage: d**4 == 1
559
True
560
"""
561
self.__d = d
562
A = parent.diamond_bracket_matrix(d)
563
HeckeAlgebraElement_matrix.__init__(self, parent, A)
564
565
def _repr_(self):
566
r"""
567
EXAMPLE::
568
569
sage: ModularSymbols(Gamma1(5), 6).diamond_bracket_operator(2)._repr_()
570
'Diamond bracket operator <2> on Modular Symbols space of dimension 10 for Gamma_1(5) of weight 6 with sign 0 and over Rational Field'
571
"""
572
return "Diamond bracket operator <%s> on %s" % (self.__d, self.domain())
573
574
def _latex_(self):
575
r"""
576
EXAMPLE::
577
578
sage: latex(ModularSymbols(Gamma1(5), 12).diamond_bracket_operator(2)) # indirect doctest
579
\langle 2 \rangle
580
"""
581
return r"\langle %s \rangle" % self.__d
582
583
class HeckeOperator(HeckeAlgebraElement):
584
r"""
585
The Hecke operator `T_n` for some `n` (which need not be coprime to the
586
level). The matrix is not computed until it is needed.
587
"""
588
def __init__(self, parent, n):
589
"""
590
EXAMPLES::
591
592
sage: M = ModularSymbols(11)
593
sage: H = M.hecke_operator(2005); H
594
Hecke operator T_2005 on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field
595
sage: H == loads(dumps(H))
596
True
597
598
We create a Hecke operator of large index (greater than 32 bits)::
599
600
sage: M1 = ModularSymbols(21,2)
601
sage: M1.hecke_operator(13^9)
602
Hecke operator T_10604499373 on Modular Symbols space of dimension 5 for Gamma_0(21) of weight 2 with sign 0 over Rational Field
603
"""
604
HeckeAlgebraElement.__init__(self, parent)
605
if not isinstance(n, (int,long,Integer)):
606
raise TypeError, "n must be an int"
607
self.__n = int(n)
608
609
def __cmp__(self, other):
610
r"""
611
Compare self and other (where the coercion model has already ensured
612
that self and other have the same parent). Hecke operators on the same
613
space compare as equal if and only if their matrices are equal, so we
614
check if the indices are the same and if not we compute the matrices
615
(which is potentially expensive).
616
617
EXAMPLES::
618
619
sage: M = ModularSymbols(Gamma0(7), 4)
620
sage: m = M.hecke_operator(3)
621
sage: m == m
622
True
623
sage: m == 2*m
624
False
625
sage: m == M.hecke_operator(5)
626
False
627
628
These last two tests involve a coercion::
629
630
sage: m == m.matrix_form()
631
True
632
sage: m == m.matrix()
633
False
634
"""
635
636
if not isinstance(other, HeckeOperator):
637
if isinstance(other, HeckeAlgebraElement_matrix):
638
return cmp(self.matrix_form(), other)
639
else:
640
raise RuntimeError, "Bug in coercion code" # can't get here
641
642
if self.__n == other.__n:
643
return 0
644
return cmp(self.matrix(), other.matrix())
645
646
def _repr_(self):
647
r"""
648
String representation of self
649
650
EXAMPLE::
651
652
sage: ModularSymbols(Gamma0(7), 4).hecke_operator(6)._repr_()
653
'Hecke operator T_6 on Modular Symbols space of dimension 4 for Gamma_0(7) of weight 4 with sign 0 over Rational Field'
654
"""
655
return "Hecke operator T_%s on %s"%(self.__n, self.domain())
656
657
def _latex_(self):
658
r"""
659
LaTeX representation of self
660
661
EXAMPLE::
662
663
sage: ModularSymbols(Gamma0(7), 4).hecke_operator(6)._latex_()
664
'T_{6}'
665
"""
666
return "T_{%s}"%self.__n
667
668
def _mul_(self, other):
669
"""
670
Multiply this Hecke operator by another element of the same algebra. If
671
the other element is of the form `T_m` for some m, we check whether the
672
product is equal to `T_{mn}` and return that; if the product is not
673
(easily seen to be) of the form `T_{mn}`, then we calculate the product
674
of the two matrices and return a Hecke algebra element defined by that.
675
676
EXAMPLES: We create the space of modular symbols of level
677
`11` and weight `2`, then compute `T_2`
678
and `T_3` on it, along with their composition.
679
680
::
681
682
sage: M = ModularSymbols(11)
683
sage: t2 = M.hecke_operator(2); t3 = M.hecke_operator(3)
684
sage: t2*t3 # indirect doctest
685
Hecke operator T_6 on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field
686
sage: t3.matrix() * t2.matrix()
687
[12 0 -2]
688
[ 0 2 0]
689
[ 0 0 2]
690
sage: (t2*t3).matrix()
691
[12 0 -2]
692
[ 0 2 0]
693
[ 0 0 2]
694
695
When we compute `T_2^5` the result is not (easily seen to
696
be) a Hecke operator of the form `T_n`, so it is returned
697
as a Hecke module homomorphism defined as a matrix::
698
699
sage: t2**5
700
Hecke operator on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field defined by:
701
[243 0 -55]
702
[ 0 -32 0]
703
[ 0 0 -32]
704
"""
705
if isinstance(other, HeckeOperator) and other.parent() == self.parent():
706
n = None
707
if arith.gcd(self.__n, other.__n) == 1:
708
n = self.__n * other.__n
709
else:
710
P = set(arith.prime_divisors(self.domain().level()))
711
if P.issubset(set(arith.prime_divisors(self.__n))) and \
712
P.issubset(set(arith.prime_divisors(other.__n))):
713
n = self.__n * other.__n
714
if n:
715
return HeckeOperator(self.parent(), n)
716
# otherwise
717
return self.matrix_form() * other
718
719
def index(self):
720
"""
721
Return the index of this Hecke operator, i.e., if this Hecke
722
operator is `T_n`, return the int `n`.
723
724
EXAMPLES::
725
726
sage: T = ModularSymbols(11).hecke_operator(17)
727
sage: T.index()
728
17
729
"""
730
return self.__n
731
732
def matrix(self, *args, **kwds):
733
"""
734
Return the matrix underlying this Hecke operator.
735
736
EXAMPLES::
737
738
sage: T = ModularSymbols(11).hecke_operator(17)
739
sage: T.matrix()
740
[18 0 -4]
741
[ 0 -2 0]
742
[ 0 0 -2]
743
"""
744
try:
745
return self.__matrix
746
except AttributeError:
747
self.__matrix = self.parent().hecke_matrix(self.__n, *args, **kwds)
748
return self.__matrix
749
750
def matrix_form(self):
751
"""
752
Return the matrix form of this element of a Hecke algebra.
753
754
::
755
756
sage: T = ModularSymbols(11).hecke_operator(17)
757
sage: T.matrix_form()
758
Hecke operator on Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field defined by:
759
[18 0 -4]
760
[ 0 -2 0]
761
[ 0 0 -2]
762
"""
763
try:
764
return self.__matrix_form
765
except AttributeError:
766
self.__matrix_form = self.parent()(self.matrix(), check=False)
767
return self.__matrix_form
768
769
770