Congruence subgroup \(\Gamma_1(N)\)¶
- class sage.modular.arithgroup.congroup_gamma1.Gamma1_class(level)[source]¶
Bases:
GammaH_class
The congruence subgroup \(\Gamma_1(N)\).
- dimension_cusp_forms(k=2, eps=None, algorithm='CohenOesterle')[source]¶
Return the dimension of the space of cusp forms for
self
, or the dimension of the subspace corresponding to the given character if one is supplied.INPUT:
k
– integer (default: 2); the weighteps
– eitherNone
or a Dirichlet character modulo N, where N is the level of this group. If this isNone
, then the dimension of the whole space is returned; otherwise, the dimension of the subspace of forms of character eps.algorithm
– either'CohenOesterle'
(the default) or'Quer'
. This specifies the method to use in the case of nontrivial character: either the Cohen–Oesterle formula as described in Stein’s book, or by Möbius inversion using the subgroups GammaH (a method due to Jordi Quer). Ignored for weight 1.
EXAMPLES:
We compute the same dimension in two different ways
sage: # needs sage.rings.number_field sage: K = CyclotomicField(3) sage: eps = DirichletGroup(7*43,K).0^2 sage: G = Gamma1(7*43)
>>> from sage.all import * >>> # needs sage.rings.number_field >>> K = CyclotomicField(Integer(3)) >>> eps = DirichletGroup(Integer(7)*Integer(43),K).gen(0)**Integer(2) >>> G = Gamma1(Integer(7)*Integer(43))
Via Cohen–Oesterle:
sage: Gamma1(7*43).dimension_cusp_forms(2, eps) # needs sage.rings.number_field 28
>>> from sage.all import * >>> Gamma1(Integer(7)*Integer(43)).dimension_cusp_forms(Integer(2), eps) # needs sage.rings.number_field 28
Via Quer’s method:
sage: Gamma1(7*43).dimension_cusp_forms(2, eps, algorithm='Quer') # needs sage.rings.number_field 28
>>> from sage.all import * >>> Gamma1(Integer(7)*Integer(43)).dimension_cusp_forms(Integer(2), eps, algorithm='Quer') # needs sage.rings.number_field 28
Some more examples:
sage: G.<eps> = DirichletGroup(9) sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [1..10]] [0, 0, 1, 0, 3, 0, 5, 0, 7, 0] sage: [Gamma1(9).dimension_cusp_forms(k, eps^2) for k in [1..10]] [0, 0, 0, 2, 0, 4, 0, 6, 0, 8]
>>> from sage.all import * >>> G = DirichletGroup(Integer(9), names=('eps',)); (eps,) = G._first_ngens(1) >>> [Gamma1(Integer(9)).dimension_cusp_forms(k, eps) for k in (ellipsis_range(Integer(1),Ellipsis,Integer(10)))] [0, 0, 1, 0, 3, 0, 5, 0, 7, 0] >>> [Gamma1(Integer(9)).dimension_cusp_forms(k, eps**Integer(2)) for k in (ellipsis_range(Integer(1),Ellipsis,Integer(10)))] [0, 0, 0, 2, 0, 4, 0, 6, 0, 8]
In weight 1, we can sometimes rule out cusp forms existing via Riemann-Roch, but if this does not work, we trigger computation of the cusp forms space via Schaeffer’s algorithm:
sage: chi = [u for u in DirichletGroup(40) if u(-1) == -1 and u(21) == 1][0] sage: Gamma1(40).dimension_cusp_forms(1, chi) 0 sage: G = DirichletGroup(57); chi = (G.0) * (G.1)^6 sage: Gamma1(57).dimension_cusp_forms(1, chi) 1
>>> from sage.all import * >>> chi = [u for u in DirichletGroup(Integer(40)) if u(-Integer(1)) == -Integer(1) and u(Integer(21)) == Integer(1)][Integer(0)] >>> Gamma1(Integer(40)).dimension_cusp_forms(Integer(1), chi) 0 >>> G = DirichletGroup(Integer(57)); chi = (G.gen(0)) * (G.gen(1))**Integer(6) >>> Gamma1(Integer(57)).dimension_cusp_forms(Integer(1), chi) 1
- dimension_eis(k=2, eps=None, algorithm='CohenOesterle')[source]¶
Return the dimension of the space of Eisenstein series forms for self, or the dimension of the subspace corresponding to the given character if one is supplied.
INPUT:
k
– integer (default: 2); the weighteps
– eitherNone
or a Dirichlet character modulo N, where N is the level of this group. If this isNone
, then the dimension of the whole space is returned; otherwise, the dimension of the subspace of Eisenstein series of character eps.algorithm
– either'CohenOesterle'
(the default) or'Quer'
. This specifies the method to use in the case of nontrivial character: either the Cohen–Oesterle formula as described in Stein’s book, or by Möbius inversion using the subgroups GammaH (a method due to Jordi Quer).
AUTHORS:
William Stein - Cohen–Oesterle algorithm
Jordi Quer - algorithm based on GammaH subgroups
David Loeffler (2009) - code refactoring
EXAMPLES:
The following two computations use different algorithms:
sage: [Gamma1(36).dimension_eis(1,eps) for eps in DirichletGroup(36)] [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0] sage: [Gamma1(36).dimension_eis(1,eps,algorithm='Quer') for eps in DirichletGroup(36)] [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]
>>> from sage.all import * >>> [Gamma1(Integer(36)).dimension_eis(Integer(1),eps) for eps in DirichletGroup(Integer(36))] [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0] >>> [Gamma1(Integer(36)).dimension_eis(Integer(1),eps,algorithm='Quer') for eps in DirichletGroup(Integer(36))] [0, 4, 3, 0, 0, 2, 6, 0, 0, 2, 3, 0]
So do these:
sage: [Gamma1(48).dimension_eis(3,eps) for eps in DirichletGroup(48)] [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0] sage: [Gamma1(48).dimension_eis(3,eps,algorithm='Quer') for eps in DirichletGroup(48)] [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
>>> from sage.all import * >>> [Gamma1(Integer(48)).dimension_eis(Integer(3),eps) for eps in DirichletGroup(Integer(48))] [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0] >>> [Gamma1(Integer(48)).dimension_eis(Integer(3),eps,algorithm='Quer') for eps in DirichletGroup(Integer(48))] [0, 12, 0, 4, 0, 8, 0, 4, 12, 0, 4, 0, 8, 0, 4, 0]
- dimension_modular_forms(k=2, eps=None, algorithm='CohenOesterle')[source]¶
Return the dimension of the space of modular forms for
self
, or the dimension of the subspace corresponding to the given character if one is supplied.INPUT:
k
– integer (default: 2); the weighteps
– eitherNone
or a Dirichlet character modulo N, where N is the level of this group. If this isNone
, then the dimension of the whole space is returned; otherwise, the dimension of the subspace of forms of character eps.algorithm
– either'CohenOesterle'
(the default) or'Quer'
. This specifies the method to use in the case of nontrivial character: either the Cohen–Oesterle formula as described in Stein’s book, or by Möbius inversion using the subgroups GammaH (a method due to Jordi Quer).
EXAMPLES:
sage: # needs sage.rings.number_field sage: K = CyclotomicField(3) sage: eps = DirichletGroup(7*43,K).0^2 sage: G = Gamma1(7*43) sage: G.dimension_modular_forms(2, eps) 32 sage: G.dimension_modular_forms(2, eps, algorithm='Quer') 32
>>> from sage.all import * >>> # needs sage.rings.number_field >>> K = CyclotomicField(Integer(3)) >>> eps = DirichletGroup(Integer(7)*Integer(43),K).gen(0)**Integer(2) >>> G = Gamma1(Integer(7)*Integer(43)) >>> G.dimension_modular_forms(Integer(2), eps) 32 >>> G.dimension_modular_forms(Integer(2), eps, algorithm='Quer') 32
- dimension_new_cusp_forms(k=2, eps=None, p=0, algorithm='CohenOesterle')[source]¶
Dimension of the new subspace (or \(p\)-new subspace) of cusp forms of weight \(k\) and character \(\varepsilon\).
INPUT:
k
– integer (default: 2)eps
– a Dirichlet characterp
– a prime (default: 0); just the \(p\)-new subspace if givenalgorithm
– either'CohenOesterle'
(the default) or'Quer'
. This specifies the method to use in the case of nontrivial character: either the Cohen–Oesterle formula as described in Stein’s book, or by Möbius inversion using the subgroups GammaH (a method due to Jordi Quer).
EXAMPLES:
sage: G = DirichletGroup(9) sage: eps = G.0^3 sage: eps.conductor() 3 sage: [Gamma1(9).dimension_new_cusp_forms(k, eps) for k in [2..10]] [0, 0, 0, 2, 0, 2, 0, 2, 0] sage: [Gamma1(9).dimension_cusp_forms(k, eps) for k in [2..10]] [0, 0, 0, 2, 0, 4, 0, 6, 0] sage: [Gamma1(9).dimension_new_cusp_forms(k, eps, 3) for k in [2..10]] [0, 0, 0, 2, 0, 2, 0, 2, 0]
>>> from sage.all import * >>> G = DirichletGroup(Integer(9)) >>> eps = G.gen(0)**Integer(3) >>> eps.conductor() 3 >>> [Gamma1(Integer(9)).dimension_new_cusp_forms(k, eps) for k in (ellipsis_range(Integer(2),Ellipsis,Integer(10)))] [0, 0, 0, 2, 0, 2, 0, 2, 0] >>> [Gamma1(Integer(9)).dimension_cusp_forms(k, eps) for k in (ellipsis_range(Integer(2),Ellipsis,Integer(10)))] [0, 0, 0, 2, 0, 4, 0, 6, 0] >>> [Gamma1(Integer(9)).dimension_new_cusp_forms(k, eps, Integer(3)) for k in (ellipsis_range(Integer(2),Ellipsis,Integer(10)))] [0, 0, 0, 2, 0, 2, 0, 2, 0]
Double check using modular symbols (independent calculation):
sage: [ModularSymbols(eps,k,sign=1).cuspidal_subspace().new_subspace().dimension() for k in [2..10]] [0, 0, 0, 2, 0, 2, 0, 2, 0] sage: [ModularSymbols(eps,k,sign=1).cuspidal_subspace().new_subspace(3).dimension() for k in [2..10]] [0, 0, 0, 2, 0, 2, 0, 2, 0]
>>> from sage.all import * >>> [ModularSymbols(eps,k,sign=Integer(1)).cuspidal_subspace().new_subspace().dimension() for k in (ellipsis_range(Integer(2),Ellipsis,Integer(10)))] [0, 0, 0, 2, 0, 2, 0, 2, 0] >>> [ModularSymbols(eps,k,sign=Integer(1)).cuspidal_subspace().new_subspace(Integer(3)).dimension() for k in (ellipsis_range(Integer(2),Ellipsis,Integer(10)))] [0, 0, 0, 2, 0, 2, 0, 2, 0]
Another example at level 33:
sage: G = DirichletGroup(33) sage: eps = G.1 sage: eps.conductor() 11 sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1) for k in [2..4]] [0, 4, 0] sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1, algorithm='Quer') for k in [2..4]] [0, 4, 0] sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1^2) for k in [2..4]] [2, 0, 6] sage: [Gamma1(33).dimension_new_cusp_forms(k, G.1^2, p=3) for k in [2..4]] [2, 0, 6]
>>> from sage.all import * >>> G = DirichletGroup(Integer(33)) >>> eps = G.gen(1) >>> eps.conductor() 11 >>> [Gamma1(Integer(33)).dimension_new_cusp_forms(k, G.gen(1)) for k in (ellipsis_range(Integer(2),Ellipsis,Integer(4)))] [0, 4, 0] >>> [Gamma1(Integer(33)).dimension_new_cusp_forms(k, G.gen(1), algorithm='Quer') for k in (ellipsis_range(Integer(2),Ellipsis,Integer(4)))] [0, 4, 0] >>> [Gamma1(Integer(33)).dimension_new_cusp_forms(k, G.gen(1)**Integer(2)) for k in (ellipsis_range(Integer(2),Ellipsis,Integer(4)))] [2, 0, 6] >>> [Gamma1(Integer(33)).dimension_new_cusp_forms(k, G.gen(1)**Integer(2), p=Integer(3)) for k in (ellipsis_range(Integer(2),Ellipsis,Integer(4)))] [2, 0, 6]
- generators(algorithm='farey')[source]¶
Return generators for this congruence subgroup. The result is cached.
INPUT:
algorithm
– string; either'farey'
(default) or'todd-coxeter'
If
algorithm
is set to'farey'
, then the generators will be calculated using Farey symbols, which will always return a minimal generating set. Seefarey_symbol
for more information.If
algorithm
is set to'todd-coxeter'
, a simpler algorithm based on Todd-Coxeter enumeration will be used. This tends to return far larger sets of generators.EXAMPLES:
sage: Gamma1(3).generators() [ [1 1] [ 1 -1] [0 1], [ 3 -2] ] sage: Gamma1(3).generators(algorithm='todd-coxeter') [ [1 1] [-2 1] [1 1] [ 1 -1] [1 0] [1 1] [-5 2] [ 1 0] [0 1], [-3 1], [0 1], [ 0 1], [3 1], [0 1], [12 -5], [-3 1], [ 1 -1] [ 1 -1] [ 4 -1] [ -5 3] [ 3 -2], [ 3 -2], [ 9 -2], [-12 7] ]
>>> from sage.all import * >>> Gamma1(Integer(3)).generators() [ [1 1] [ 1 -1] [0 1], [ 3 -2] ] >>> Gamma1(Integer(3)).generators(algorithm='todd-coxeter') [ [1 1] [-2 1] [1 1] [ 1 -1] [1 0] [1 1] [-5 2] [ 1 0] [0 1], [-3 1], [0 1], [ 0 1], [3 1], [0 1], [12 -5], [-3 1], <BLANKLINE> [ 1 -1] [ 1 -1] [ 4 -1] [ -5 3] [ 3 -2], [ 3 -2], [ 9 -2], [-12 7] ]
- index()[source]¶
Return the index of
self
in the full modular group. This is given by the formula\[\begin{split}N^2 \prod_{\substack{p \mid N \\ \text{$p$ prime}}} \left( 1 - \frac{1}{p^2}\right).\end{split}\]EXAMPLES:
sage: Gamma1(180).index() 20736 sage: [Gamma1(n).projective_index() for n in [1..16]] [1, 3, 4, 6, 12, 12, 24, 24, 36, 36, 60, 48, 84, 72, 96, 96]
>>> from sage.all import * >>> Gamma1(Integer(180)).index() 20736 >>> [Gamma1(n).projective_index() for n in (ellipsis_range(Integer(1),Ellipsis,Integer(16)))] [1, 3, 4, 6, 12, 12, 24, 24, 36, 36, 60, 48, 84, 72, 96, 96]
- is_even()[source]¶
Return
True
precisely if this subgroup contains the matrix -1.EXAMPLES:
sage: Gamma1(1).is_even() True sage: Gamma1(2).is_even() True sage: Gamma1(15).is_even() False
>>> from sage.all import * >>> Gamma1(Integer(1)).is_even() True >>> Gamma1(Integer(2)).is_even() True >>> Gamma1(Integer(15)).is_even() False
- is_subgroup(right)[source]¶
Return
True
ifself
is a subgroup ofright
.EXAMPLES:
sage: Gamma1(3).is_subgroup(SL2Z) True sage: Gamma1(3).is_subgroup(Gamma1(5)) False sage: Gamma1(3).is_subgroup(Gamma1(6)) False sage: Gamma1(6).is_subgroup(Gamma1(3)) True sage: Gamma1(6).is_subgroup(Gamma0(2)) True sage: Gamma1(80).is_subgroup(GammaH(40, [])) True sage: Gamma1(80).is_subgroup(GammaH(40, [21])) True
>>> from sage.all import * >>> Gamma1(Integer(3)).is_subgroup(SL2Z) True >>> Gamma1(Integer(3)).is_subgroup(Gamma1(Integer(5))) False >>> Gamma1(Integer(3)).is_subgroup(Gamma1(Integer(6))) False >>> Gamma1(Integer(6)).is_subgroup(Gamma1(Integer(3))) True >>> Gamma1(Integer(6)).is_subgroup(Gamma0(Integer(2))) True >>> Gamma1(Integer(80)).is_subgroup(GammaH(Integer(40), [])) True >>> Gamma1(Integer(80)).is_subgroup(GammaH(Integer(40), [Integer(21)])) True
- ncusps()[source]¶
Return the number of cusps of this subgroup \(\Gamma_1(N)\).
EXAMPLES:
sage: [Gamma1(n).ncusps() for n in [1..15]] [1, 2, 2, 3, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 16] sage: [Gamma1(n).ncusps() for n in prime_range(2, 100)] [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]
>>> from sage.all import * >>> [Gamma1(n).ncusps() for n in (ellipsis_range(Integer(1),Ellipsis,Integer(15)))] [1, 2, 2, 3, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 16] >>> [Gamma1(n).ncusps() for n in prime_range(Integer(2), Integer(100))] [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]
- nu2()[source]¶
Calculate the number of orbits of elliptic points of order 2 for this subgroup \(\Gamma_1(N)\). This is known to be 0 if N > 2.
EXAMPLES:
sage: Gamma1(2).nu2() 1 sage: Gamma1(457).nu2() 0 sage: [Gamma1(n).nu2() for n in [1..16]] [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> from sage.all import * >>> Gamma1(Integer(2)).nu2() 1 >>> Gamma1(Integer(457)).nu2() 0 >>> [Gamma1(n).nu2() for n in (ellipsis_range(Integer(1),Ellipsis,Integer(16)))] [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
- nu3()[source]¶
Calculate the number of orbits of elliptic points of order 3 for this subgroup \(\Gamma_1(N)\). This is known to be 0 if N > 3.
EXAMPLES:
sage: Gamma1(2).nu3() 0 sage: Gamma1(3).nu3() 1 sage: Gamma1(457).nu3() 0 sage: [Gamma1(n).nu3() for n in [1..10]] [1, 0, 1, 0, 0, 0, 0, 0, 0, 0]
>>> from sage.all import * >>> Gamma1(Integer(2)).nu3() 0 >>> Gamma1(Integer(3)).nu3() 1 >>> Gamma1(Integer(457)).nu3() 0 >>> [Gamma1(n).nu3() for n in (ellipsis_range(Integer(1),Ellipsis,Integer(10)))] [1, 0, 1, 0, 0, 0, 0, 0, 0, 0]
- sage.modular.arithgroup.congroup_gamma1.Gamma1_constructor(N)[source]¶
Return the congruence subgroup \(\Gamma_1(N)\).
EXAMPLES:
sage: Gamma1(5) # indirect doctest Congruence Subgroup Gamma1(5) sage: G = Gamma1(23) sage: G is Gamma1(23) True sage: G is GammaH(23, [1]) True sage: TestSuite(G).run() sage: G is loads(dumps(G)) True
>>> from sage.all import * >>> Gamma1(Integer(5)) # indirect doctest Congruence Subgroup Gamma1(5) >>> G = Gamma1(Integer(23)) >>> G is Gamma1(Integer(23)) True >>> G is GammaH(Integer(23), [Integer(1)]) True >>> TestSuite(G).run() >>> G is loads(dumps(G)) True
- sage.modular.arithgroup.congroup_gamma1.is_Gamma1(x)[source]¶
Return
True
if x is a congruence subgroup of type Gamma1.EXAMPLES:
sage: from sage.modular.arithgroup.all import is_Gamma1 sage: is_Gamma1(SL2Z) doctest:warning... DeprecationWarning: The function is_Gamma1 is deprecated; use 'isinstance(..., Gamma1_class)' instead. See https://github.com/sagemath/sage/issues/38035 for details. False sage: is_Gamma1(Gamma1(13)) True sage: is_Gamma1(Gamma0(6)) False sage: is_Gamma1(GammaH(12, [])) # trick question! True sage: is_Gamma1(GammaH(12, [5])) False
>>> from sage.all import * >>> from sage.modular.arithgroup.all import is_Gamma1 >>> is_Gamma1(SL2Z) doctest:warning... DeprecationWarning: The function is_Gamma1 is deprecated; use 'isinstance(..., Gamma1_class)' instead. See https://github.com/sagemath/sage/issues/38035 for details. False >>> is_Gamma1(Gamma1(Integer(13))) True >>> is_Gamma1(Gamma0(Integer(6))) False >>> is_Gamma1(GammaH(Integer(12), [])) # trick question! True >>> is_Gamma1(GammaH(Integer(12), [Integer(5)])) False