Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/arithgroup/congroup_gamma1.py
4091 views
1
r"""
2
Congruence Subgroup `\Gamma_1(N)`
3
"""
4
5
################################################################################
6
#
7
# Copyright (C) 2009, The Sage Group -- http://www.sagemath.org/
8
#
9
# Distributed under the terms of the GNU General Public License (GPL)
10
#
11
# The full text of the GPL is available at:
12
#
13
# http://www.gnu.org/licenses/
14
#
15
################################################################################
16
17
from sage.misc.cachefunc import cached_method
18
19
from sage.misc.misc import prod
20
from congroup_generic import is_CongruenceSubgroup
21
from congroup_gammaH import GammaH_class, is_GammaH, GammaH_constructor
22
#from congroup_gamma0 import Gamma0_constructor -- circular!
23
from arithgroup_element import ArithmeticSubgroupElement
24
from sage.rings.all import ZZ, euler_phi as phi, moebius, divisors
25
from sage.modular.dirichlet import DirichletGroup
26
27
# Just for now until we make an SL_2 group type.
28
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
29
from sage.matrix.matrix_space import MatrixSpace
30
Mat2Z = MatrixSpace(IntegerModRing(0),2)
31
32
def is_Gamma1(x):
33
"""
34
Return True if x is a congruence subgroup of type Gamma1.
35
36
EXAMPLES::
37
38
sage: from sage.modular.arithgroup.all import is_Gamma1
39
sage: is_Gamma1(SL2Z)
40
False
41
sage: is_Gamma1(Gamma1(13))
42
True
43
sage: is_Gamma1(Gamma0(6))
44
False
45
sage: is_Gamma1(GammaH(12, [])) # trick question!
46
True
47
sage: is_Gamma1(GammaH(12, [5]))
48
False
49
"""
50
#from congroup_sl2z import is_SL2Z
51
#return (isinstance(x, Gamma1_class) or is_SL2Z(x))
52
return isinstance(x, Gamma1_class)
53
54
_gamma1_cache = {}
55
def Gamma1_constructor(N):
56
r"""
57
Return the congruence subgroup `\Gamma_1(N)`.
58
59
EXAMPLES::
60
61
sage: Gamma1(5) # indirect doctest
62
Congruence Subgroup Gamma1(5)
63
sage: G = Gamma1(23)
64
sage: G is Gamma1(23)
65
True
66
sage: G == loads(dumps(G))
67
True
68
sage: G is loads(dumps(G))
69
True
70
"""
71
if N == 1 or N == 2:
72
from congroup_gamma0 import Gamma0_constructor
73
return Gamma0_constructor(N)
74
try:
75
return _gamma1_cache[N]
76
except KeyError:
77
_gamma1_cache[N] = Gamma1_class(N)
78
return _gamma1_cache[N]
79
80
class Gamma1_class(GammaH_class):
81
r"""
82
The congruence subgroup `\Gamma_1(N)`.
83
84
TESTS::
85
86
sage: [Gamma1(n).genus() for n in prime_range(2,100)]
87
[0, 0, 0, 0, 1, 2, 5, 7, 12, 22, 26, 40, 51, 57, 70, 92, 117, 126, 155, 176, 187, 222, 247, 287, 345]
88
sage: [Gamma1(n).index() for n in [1..10]]
89
[1, 3, 8, 12, 24, 24, 48, 48, 72, 72]
90
91
sage: [Gamma1(n).dimension_cusp_forms() for n in [1..20]]
92
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 1, 1, 2, 5, 2, 7, 3]
93
sage: [Gamma1(n).dimension_cusp_forms(1) for n in [1..20]]
94
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
95
sage: [Gamma1(4).dimension_cusp_forms(k) for k in [1..20]]
96
[0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8]
97
sage: Gamma1(23).dimension_cusp_forms(1)
98
Traceback (most recent call last):
99
...
100
NotImplementedError: Computation of dimensions of weight 1 cusp forms spaces not implemented in general
101
"""
102
103
def __init__(self, level):
104
r"""
105
The congruence subgroup `\Gamma_1(N)`.
106
107
EXAMPLES::
108
109
sage: G = Gamma1(11); G
110
Congruence Subgroup Gamma1(11)
111
sage: loads(G.dumps()) == G
112
True
113
"""
114
GammaH_class.__init__(self, level, [])
115
116
def __cmp__(self, other):
117
"""
118
Compare self to other.
119
120
The ordering on congruence subgroups of the form `\Gamma_H(N)` for
121
some H is first by level and then by the subgroup H. In
122
particular, this means that we have `\Gamma_1(N) < \Gamma_H(N) <
123
\Gamma_0(N)` for every nontrivial subgroup H.
124
125
EXAMPLES::
126
127
sage: G = Gamma1(86)
128
sage: G.__cmp__(G)
129
0
130
sage: G.__cmp__(GammaH(86, [11])) is not 0
131
True
132
sage: Gamma1(12) < Gamma0(12)
133
True
134
sage: Gamma1(10) < Gamma1(12)
135
True
136
sage: Gamma1(11) == GammaH(11, [])
137
True
138
sage: Gamma1(1) == SL2Z
139
True
140
sage: Gamma1(2) == Gamma0(2)
141
True
142
"""
143
from all import is_GammaH
144
if not is_CongruenceSubgroup(other):
145
return cmp(type(self), type(other))
146
147
c = cmp(self.level(), other.level())
148
if c: return c
149
150
# Since Gamma1(N) is GammaH(N) for H all of (Z/N)^\times,
151
# we know how to compare it to any other GammaH without having
152
# to look at self._list_of_elements_in_H().
153
if is_GammaH(other):
154
if is_Gamma1(other):
155
return 0
156
else:
157
H = other._generators_for_H()
158
return cmp(0,len(H))
159
return cmp(type(self), type(other))
160
161
def _repr_(self):
162
"""
163
Return the string representation of self.
164
165
EXAMPLES::
166
167
sage: Gamma1(133)._repr_()
168
'Congruence Subgroup Gamma1(133)'
169
"""
170
return "Congruence Subgroup Gamma1(%s)"%self.level()
171
172
def __reduce__(self):
173
"""
174
Used for pickling self.
175
176
EXAMPLES::
177
178
sage: Gamma1(82).__reduce__()
179
(<function Gamma1_constructor at ...>, (82,))
180
"""
181
return Gamma1_constructor, (self.level(),)
182
183
def _latex_(self):
184
r"""
185
Return the \LaTeX representation of self.
186
187
EXAMPLES::
188
189
sage: Gamma1(3)._latex_()
190
'\\Gamma_1(3)'
191
sage: latex(Gamma1(3))
192
\Gamma_1(3)
193
"""
194
return "\\Gamma_1(%s)"%self.level()
195
196
def is_even(self):
197
"""
198
Return True precisely if this subgroup contains the matrix -1.
199
200
EXAMPLES::
201
202
sage: Gamma1(1).is_even()
203
True
204
sage: Gamma1(2).is_even()
205
True
206
sage: Gamma1(15).is_even()
207
False
208
"""
209
return self.level() in [1,2]
210
211
def is_subgroup(self, right):
212
"""
213
Return True if self is a subgroup of right.
214
215
EXAMPLES::
216
217
sage: Gamma1(3).is_subgroup(SL2Z)
218
True
219
sage: Gamma1(3).is_subgroup(Gamma1(5))
220
False
221
sage: Gamma1(3).is_subgroup(Gamma1(6))
222
False
223
sage: Gamma1(6).is_subgroup(Gamma1(3))
224
True
225
sage: Gamma1(6).is_subgroup(Gamma0(2))
226
True
227
sage: Gamma1(80).is_subgroup(GammaH(40, []))
228
True
229
sage: Gamma1(80).is_subgroup(GammaH(40, [21]))
230
True
231
"""
232
if right.level() == 1:
233
return True
234
if is_GammaH(right):
235
return self.level() % right.level() == 0
236
else:
237
raise NotImplementedError
238
239
@cached_method
240
def generators(self, algorithm="farey"):
241
r"""
242
Return generators for this congruence subgroup. The result is cached.
243
244
INPUT:
245
246
- ``algorithm`` (string): either ``farey`` (default) or
247
``todd-coxeter``.
248
249
If ``algorithm`` is set to ``"farey"``, then the generators will be
250
calculated using Farey symbols, which will always return a *minimal*
251
generating set. See :mod:`~sage.modular.arithgroup.farey_symbol` for
252
more information.
253
254
If ``algorithm`` is set to ``"todd-coxeter"``, a simpler algorithm
255
based on Todd-Coxeter enumeration will be used. This tends to return
256
far larger sets of generators.
257
258
EXAMPLE::
259
260
sage: Gamma1(3).generators()
261
[
262
[1 1] [ 1 -1]
263
[0 1], [ 3 -2]
264
]
265
sage: Gamma1(3).generators(algorithm="todd-coxeter")
266
[
267
[1 1] [-20 9] [ 4 1] [-5 -2] [ 1 -1] [1 0] [1 1] [-5 2]
268
[0 1], [ 51 -23], [-9 -2], [ 3 1], [ 0 1], [3 1], [0 1], [12 -5],
269
<BLANKLINE>
270
[ 1 0] [ 4 -1] [ -5 3] [ 1 -1] [ 7 -3] [ 4 -1] [ -5 3]
271
[-3 1], [ 9 -2], [-12 7], [ 3 -2], [12 -5], [ 9 -2], [-12 7]
272
]
273
"""
274
if algorithm=="farey":
275
return self.farey_symbol().generators()
276
elif algorithm=="todd-coxeter":
277
from sage.modular.modsym.g1list import G1list
278
from congroup_pyx import generators_helper
279
level = self.level()
280
gen_list = generators_helper(G1list(level), level, Mat2Z)
281
return [self(g, check=False) for g in gen_list]
282
else:
283
raise ValueError, "Unknown algorithm '%s' (should be either 'farey' or 'todd-coxeter')" % algorithm
284
285
def __call__(self, x, check=True):
286
r"""
287
Create an element of this congruence subgroup from x.
288
289
If the optional flag check is True (default), check whether
290
x actually gives an element of self.
291
292
EXAMPLES::
293
294
sage: G = Gamma1(5)
295
sage: G([1, 0, -10, 1])
296
[ 1 0]
297
[-10 1]
298
sage: G(matrix(ZZ, 2, [6, 1, 5, 1]))
299
[6 1]
300
[5 1]
301
sage: G([1, 1, 6, 7])
302
Traceback (most recent call last):
303
...
304
TypeError: matrix must have diagonal entries (=1, 7) congruent to 1 modulo 5, and lower left entry (=6) divisible by 5
305
"""
306
from all import SL2Z
307
x = SL2Z(x, check)
308
if not check:
309
return x
310
311
a = x.a()
312
c = x.c()
313
d = x.d()
314
N = self.level()
315
if (a%N == 1) and (c%N == 0):
316
return x
317
# don't need to check d == 1 mod N as this is automatic from det
318
else:
319
raise TypeError, "matrix must have diagonal entries (=%s, %s) congruent to 1 modulo %s, and lower left entry (=%s) divisible by %s" %(a, d, N, c, N)
320
321
322
def nu2(self):
323
r"""
324
Calculate the number of orbits of elliptic points of order 2 for this
325
subgroup `\Gamma_1(N)`. This is known to be 0 if N > 2.
326
327
EXAMPLE::
328
329
sage: Gamma1(2).nu2()
330
1
331
sage: Gamma1(457).nu2()
332
0
333
sage: [Gamma1(n).nu2() for n in [1..16]]
334
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
335
"""
336
337
N = self.level()
338
if N > 2: return 0
339
elif N == 2 or N == 1: return 1
340
341
def nu3(self):
342
r"""
343
Calculate the number of orbits of elliptic points of order 3 for this
344
subgroup `\Gamma_1(N)`. This is known to be 0 if N > 3.
345
346
EXAMPLE::
347
348
sage: Gamma1(2).nu3()
349
0
350
sage: Gamma1(3).nu3()
351
1
352
sage: Gamma1(457).nu3()
353
0
354
sage: [Gamma1(n).nu3() for n in [1..10]]
355
[1, 0, 1, 0, 0, 0, 0, 0, 0, 0]
356
"""
357
358
N = self.level()
359
if N > 3 or N == 2: return 0
360
else: return 1
361
362
def ncusps(self):
363
r"""
364
Return the number of cusps of this subgroup `\Gamma_1(N)`.
365
366
EXAMPLES::
367
368
sage: [Gamma1(n).ncusps() for n in [1..15]]
369
[1, 2, 2, 3, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 16]
370
sage: [Gamma1(n).ncusps() for n in prime_range(2, 100)]
371
[2, 2, 4, 6, 10, 12, 16, 18, 22, 28, 30, 36, 40, 42, 46, 52, 58, 60, 66, 70, 72, 78, 82, 88, 96]
372
"""
373
n = self.level()
374
if n <= 4:
375
return [None, 1, 2, 2, 3][n]
376
return ZZ(sum([phi(d)*phi(n/d)/ZZ(2) for d in n.divisors()]))
377
378
def index(self):
379
r"""
380
Return the index of self in the full modular group. This is given by the formula
381
382
.. math::
383
384
N^2 \prod_{\substack{p \mid N \\ \text{$p$ prime}}} \left( 1 - \frac{1}{p^2}\right).
385
386
EXAMPLE::
387
388
sage: Gamma1(180).index()
389
20736
390
sage: [Gamma1(n).projective_index() for n in [1..16]]
391
[1, 3, 4, 6, 12, 12, 24, 24, 36, 36, 60, 48, 84, 72, 96, 96]
392
"""
393
return prod([p**(2*e) - p**(2*e-2) for (p,e) in self.level().factor()])
394
395
##################################################################################
396
# Dimension formulas for Gamma1, accepting a Dirichlet character as an argument. #
397
##################################################################################
398
399
def dimension_modular_forms(self, k=2, eps=None, algorithm="CohenOesterle"):
400
r"""
401
Return the dimension of the space of modular forms for self, or the
402
dimension of the subspace corresponding to the given character if one
403
is supplied.
404
405
INPUT:
406
407
- ``k`` - an integer (default: 2), the weight.
408
409
- ``eps`` - either None or a Dirichlet character modulo N, where N is
410
the level of this group. If this is None, then the dimension of the
411
whole space is returned; otherwise, the dimension of the subspace of
412
forms of character eps.
413
414
- ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This
415
specifies the method to use in the case of nontrivial character:
416
either the Cohen--Oesterle formula as described in Stein's book, or
417
by Moebius inversion using the subgroups GammaH (a method due to
418
Jordi Quer).
419
420
EXAMPLES::
421
422
sage: K = CyclotomicField(3)
423
sage: eps = DirichletGroup(7*43,K).0^2
424
sage: G = Gamma1(7*43)
425
426
sage: G.dimension_modular_forms(2, eps)
427
32
428
sage: G.dimension_modular_forms(2, eps, algorithm="Quer")
429
32
430
"""
431
432
return self.dimension_cusp_forms(k, eps, algorithm) + self.dimension_eis(k, eps, algorithm)
433
434
def dimension_cusp_forms(self, k=2, eps=None, algorithm="CohenOesterle"):
435
r"""
436
Return the dimension of the space of cusp forms for self, or the
437
dimension of the subspace corresponding to the given character if one
438
is supplied.
439
440
INPUT:
441
442
- ``k`` - an integer (default: 2), the weight.
443
444
- ``eps`` - either None or a Dirichlet character modulo N, where N is
445
the level of this group. If this is None, then the dimension of the
446
whole space is returned; otherwise, the dimension of the subspace of
447
forms of character eps.
448
449
- ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This
450
specifies the method to use in the case of nontrivial character:
451
either the Cohen--Oesterle formula as described in Stein's book, or
452
by Moebius inversion using the subgroups GammaH (a method due to
453
Jordi Quer).
454
455
EXAMPLES:
456
457
We compute the same dimension in two different ways ::
458
459
sage: K = CyclotomicField(3)
460
sage: eps = DirichletGroup(7*43,K).0^2
461
sage: G = Gamma1(7*43)
462
463
Via Cohen--Oesterle: ::
464
465
sage: Gamma1(7*43).dimension_cusp_forms(2, eps)
466
28
467
468
Via Quer's method: ::
469
470
sage: Gamma1(7*43).dimension_cusp_forms(2, eps, algorithm="Quer")
471
28
472
473
Some more examples: ::
474
475
sage: G.<eps> = DirichletGroup(9)
476
sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [1..10]]
477
[0, 0, 1, 0, 3, 0, 5, 0, 7, 0]
478
sage: [Gamma1(9).dimension_cusp_forms(k, eps^2) for k in [1..10]]
479
[0, 0, 0, 2, 0, 4, 0, 6, 0, 8]
480
"""
481
482
from all import Gamma0
483
484
# first deal with special cases
485
486
if eps is None:
487
return GammaH_class.dimension_cusp_forms(self, k)
488
489
N = self.level()
490
if eps.base_ring().characteristic() != 0:
491
raise ValueError
492
493
eps = DirichletGroup(N, eps.base_ring())(eps)
494
495
if eps.is_trivial():
496
return Gamma0(N).dimension_cusp_forms(k)
497
498
if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k%2) == 0 and eps.is_odd()):
499
return ZZ(0)
500
501
if k == 1:
502
try:
503
n = self.dimension_cusp_forms(1)
504
if n == 0:
505
return ZZ(0)
506
else: # never happens at present
507
raise NotImplementedError, "Computations of dimensions of spaces of weight 1 cusp forms not implemented at present"
508
except NotImplementedError:
509
raise
510
511
# now the main part
512
513
if algorithm == "Quer":
514
n = eps.order()
515
dim = ZZ(0)
516
for d in n.divisors():
517
G = GammaH_constructor(N,(eps**d).kernel())
518
dim = dim + moebius(d)*G.dimension_cusp_forms(k)
519
return dim//phi(n)
520
521
elif algorithm == "CohenOesterle":
522
K = eps.base_ring()
523
from sage.modular.dims import CohenOesterle
524
from all import Gamma0
525
return ZZ( K(Gamma0(N).index() * (k-1)/ZZ(12)) + CohenOesterle(eps,k) )
526
527
else: #algorithm not in ["CohenOesterle", "Quer"]:
528
raise ValueError, "Unrecognised algorithm in dimension_cusp_forms"
529
530
531
def dimension_eis(self, k=2, eps=None, algorithm="CohenOesterle"):
532
r"""
533
Return the dimension of the space of Eisenstein series forms for self,
534
or the dimension of the subspace corresponding to the given character
535
if one is supplied.
536
537
INPUT:
538
539
- ``k`` - an integer (default: 2), the weight.
540
541
- ``eps`` - either None or a Dirichlet character modulo N, where N is
542
the level of this group. If this is None, then the dimension of the
543
whole space is returned; otherwise, the dimension of the subspace of
544
Eisenstein series of character eps.
545
546
- ``algorithm`` -- either "CohenOesterle" (the default) or "Quer". This
547
specifies the method to use in the case of nontrivial character:
548
either the Cohen--Oesterle formula as described in Stein's book, or
549
by Moebius inversion using the subgroups GammaH (a method due to
550
Jordi Quer).
551
552
AUTHORS:
553
554
- William Stein - Cohen--Oesterle algorithm
555
556
- Jordi Quer - algorithm based on GammaH subgroups
557
558
- David Loeffler (2009) - code refactoring
559
560
EXAMPLES:
561
562
The following two computations use different algorithms: ::
563
564
sage: [Gamma1(36).dimension_eis(1,eps) for eps in DirichletGroup(36)]
565
[0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]
566
sage: [Gamma1(36).dimension_eis(1,eps,algorithm="Quer") for eps in DirichletGroup(36)]
567
[0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]
568
569
So do these: ::
570
571
sage: [Gamma1(48).dimension_eis(3,eps) for eps in DirichletGroup(48)]
572
[0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
573
sage: [Gamma1(48).dimension_eis(3,eps,algorithm="Quer") for eps in DirichletGroup(48)]
574
[0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
575
"""
576
from all import Gamma0
577
578
# first deal with special cases
579
580
if eps is None:
581
return GammaH_class.dimension_eis(self, k)
582
583
N = self.level()
584
eps = DirichletGroup(N)(eps)
585
586
if eps.is_trivial():
587
return Gamma0(N).dimension_eis(k)
588
589
# Note case of k = 0 and trivial character already dealt with separately, so k <= 0 here is valid:
590
if (k <= 0) or ((k % 2) == 1 and eps.is_even()) or ((k%2) == 0 and eps.is_odd()):
591
return ZZ(0)
592
593
if algorithm == "Quer":
594
n = eps.order()
595
dim = ZZ(0)
596
for d in n.divisors():
597
G = GammaH_constructor(N,(eps**d).kernel())
598
dim = dim + moebius(d)*G.dimension_eis(k)
599
return dim//phi(n)
600
601
elif algorithm == "CohenOesterle":
602
from sage.modular.dims import CohenOesterle
603
K = eps.base_ring()
604
j = 2-k
605
# We use the Cohen-Oesterle formula in a subtle way to
606
# compute dim M_k(N,eps) (see Ch. 6 of William Stein's book on
607
# computing with modular forms).
608
alpha = -ZZ( K(Gamma0(N).index()*(j-1)/ZZ(12)) + CohenOesterle(eps,j) )
609
if k == 1:
610
return alpha
611
else:
612
return alpha - self.dimension_cusp_forms(k, eps)
613
614
else: #algorithm not in ["CohenOesterle", "Quer"]:
615
raise ValueError, "Unrecognised algorithm in dimension_eis"
616
617
def dimension_new_cusp_forms(self, k=2, eps=None, p=0, algorithm="CohenOesterle"):
618
r"""
619
Dimension of the new subspace (or `p`-new subspace) of cusp forms of
620
weight `k` and character `\varepsilon`.
621
622
INPUT:
623
624
- ``k`` - an integer (default: 2)
625
626
- ``eps`` - a Dirichlet character
627
628
- ``p`` - a prime (default: 0); just the `p`-new subspace if given
629
630
- ``algorithm`` - either "CohenOesterle" (the default) or "Quer". This
631
specifies the method to use in the case of nontrivial character:
632
either the Cohen--Oesterle formula as described in Stein's book, or
633
by Moebius inversion using the subgroups GammaH (a method due to
634
Jordi Quer).
635
636
EXAMPLES::
637
638
sage: G = DirichletGroup(9)
639
sage: eps = G.0^3
640
sage: eps.conductor()
641
3
642
sage: [Gamma1(9).dimension_new_cusp_forms(k, eps) for k in [2..10]]
643
[0, 0, 0, 2, 0, 2, 0, 2, 0]
644
sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [2..10]]
645
[0, 0, 0, 2, 0, 4, 0, 6, 0]
646
sage: [Gamma1(9).dimension_new_cusp_forms(k, eps, 3) for k in [2..10]]
647
[0, 0, 0, 2, 0, 2, 0, 2, 0]
648
649
Double check using modular symbols (independent calculation)::
650
651
sage: [ModularSymbols(eps,k,sign=1).cuspidal_subspace().new_subspace().dimension() for k in [2..10]]
652
[0, 0, 0, 2, 0, 2, 0, 2, 0]
653
sage: [ModularSymbols(eps,k,sign=1).cuspidal_subspace().new_subspace(3).dimension() for k in [2..10]]
654
[0, 0, 0, 2, 0, 2, 0, 2, 0]
655
656
Another example at level 33::
657
658
sage: G = DirichletGroup(33)
659
sage: eps = G.1
660
sage: eps.conductor()
661
11
662
sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1) for k in [2..4]]
663
[0, 4, 0]
664
sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1, algorithm="Quer") for k in [2..4]]
665
[0, 4, 0]
666
sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1^2) for k in [2..4]]
667
[2, 0, 6]
668
sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1^2, p=3) for k in [2..4]]
669
[2, 0, 6]
670
671
"""
672
673
if eps == None:
674
return GammaH_class.dimension_new_cusp_forms(self, k, p)
675
676
N = self.level()
677
eps = DirichletGroup(N)(eps)
678
679
from all import Gamma0
680
681
if eps.is_trivial():
682
return Gamma0(N).dimension_new_cusp_forms(k, p)
683
684
from congroup_gammaH import mumu
685
686
if p == 0 or N%p != 0 or eps.conductor().valuation(p) == N.valuation(p):
687
D = [eps.conductor()*d for d in divisors(N//eps.conductor())]
688
return sum([Gamma1_constructor(M).dimension_cusp_forms(k, eps.restrict(M), algorithm)*mumu(N//M) for M in D])
689
eps_p = eps.restrict(N//p)
690
old = Gamma1_constructor(N//p).dimension_cusp_forms(k, eps_p, algorithm)
691
return self.dimension_cusp_forms(k, eps, algorithm) - 2*old
692
693
694
695