Bases: sage.groups.old.Group
Base class for arithmetic subgroups of . Not
intended to be used directly, but still includes quite a few
general-purpose routines which compute data about an arithmetic subgroup
assuming that it has a working element testing routine.
Test whether or not cusps x and y are equivalent modulo self. If self has a reduce_cusp() method, use that; otherwise do a slow explicit test.
If trans = False, returns True or False. If trans = True, then return either False or an element of self mapping x onto y.
EXAMPLE:
sage: Gamma0(7).are_equivalent(Cusp(1/3), Cusp(0), trans=True)
[ 3 -1]
[-14 5]
sage: Gamma0(7).are_equivalent(Cusp(1/3), Cusp(1/7))
False
Return self as an arithmetic subgroup defined in terms of the
permutation action of on its right cosets.
This method uses Todd-coxeter enumeration (via the method
todd_coxeter()) which can be extremely slow for arithmetic
subgroups with relatively large index in .
EXAMPLES:
sage: G = Gamma(3)
sage: P = G.as_permutation_group(); P
Arithmetic subgroup of index 24
sage: G.ncusps() == P.ncusps()
True
sage: G.nu2() == P.nu2()
True
sage: G.nu3() == P.nu3()
True
sage: G.an_element() in P
True
sage: P.an_element() in G
True
Return right coset representatives for self \ G, where G is another arithmetic subgroup that contains self. If G = None, default to G = SL2Z.
For generic arithmetic subgroups G this is carried out by Todd-Coxeter enumeration; here G is treated as a black box, implementing nothing but membership testing.
EXAMPLES:
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().coset_reps()
Traceback (most recent call last):
...
NotImplementedError
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.coset_reps(Gamma0(3))
[
[1 0] [ 0 -1] [ 0 -1] [ 0 -1]
[0 1], [ 1 0], [ 1 1], [ 1 2]
]
Return a triple (g, w, t) where g is an element of self generating the stabiliser of the given cusp, w is the width of the cusp, and t is 1 if the cusp is regular and -1 if not.
EXAMPLES:
sage: Gamma1(4).cusp_data(Cusps(1/2))
(
[ 1 -1]
[ 4 -3], 1, -1
)
Return the width of the orbit of cusps represented by c.
EXAMPLES:
sage: Gamma0(11).cusp_width(Cusps(oo))
1
sage: Gamma0(11).cusp_width(0)
11
sage: [Gamma0(100).cusp_width(c) for c in Gamma0(100).cusps()]
[100, 1, 4, 1, 1, 1, 4, 25, 1, 1, 4, 1, 25, 4, 1, 4, 1, 1]
Return a sorted list of inequivalent cusps for self, i.e. a set of
representatives for the orbits of self on .
These should be returned in a reduced form where this makes sense.
INPUTS:
EXAMPLES:
sage: Gamma0(36).cusps()
[0, 1/18, 1/12, 1/9, 1/6, 1/4, 1/3, 5/12, 1/2, 2/3, 5/6, Infinity]
sage: Gamma0(36).cusps(algorithm='modsym') == Gamma0(36).cusps()
True
sage: GammaH(36, [19,29]).cusps() == Gamma0(36).cusps()
True
sage: Gamma0(1).cusps()
[Infinity]
Return the dimension of the space of weight k cusp forms for this group. This is given by a standard formula in terms of k and various invariants of the group; see Diamond + Shurman, “A First Course in Modular Forms”, section 3.5 and 3.6. If k is not given, default to k = 2.
For dimensions of spaces of cusp forms with character for Gamma1, use the standalone function dimension_cusp_forms().
For weight 1 cusp forms this function only works in cases where one can prove solely in terms of Riemann-Roch theory that there aren’t any cusp forms (i.e. when the number of regular cusps is strictly greater than the degree of the canonical divisor). Otherwise a NotImplementedError is raised.
EXAMPLE:
sage: Gamma1(31).dimension_cusp_forms(2)
26
sage: Gamma1(3).dimension_cusp_forms(1)
0
sage: Gamma1(4).dimension_cusp_forms(1) # irregular cusp
0
sage: Gamma1(31).dimension_cusp_forms(1)
Traceback (most recent call last):
...
NotImplementedError: Computation of dimensions of weight 1 cusp forms spaces not implemented in general
Return the dimension of the space of weight k Eisenstein series for this group, which is a subspace of the space of modular forms complementary to the space of cusp forms.
INPUT:
EXAMPLES:
sage: GammaH(33,[2]).dimension_eis()
7
sage: GammaH(33,[2]).dimension_eis(3)
0
sage: GammaH(33, [2,5]).dimension_eis(2)
3
sage: GammaH(33, [4]).dimension_eis(1)
4
Return the dimension of the space of weight k modular forms for this group. This is given by a standard formula in terms of k and various invariants of the group; see Diamond + Shurman, “A First Course in Modular Forms”, section 3.5 and 3.6. If k is not given, defaults to k = 2.
For dimensions of spaces of modular forms with character for Gamma1, use the standalone function dimension_modular_forms().
For weight 1 modular forms this function only works in cases where one can prove solely in terms of Riemann-Roch theory that there aren’t any cusp forms (i.e. when the number of regular cusps is strictly greater than the degree of the canonical divisor). Otherwise a NotImplementedError is raised.
EXAMPLE:
sage: Gamma1(31).dimension_modular_forms(2)
55
sage: Gamma1(3).dimension_modular_forms(1)
1
sage: Gamma1(4).dimension_modular_forms(1) # irregular cusp
1
sage: Gamma1(31).dimension_modular_forms(1)
Traceback (most recent call last):
...
NotImplementedError: Computation of dimensions of weight 1 cusp forms spaces not implemented in general
Return the Farey symbol associated to this subgroup. See the farey_symbol module for more information.
EXAMPLE:
sage: Gamma1(4).farey_symbol()
FareySymbol(Congruence Subgroup Gamma1(4))
Return the i-th generator of self, i.e. the i-th element of the tuple self.gens().
EXAMPLES:
sage: SL2Z.gen(1)
[1 1]
[0 1]
Return the generalised level of self, i.e. the least common multiple of the widths of all cusps.
If self is even, Wohlfart’s theorem tells us that this is equal to the (conventional) level of self when self is a congruence subgroup. This can fail if self is odd, but the actual level is at most twice the generalised level. See the paper by Kiming, Schuett and Verrill for more examples.
EXAMPLE:
sage: Gamma0(18).generalised_level()
18
sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroup(5).index()
Traceback (most recent call last):
...
NotImplementedError
In the following example, the actual level is twice the generalised
level. This is the group from Example 17 of K-S-V.
sage: G = CongruenceSubgroup(8, [ [1,1,0,1], [3,-1,4,-1] ])
sage: G.level()
8
sage: G.generalised_level()
4
Return a list of generators for this congruence subgroup. The result is cached.
INPUT:
If algorithm is set to "farey", then the generators will be calculated using Farey symbols, which will always return a minimal generating set. See farey_symbol for more information.
If algorithm is set to "todd-coxeter", a simpler algorithm based on Todd-Coxeter enumeration will be used. This is exceedingly slow for general subgroups, and the list of generators will be far from minimal (indeed it may contain repetitions).
EXAMPLE:
sage: Gamma(2).generators()
[
[1 2] [ 3 -2] [-1 0]
[0 1], [ 2 -1], [ 0 -1]
]
sage: Gamma(2).generators(algorithm="todd-coxeter")
[
[1 2] [-1 0] [ 1 0] [-1 0] [-1 2] [-1 0] [1 0]
[0 1], [ 0 -1], [-2 1], [ 0 -1], [-2 3], [ 2 -1], [2 1]
]
Return a tuple of generators for this congruence subgroup.
The generators need not be minimal. For arguments, see generators().
EXAMPLES:
sage: SL2Z.gens()
(
[ 0 -1] [1 1]
[ 1 0], [0 1]
)
Return the genus of the modular curve of self.
EXAMPLES:
sage: Gamma1(5).genus()
0
sage: Gamma1(31).genus()
26
sage: Gamma1(157).genus() == dimension_cusp_forms(Gamma1(157), 2)
True
sage: GammaH(7, [2]).genus()
0
sage: [Gamma0(n).genus() for n in [1..23]]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 2, 2]
sage: [n for n in [1..200] if Gamma0(n).genus() == 1]
[11, 14, 15, 17, 19, 20, 21, 24, 27, 32, 36, 49]
Return the index of self in the full modular group.
EXAMPLES:
sage: Gamma0(17).index()
18
sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroup(5).index()
Traceback (most recent call last):
...
NotImplementedError
Return True if this arithmetic subgroup is abelian.
Since arithmetic subgroups are always nonabelian, this always returns False.
EXAMPLES:
sage: SL2Z.is_abelian()
False
sage: Gamma0(3).is_abelian()
False
sage: Gamma1(12).is_abelian()
False
sage: GammaH(4, [3]).is_abelian()
False
Return True if self is a congruence subgroup.
EXAMPLE:
sage: Gamma0(5).is_congruence()
True
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().is_congruence()
Traceback (most recent call last):
...
NotImplementedError
Return True precisely if this subgroup contains the matrix -1.
EXAMPLES:
sage: SL2Z.is_even()
True
sage: Gamma0(20).is_even()
True
sage: Gamma1(5).is_even()
False
sage: GammaH(11, [3]).is_even()
False
Return True if this arithmetic subgroup is finite.
Since arithmetic subgroups are always infinite, this always returns False.
EXAMPLES:
sage: SL2Z.is_finite()
False
sage: Gamma0(3).is_finite()
False
sage: Gamma1(12).is_finite()
False
sage: GammaH(4, [3]).is_finite()
False
Return True precisely if this subgroup is a normal subgroup of SL2Z.
EXAMPLES:
sage: Gamma(3).is_normal()
True
sage: Gamma1(3).is_normal()
False
Return True precisely if this subgroup does not contain the matrix -1.
EXAMPLES:
sage: SL2Z.is_odd()
False
sage: Gamma0(20).is_odd()
False
sage: Gamma1(5).is_odd()
True
sage: GammaH(11, [3]).is_odd()
True
Return True if the orbit of the given cusp is a regular cusp for self, otherwise False. This is automatically true if -1 is in self.
EXAMPLES:
sage: Gamma1(4).is_regular_cusp(Cusps(1/2))
False
sage: Gamma1(4).is_regular_cusp(Cusps(oo))
True
Return True if self is a subgroup of right, and False otherwise. For generic arithmetic subgroups this is done by the absurdly slow algorithm of checking all of the generators of self to see if they are in right.
EXAMPLES:
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().is_subgroup(SL2Z)
Traceback (most recent call last):
...
NotImplementedError
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.is_subgroup(Gamma1(18), Gamma0(6))
True
Return the number of cusps of this arithmetic subgroup. This is provided as a separate function since for dimension formulae in even weight all we need to know is the number of cusps, and this can be calculated very quickly, while enumerating all cusps is much slower.
EXAMPLES:
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.ncusps(Gamma0(7))
2
Return the size of the minimal generating set of self returned by generators().
EXAMPLES:
sage: Gamma0(22).ngens()
8
sage: Gamma1(14).ngens()
13
sage: GammaH(11, [3]).ngens()
3
sage: SL2Z.ngens()
2
Return the number of cusps of self that are “irregular”, i.e. their stabiliser can only be generated by elements with both eigenvalues -1 rather than +1. If the group contains -1, every cusp is clearly regular.
EXAMPLES:
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nirregcusps(Gamma1(4))
1
Return the number of cusps of self that are “regular”, i.e. their stabiliser has a generator with both eigenvalues +1 rather than -1. If the group contains -1, every cusp is clearly regular.
EXAMPLES:
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nregcusps(Gamma1(4))
2
Return the number of orbits of elliptic points of order 2 for this arithmetic subgroup.
EXAMPLES:
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().nu2()
Traceback (most recent call last):
...
NotImplementedError
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nu2(Gamma0(1105)) == 8
True
Return the number of orbits of elliptic points of order 3 for this arithmetic subgroup.
EXAMPLES:
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().nu3()
Traceback (most recent call last):
...
NotImplementedError
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nu3(Gamma0(1729)) == 8
True
We test that a bug in handling of subgroups not containing -1 is fixed:
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nu3(GammaH(7, [2]))
2
Return the number of elements in this arithmetic subgroup.
Since arithmetic subgroups are always infinite, this always returns infinity.
EXAMPLES:
sage: SL2Z.order()
+Infinity
sage: Gamma0(5).order()
+Infinity
sage: Gamma1(2).order()
+Infinity
sage: GammaH(12, [5]).order()
+Infinity
Return the index of the image of self in . This is equal
to the index of self if self contains -1, and half of this otherwise.
This is equal to the degree of the natural map from the modular curve
of self to the -line.
EXAMPLE:
sage: Gamma0(5).projective_index()
6
sage: Gamma1(5).projective_index()
12
Given a cusp , return the unique reduced cusp
equivalent to c under the action of self, where a reduced cusp is an
element
with r,s coprime non-negative integers, s as
small as possible, and r as small as possible for that s.
NOTE: This function should be overridden by all subclasses.
EXAMPLES:
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().reduce_cusp(1/4)
Traceback (most recent call last):
...
NotImplementedError
Returns the Sturm bound for modular forms of the given weight and level this subgroup.
INPUT:
FURTHER DETAILS: This function returns a positive integer
such that the Hecke operators
acting on cusp forms generate the
Hecke algebra as a
-module when the character
is trivial or quadratic. Otherwise,
generate the Hecke algebra at least as a
-module, where
is the ring generated by the
values of the Dirichlet character
.
Alternatively, this is a bound such that if two cusp forms
associated to this space of modular symbols are congruent modulo
, then they are congruent modulo
.
REFERENCES:
REMARK: Kevin Buzzard pointed out to me (William Stein) in Fall
2002 that the above bound is fine for with
character, as one sees by taking a power of
. More
precisely, if
for first
coefficients, then
for
first
coefficients. Since the weight of
is
, it follows that if
, where
is the Sturm bound for
at weight
, then
has valuation large enough to be forced to be
at
by Sturm bound (which is valid if we choose
correctly). Thus
.
Conclusion: For
with fixed character, the
Sturm bound is exactly the same as for
.
A key point is that we are finding
generators for the Hecke algebra
here, not
-generators. So if one wants
generators for the Hecke algebra over
, this
bound must be suitably modified (and I’m not sure what the
modification is).
AUTHORS:
Return the smallest even subgroup of containing self.
EXAMPLE:
sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().to_even_subgroup()
Traceback (most recent call last):
...
NotImplementedError
Compute coset representatives for self \ G and action of standard generators on them via Todd-Coxeter enumeration.
If G is None, default to SL2Z. The method also computes generators of the subgroup at same time.
INPUT:
This is extremely slow in general.
OUTPUT:
EXAMPLES:
sage: L = SL2Z([1,1,0,1])
sage: S = SL2Z([0,-1,1,0])
sage: G = Gamma(2)
sage: reps, gens, l, s = G.todd_coxeter()
sage: len(reps) == G.index()
True
sage: all(reps[i] * L * ~reps[l[i]] in G for i in xrange(6))
True
sage: all(reps[i] * S * ~reps[s[i]] in G for i in xrange(6))
True
sage: G = Gamma0(7)
sage: reps, gens, l, s = G.todd_coxeter()
sage: len(reps) == G.index()
True
sage: all(reps[i] * L * ~reps[l[i]] in G for i in xrange(8))
True
sage: all(reps[i] * S * ~reps[s[i]] in G for i in xrange(8))
True
sage: G = Gamma1(3)
sage: reps, gens, l, s = G.todd_coxeter(on_right=False)
sage: len(reps) == G.index()
True
sage: all(~reps[l[i]] * L * reps[i] in G for i in xrange(8))
True
sage: all(~reps[s[i]] * S * reps[i] in G for i in xrange(8))
True
sage: G = Gamma0(5)
sage: reps, gens, l, s = G.todd_coxeter(on_right=False)
sage: len(reps) == G.index()
True
sage: all(~reps[l[i]] * L * reps[i] in G for i in xrange(6))
True
sage: all(~reps[s[i]] * S * reps[i] in G for i in xrange(6))
True
Return True if x is of type ArithmeticSubgroup.
EXAMPLE:
sage: from sage.modular.arithgroup.all import is_ArithmeticSubgroup
sage: is_ArithmeticSubgroup(GL(2, GF(7)))
False
sage: is_ArithmeticSubgroup(Gamma0(4))
True