Path: blob/master/sage/modular/arithgroup/arithgroup_generic.py
4057 views
r"""1Arithmetic subgroups (finite index subgroups of `{\rm SL}_2(\ZZ)`)2"""34################################################################################5#6# Copyright (C) 2009, The Sage Group -- http://www.sagemath.org/7#8# Distributed under the terms of the GNU General Public License (GPL)9#10# The full text of the GPL is available at:11#12# http://www.gnu.org/licenses/13#14################################################################################151617import sage.groups.group as group18from sage.rings.all import ZZ19import sage.rings.arith as arith20from sage.misc.cachefunc import cached_method21from copy import copy # for making copies of lists of cusps22from sage.modular.modsym.p1list import lift_to_sl2z23from sage.modular.cusps import Cusp2425def is_ArithmeticSubgroup(x):26r"""27Return True if x is of type ArithmeticSubgroup.2829EXAMPLE::3031sage: from sage.modular.arithgroup.all import is_ArithmeticSubgroup32sage: is_ArithmeticSubgroup(GL(2, GF(7)))33False34sage: is_ArithmeticSubgroup(Gamma0(4))35True36"""3738return isinstance(x, ArithmeticSubgroup)394041class ArithmeticSubgroup(group.Group):42r"""43Base class for arithmetic subgroups of `{\rm SL}_2(\ZZ)`. Not44intended to be used directly, but still includes quite a few45general-purpose routines which compute data about an arithmetic subgroup46assuming that it has a working element testing routine.47"""4849def __init__(self):50r"""51Standard init routine.5253EXAMPLE::5455sage: G = Gamma1(7)56sage: G.category() # indirect doctest57Category of groups58"""59group.Group.__init__(self)6061def _repr_(self):62r"""63Return the string representation of self.6465NOTE: This function should be overridden by all subclasses.6667EXAMPLES::6869sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup()._repr_()70'Generic arithmetic subgroup of SL2Z'71"""72return "Generic arithmetic subgroup of SL2Z"7374def __reduce__(self):75r"""76Used for pickling self.7778NOTE: This function should be overridden by all subclasses.7980EXAMPLES::8182sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().__reduce__()83Traceback (most recent call last):84...85NotImplementedError: all subclasses must define a __reduce__ method86"""87raise NotImplementedError, "all subclasses must define a __reduce__ method"8889def __hash__(self):90r"""91Return a hash of self.9293EXAMPLES::9495sage: Gamma0(11).__hash__()96-545929996 # 32-bit97466678398374495476 # 64-bit98sage: Gamma1(11).__hash__()99-830809815 # 32-bit1004909638266971150633 # 64-bit101"""102return hash(str(self))103104def coset_reps(self, G=None):105r"""106Return right coset representatives for self \\ G, where G is another107arithmetic subgroup that contains self. If G = None, default to G =108SL2Z.109110For generic arithmetic subgroups G this is carried out by Todd-Coxeter111enumeration; here G is treated as a black box, implementing nothing but112membership testing.113114EXAMPLES::115116sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().coset_reps()117Traceback (most recent call last):118...119NotImplementedError120sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.coset_reps(Gamma0(3))121[122[1 0] [ 0 -1] [ 0 -1] [ 0 -1]123[0 1], [ 1 0], [ 1 1], [ 1 2]124]125"""126return self.todd_coxeter(G)[0]127128@cached_method129def todd_coxeter(self, G=None, on_right=True):130r"""131Compute coset representatives for self \\ G and action of standard132generators on them via Todd-Coxeter enumeration.133134If ``G`` is ``None``, default to ``SL2Z``. The method also computes135generators of the subgroup at same time.136137INPUT:138139- ``G`` - intermediate subgroup (currently not implemented if diffferent140from SL(2,Z))141142- ``on_right`` - boolean (default: True) - if True return right coset143enumeration, if False return left one.144145This is *extremely* slow in general.146147OUTPUT:148149- a list of coset representatives150151- a list of generators for the group152153- ``l`` - list of integers that correspond to the action of the154standard parabolic element [[1,1],[0,1]] of `SL(2,\ZZ)` on the cosets155of self.156157- ``s`` - list of integers that correspond to the action of the standard158element of order `2` [[0,-1],[1,0]] on the cosets of self.159160EXAMPLES::161162sage: L = SL2Z([1,1,0,1])163sage: S = SL2Z([0,-1,1,0])164165sage: G = Gamma(2)166sage: reps, gens, l, s = G.todd_coxeter()167sage: len(reps) == G.index()168True169sage: all(reps[i] * L * ~reps[l[i]] in G for i in xrange(6))170True171sage: all(reps[i] * S * ~reps[s[i]] in G for i in xrange(6))172True173174sage: G = Gamma0(7)175sage: reps, gens, l, s = G.todd_coxeter()176sage: len(reps) == G.index()177True178sage: all(reps[i] * L * ~reps[l[i]] in G for i in xrange(8))179True180sage: all(reps[i] * S * ~reps[s[i]] in G for i in xrange(8))181True182183sage: G = Gamma1(3)184sage: reps, gens, l, s = G.todd_coxeter(on_right=False)185sage: len(reps) == G.index()186True187sage: all(~reps[l[i]] * L * reps[i] in G for i in xrange(8))188True189sage: all(~reps[s[i]] * S * reps[i] in G for i in xrange(8))190True191192sage: G = Gamma0(5)193sage: reps, gens, l, s = G.todd_coxeter(on_right=False)194sage: len(reps) == G.index()195True196sage: all(~reps[l[i]] * L * reps[i] in G for i in xrange(6))197True198sage: all(~reps[s[i]] * S * reps[i] in G for i in xrange(6))199True200"""201from all import SL2Z202203if G is None:204G = SL2Z205if G != SL2Z:206raise NotImplementedError, "Don't know how to compute coset reps for subgroups yet"207208id = SL2Z([1,0,0,1])209l = SL2Z([1,1,0,1])210s = SL2Z([0,-1,1,0])211212reps = [id] # coset representatives213reps_inv = {id:0} # coset representatives index214215l_wait_back = [id] # rep with no incoming s_edge216s_wait_back = [id] # rep with no incoming l_edge217l_wait = [id] # rep with no outgoing l_edge218s_wait = [id] # rep with no outgoing s_edge219220l_edges = [None] # edges for l221s_edges = [None] # edges for s222223gens = []224225while l_wait or s_wait:226if l_wait:227x = l_wait.pop(0)228y = x229not_end = True230while not_end:231if on_right:232y = y*l233else:234y = l*y235for i in xrange(len(l_wait_back)):236v = l_wait_back[i]237if on_right:238yy = y*~v239else:240yy = ~v*y241if yy in self:242l_edges[reps_inv[x]] = reps_inv[v]243del l_wait_back[i]244if yy != id:245gens.append(self(yy))246not_end = False247break248else:249reps_inv[y] = len(reps)250l_edges[reps_inv[x]] = len(reps)251reps.append(y)252l_edges.append(None)253s_edges.append(None)254s_wait_back.append(y)255s_wait.append(y)256x = y257258if s_wait:259x = s_wait.pop(0)260y = x261not_end = True262while not_end:263if on_right:264y = y*s265else:266y = s*y267for i in xrange(len(s_wait_back)):268v = s_wait_back[i]269if on_right:270yy = y*~v271else:272yy = ~v*y273if yy in self:274s_edges[reps_inv[x]] = reps_inv[v]275del s_wait_back[i]276if yy != id:277gens.append(self(yy))278not_end = False279break280else:281reps_inv[y] = len(reps)282s_edges[reps_inv[x]] = len(reps)283reps.append(y)284l_edges.append(None)285s_edges.append(None)286l_wait_back.append(y)287l_wait.append(y)288x = y289290return reps, gens, l_edges, s_edges291292def nu2(self):293r"""294Return the number of orbits of elliptic points of order 2 for this295arithmetic subgroup.296297EXAMPLES::298299sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().nu2()300Traceback (most recent call last):301...302NotImplementedError303sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nu2(Gamma0(1105)) == 8304True305"""306307# Subgroups not containing -1 have no elliptic points of order 2.308309if not self.is_even():310return 0311312# Cheap trick: if self is a subgroup of something with no elliptic points,313# then self has no elliptic points either.314315from all import Gamma0, is_CongruenceSubgroup316if is_CongruenceSubgroup(self):317if self.is_subgroup(Gamma0(self.level())) and Gamma0(self.level()).nu2() == 0:318return 0319320# Otherwise, the number of elliptic points is the number of g in self \321# SL2Z such that the stabiliser of g * i in self is not trivial. (Note322# that the points g*i for g in the coset reps are not distinct, but it323# still works, since the failure of these points to be distinct happens324# precisely when the preimages are not elliptic.)325326from all import SL2Z327count = 0328for g in self.coset_reps():329if g * SL2Z([0,1,-1,0]) * (~g) in self:330count += 1331return count332333def nu3(self):334r"""335Return the number of orbits of elliptic points of order 3 for this336arithmetic subgroup.337338EXAMPLES::339340sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().nu3()341Traceback (most recent call last):342...343NotImplementedError344sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nu3(Gamma0(1729)) == 8345True346347We test that a bug in handling of subgroups not containing -1 is fixed: ::348349sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nu3(GammaH(7, [2]))3502351"""352353# Cheap trick: if self is a subgroup of something with no elliptic points,354# then self has no elliptic points either.355356from all import Gamma0, is_CongruenceSubgroup357if is_CongruenceSubgroup(self):358if self.is_subgroup(Gamma0(self.level())) and Gamma0(self.level()).nu3() == 0:359return 0360361from all import SL2Z362count = 0363for g in self.coset_reps():364if g * SL2Z([0,1,-1,-1]) * (~g) in self:365count += 1366367if self.is_even():368return count369else:370return count/2371372def __cmp__(self, other):373r"""374Compare self to other.375376NOTE: This function must be overridden by all subclasses.377378EXAMPLES::379380sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().__cmp__(ZZ)381Traceback (most recent call last):382...383NotImplementedError384"""385raise NotImplementedError386387def is_abelian(self):388r"""389Return True if this arithmetic subgroup is abelian.390391Since arithmetic subgroups are always nonabelian, this always392returns False.393394EXAMPLES::395396sage: SL2Z.is_abelian()397False398sage: Gamma0(3).is_abelian()399False400sage: Gamma1(12).is_abelian()401False402sage: GammaH(4, [3]).is_abelian()403False404"""405return False406407def is_finite(self):408r"""409Return True if this arithmetic subgroup is finite.410411Since arithmetic subgroups are always infinite, this always412returns False.413414EXAMPLES::415416sage: SL2Z.is_finite()417False418sage: Gamma0(3).is_finite()419False420sage: Gamma1(12).is_finite()421False422sage: GammaH(4, [3]).is_finite()423False424"""425return False426427def is_subgroup(self, right):428r"""429Return True if self is a subgroup of right, and False otherwise. For430generic arithmetic subgroups this is done by the absurdly slow431algorithm of checking all of the generators of self to see if they are432in right.433434EXAMPLES::435436sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().is_subgroup(SL2Z)437Traceback (most recent call last):438...439NotImplementedError440sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.is_subgroup(Gamma1(18), Gamma0(6))441True442"""443# ridiculously slow generic algorithm444445w = self.gens()446for g in w:447if not (g in right):448return False449return True450451def is_normal(self):452r"""453Return True precisely if this subgroup is a normal subgroup of SL2Z.454455EXAMPLES::456457sage: Gamma(3).is_normal()458True459sage: Gamma1(3).is_normal()460False461"""462from all import SL2Z463for x in self.gens():464for y in SL2Z.gens():465if y*SL2Z(x)*(~y) not in self:466return False467return True468469def is_odd(self):470r"""471Return True precisely if this subgroup does not contain the472matrix -1.473474EXAMPLES::475476sage: SL2Z.is_odd()477False478sage: Gamma0(20).is_odd()479False480sage: Gamma1(5).is_odd()481True482sage: GammaH(11, [3]).is_odd()483True484"""485return not self.is_even()486487def is_even(self):488r"""489Return True precisely if this subgroup contains the matrix -1.490491EXAMPLES::492493sage: SL2Z.is_even()494True495sage: Gamma0(20).is_even()496True497sage: Gamma1(5).is_even()498False499sage: GammaH(11, [3]).is_even()500False501"""502return [-1, 0, 0, -1] in self503504def to_even_subgroup(self):505r"""506Return the smallest even subgroup of `SL(2, \ZZ)` containing self.507508EXAMPLE::509510sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().to_even_subgroup()511Traceback (most recent call last):512...513NotImplementedError514"""515if self.is_even():516return self517else:518raise NotImplementedError519520def order(self):521r"""522Return the number of elements in this arithmetic subgroup.523524Since arithmetic subgroups are always infinite, this always returns525infinity.526527EXAMPLES::528529sage: SL2Z.order()530+Infinity531sage: Gamma0(5).order()532+Infinity533sage: Gamma1(2).order()534+Infinity535sage: GammaH(12, [5]).order()536+Infinity537"""538from sage.rings.infinity import infinity539return infinity540541def reduce_cusp(self, c):542r"""543Given a cusp `c \in \mathbb{P}^1(\QQ)`, return the unique reduced cusp544equivalent to c under the action of self, where a reduced cusp is an545element `\tfrac{r}{s}` with r,s coprime non-negative integers, s as546small as possible, and r as small as possible for that s.547548NOTE: This function should be overridden by all subclasses.549550EXAMPLES::551552sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().reduce_cusp(1/4)553Traceback (most recent call last):554...555NotImplementedError556"""557raise NotImplementedError558559def cusps(self, algorithm='default'):560r"""561Return a sorted list of inequivalent cusps for self, i.e. a set of562representatives for the orbits of self on `\mathbb{P}^1(\QQ)`.563These should be returned in a reduced form where this makes sense.564565INPUTS:566567- ``algorithm`` -- which algorithm to use to compute the cusps of self.568``'default'`` finds representatives for a known complete set of569cusps. ``'modsym'`` computes the boundary map on the space of weight570two modular symbols associated to self, which finds the cusps for571self in the process.572573EXAMPLES::574575sage: Gamma0(36).cusps()576[0, 1/18, 1/12, 1/9, 1/6, 1/4, 1/3, 5/12, 1/2, 2/3, 5/6, Infinity]577sage: Gamma0(36).cusps(algorithm='modsym') == Gamma0(36).cusps()578True579sage: GammaH(36, [19,29]).cusps() == Gamma0(36).cusps()580True581sage: Gamma0(1).cusps()582[Infinity]583"""584try:585return copy(self._cusp_list[algorithm])586except (AttributeError,KeyError):587self._cusp_list = {}588589from congroup_sl2z import is_SL2Z590if is_SL2Z(self):591from sage.modular.cusps import Cusp592s = [Cusp(1,0)]593594if algorithm == 'default':595s = self._find_cusps()596elif algorithm == 'modsym':597s = sorted([self.reduce_cusp(c) for c in self.modular_symbols().cusps()])598else:599raise ValueError, "unknown algorithm: %s"%algorithm600601self._cusp_list[algorithm] = s602return copy(s)603604def _find_cusps(self):605r"""606Calculate a list of inequivalent cusps.607608EXAMPLES::609610sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroup(5)._find_cusps()611Traceback (most recent call last):612...613NotImplementedError614615NOTE: There is a generic algorithm implemented at the top level that616uses the coset representatives of self. This is *very slow* and for all617the standard congruence subgroups there is a quicker way of doing it,618so this should usually be overridden in subclasses; but it doesn't have619to be.620"""621from sage.modular.cusps import Cusp622i = Cusp([1,0])623L = [i]624for a in self.coset_reps():625ai = i.apply([a.a(), a.b(), a.c(), a.d()])626new = 1627for v in L:628if self.are_equivalent(ai, v):629new = 0630break631if new == 1:632L.append(ai)633return L634635def are_equivalent(self, x, y, trans = False):636r"""637Test whether or not cusps x and y are equivalent modulo self. If self638has a reduce_cusp() method, use that; otherwise do a slow explicit639test.640641If trans = False, returns True or False. If trans = True, then return642either False or an element of self mapping x onto y.643644EXAMPLE::645646sage: Gamma0(7).are_equivalent(Cusp(1/3), Cusp(0), trans=True)647[ 3 -1]648[-14 5]649sage: Gamma0(7).are_equivalent(Cusp(1/3), Cusp(1/7))650False651"""652x = Cusp(x)653y = Cusp(y)654if not trans:655try:656xr = self.reduce_cusp(x)657yr = self.reduce_cusp(y)658if xr != yr:659return False660if xr == yr:661return True662except NotImplementedError:663pass664665from all import SL2Z666667vx = lift_to_sl2z(x.numerator(),x.denominator(), 0)668dx = SL2Z([vx[2], -vx[0], vx[3], -vx[1]])669vy = lift_to_sl2z(y.numerator(),y.denominator(), 0)670dy = SL2Z([vy[2], -vy[0], vy[3], -vy[1]])671672for i in xrange(self.index()):673# Note that the width of any cusp is bounded above by the index of self.674# If self is congruence, then the level of self is a much better bound, but675# this method is written to work with non-congruence subgroups as well,676if dy * SL2Z([1,i,0,1])*(~dx) in self:677if trans:678return dy * SL2Z([1,i,0,1]) * ~dx679else:680return True681elif (self.is_odd() and dy * SL2Z([-1,-i,0,-1]) * ~dx in self):682if trans:683return dy * SL2Z([-1,-i,0,-1]) * ~dx684else:685return True686return False687688def cusp_data(self, c):689r"""690Return a triple (g, w, t) where g is an element of self generating the691stabiliser of the given cusp, w is the width of the cusp, and t is 1 if692the cusp is regular and -1 if not.693694EXAMPLES::695696sage: Gamma1(4).cusp_data(Cusps(1/2))697(698[ 1 -1]699[ 4 -3], 1, -1700)701"""702c = Cusp(c)703from all import SL2Z # can't import at top as that would cause a circular import704705# first find an element of SL2Z sending infinity to the given cusp706w = lift_to_sl2z(c.denominator(), c.numerator(), 0)707g = SL2Z([w[3], w[1], w[2],w[0]])708709for d in xrange(1,1+self.index()):710if g * SL2Z([1,d,0,1]) * (~g) in self:711return (g * SL2Z([1,d,0,1]) * (~g), d, 1)712elif g * SL2Z([-1,-d,0,-1]) * (~g) in self:713return (g * SL2Z([-1,-d,0,-1]) * (~g), d, -1)714raise ArithmeticError, "Can't get here!"715716def is_regular_cusp(self, c):717r"""718Return True if the orbit of the given cusp is a regular cusp for self,719otherwise False. This is automatically true if -1 is in self.720721EXAMPLES::722723sage: Gamma1(4).is_regular_cusp(Cusps(1/2))724False725sage: Gamma1(4).is_regular_cusp(Cusps(oo))726True727"""728if self.is_even(): return True729return (self.cusp_data(c)[2] == 1)730731def cusp_width(self, c):732r"""733Return the width of the orbit of cusps represented by c.734735EXAMPLES::736737sage: Gamma0(11).cusp_width(Cusps(oo))7381739sage: Gamma0(11).cusp_width(0)74011741sage: [Gamma0(100).cusp_width(c) for c in Gamma0(100).cusps()]742[100, 1, 4, 1, 1, 1, 4, 25, 1, 1, 4, 1, 25, 4, 1, 4, 1, 1]743"""744return self.cusp_data(c)[1]745746def index(self):747r"""748Return the index of self in the full modular group.749750EXAMPLES::751752sage: Gamma0(17).index()75318754sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroup(5).index()755Traceback (most recent call last):756...757NotImplementedError758"""759760return len(list(self.coset_reps()))761762def generalised_level(self):763r"""764Return the generalised level of self, i.e. the least common multiple of765the widths of all cusps.766767If self is *even*, Wohlfart's theorem tells us that this is equal to768the (conventional) level of self when self is a congruence subgroup.769This can fail if self is odd, but the actual level is at most twice the770generalised level. See the paper by Kiming, Schuett and Verrill for771more examples.772773EXAMPLE::774775sage: Gamma0(18).generalised_level()77618777sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroup(5).index()778Traceback (most recent call last):779...780NotImplementedError781782In the following example, the actual level is twice the generalised783level. This is the group `G_2` from Example 17 of K-S-V.784785::786787sage: G = CongruenceSubgroup(8, [ [1,1,0,1], [3,-1,4,-1] ])788sage: G.level()7898790sage: G.generalised_level()7914792"""793return arith.lcm([self.cusp_width(c) for c in self.cusps()])794795def projective_index(self):796r"""797Return the index of the image of self in `{\rm PSL}_2(\ZZ)`. This is equal798to the index of self if self contains -1, and half of this otherwise.799800This is equal to the degree of the natural map from the modular curve801of self to the `j`-line.802803EXAMPLE::804805sage: Gamma0(5).projective_index()8066807sage: Gamma1(5).projective_index()80812809"""810811if self.is_even():812return self.index()813else:814return self.index() // 2815816def is_congruence(self):817r"""818Return True if self is a congruence subgroup.819820EXAMPLE::821822sage: Gamma0(5).is_congruence()823True824sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().is_congruence()825Traceback (most recent call last):826...827NotImplementedError828"""829830raise NotImplementedError831832def genus(self):833r"""834Return the genus of the modular curve of self.835836EXAMPLES::837838sage: Gamma1(5).genus()8390840sage: Gamma1(31).genus()84126842sage: Gamma1(157).genus() == dimension_cusp_forms(Gamma1(157), 2)843True844sage: GammaH(7, [2]).genus()8450846sage: [Gamma0(n).genus() for n in [1..23]]847[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 2, 2]848sage: [n for n in [1..200] if Gamma0(n).genus() == 1]849[11, 14, 15, 17, 19, 20, 21, 24, 27, 32, 36, 49]850851852"""853854return ZZ(1 + (self.projective_index()) / ZZ(12) - (self.nu2())/ZZ(4) - (self.nu3())/ZZ(3) - self.ncusps()/ZZ(2))855856def farey_symbol(self):857r"""858Return the Farey symbol associated to this subgroup. See the859:mod:`~sage.modular.arithgroup.farey_symbol` module for more860information.861862EXAMPLE::863864sage: Gamma1(4).farey_symbol()865FareySymbol(Congruence Subgroup Gamma1(4))866"""867from farey_symbol import Farey868return Farey(self)869870@cached_method871def generators(self, algorithm="farey"):872r"""873Return a list of generators for this congruence subgroup. The result is cached.874875INPUT:876877- ``algorithm`` (string): either ``farey`` or ``todd-coxeter``.878879If ``algorithm`` is set to ``"farey"``, then the generators will be880calculated using Farey symbols, which will always return a *minimal*881generating set. See :mod:`~sage.modular.arithgroup.farey_symbol` for882more information.883884If ``algorithm`` is set to ``"todd-coxeter"``, a simpler algorithm885based on Todd-Coxeter enumeration will be used. This is *exceedingly*886slow for general subgroups, and the list of generators will be far from887minimal (indeed it may contain repetitions).888889EXAMPLE::890891sage: Gamma(2).generators()892[893[1 2] [ 3 -2] [-1 0]894[0 1], [ 2 -1], [ 0 -1]895]896sage: Gamma(2).generators(algorithm="todd-coxeter")897[898[1 2] [-1 0] [ 1 0] [-1 0] [-1 2] [-1 0] [1 0]899[0 1], [ 0 -1], [-2 1], [ 0 -1], [-2 3], [ 2 -1], [2 1]900]901"""902if algorithm=="farey":903return self.farey_symbol().generators()904elif algorithm == "todd-coxeter":905return self.todd_coxeter()[1]906else:907raise ValueError, "Unknown algorithm '%s' (should be either 'farey' or 'todd-coxeter')" % algorithm908909def gens(self, *args, **kwds):910r"""911Return a tuple of generators for this congruence subgroup.912913The generators need not be minimal. For arguments, see :meth:`~generators`.914915EXAMPLES::916917sage: SL2Z.gens()918(919[ 0 -1] [1 1]920[ 1 0], [0 1]921)922"""923return tuple(self.generators(*args, **kwds))924925def gen(self, i):926r"""927Return the i-th generator of self, i.e. the i-th element of the928tuple self.gens().929930EXAMPLES::931932sage: SL2Z.gen(1)933[1 1]934[0 1]935"""936return self.generators()[i]937938def ngens(self):939r"""940Return the size of the minimal generating set of self returned by941:meth:`generators`.942943EXAMPLES::944945sage: Gamma0(22).ngens()9468947sage: Gamma1(14).ngens()94813949sage: GammaH(11, [3]).ngens()9503951sage: SL2Z.ngens()9522953"""954return len(self.generators())955956def ncusps(self):957r"""958Return the number of cusps of this arithmetic subgroup. This is959provided as a separate function since for dimension formulae in even960weight all we need to know is the number of cusps, and this can be961calculated very quickly, while enumerating all cusps is much slower.962963EXAMPLES::964965sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.ncusps(Gamma0(7))9662967"""968969return ZZ(len(self.cusps()))970971def nregcusps(self):972r"""973Return the number of cusps of self that are "regular", i.e. their974stabiliser has a generator with both eigenvalues +1 rather than -1. If975the group contains -1, every cusp is clearly regular.976977EXAMPLES::978979sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nregcusps(Gamma1(4))9802981"""982return self.ncusps() - self.nirregcusps()983984def nirregcusps(self):985r"""986Return the number of cusps of self that are "irregular", i.e. their987stabiliser can only be generated by elements with both eigenvalues -1988rather than +1. If the group contains -1, every cusp is clearly989regular.990991EXAMPLES::992993sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nirregcusps(Gamma1(4))9941995"""996if self.is_even():997return 0998else:999return ZZ(len([c for c in self.cusps() if not self.is_regular_cusp(c)]))10001001def dimension_modular_forms(self, k=2):1002r"""1003Return the dimension of the space of weight k modular forms for this1004group. This is given by a standard formula in terms of k and various1005invariants of the group; see Diamond + Shurman, "A First Course in1006Modular Forms", section 3.5 and 3.6. If k is not given, defaults to k =10072.10081009For dimensions of spaces of modular forms with character for Gamma1, use1010the standalone function dimension_modular_forms().10111012For weight 1 modular forms this function only works in cases where one1013can prove solely in terms of Riemann-Roch theory that there aren't any1014cusp forms (i.e. when the number of regular cusps is strictly greater1015than the degree of the canonical divisor). Otherwise a1016NotImplementedError is raised.10171018EXAMPLE::10191020sage: Gamma1(31).dimension_modular_forms(2)1021551022sage: Gamma1(3).dimension_modular_forms(1)102311024sage: Gamma1(4).dimension_modular_forms(1) # irregular cusp102511026sage: Gamma1(31).dimension_modular_forms(1)1027Traceback (most recent call last):1028...1029NotImplementedError: Computation of dimensions of weight 1 cusp forms spaces not implemented in general1030"""10311032k = ZZ(k)1033if k < 0: return ZZ(0)1034if k == 0: return ZZ(1)10351036if not (k % 2):1037# k even10381039return (k-1) * (self.genus() - 1) + (k // ZZ(4))*self.nu2() + (k // ZZ(3))*self.nu3() + (k // ZZ(2))*self.ncusps()10401041else:1042# k odd1043if self.is_even():1044return ZZ(0)1045else:1046e_reg = self.nregcusps()1047e_irr = self.nirregcusps()10481049if k > 1:1050return (k-1)*(self.genus()-1) + (k // ZZ(3)) * self.nu3() + (k * e_reg)/ZZ(2) + (k-1)/ZZ(2) * e_irr1051else:1052if e_reg > 2*self.genus() - 2:1053return e_reg / ZZ(2)1054else:1055raise NotImplementedError, "Computation of dimensions of weight 1 modular forms spaces not implemented in general"10561057def dimension_cusp_forms(self, k=2):1058r"""1059Return the dimension of the space of weight k cusp forms for this1060group. This is given by a standard formula in terms of k and various1061invariants of the group; see Diamond + Shurman, "A First Course in1062Modular Forms", section 3.5 and 3.6. If k is not given, default to k =10632.10641065For dimensions of spaces of cusp forms with character for Gamma1, use1066the standalone function dimension_cusp_forms().10671068For weight 1 cusp forms this function only works in cases where one can1069prove solely in terms of Riemann-Roch theory that there aren't any cusp1070forms (i.e. when the number of regular cusps is strictly greater than1071the degree of the canonical divisor). Otherwise a NotImplementedError is1072raised.10731074EXAMPLE::10751076sage: Gamma1(31).dimension_cusp_forms(2)1077261078sage: Gamma1(3).dimension_cusp_forms(1)107901080sage: Gamma1(4).dimension_cusp_forms(1) # irregular cusp108101082sage: Gamma1(31).dimension_cusp_forms(1)1083Traceback (most recent call last):1084...1085NotImplementedError: Computation of dimensions of weight 1 cusp forms spaces not implemented in general1086"""1087k = ZZ(k)1088if k <= 0: return ZZ(0)10891090if not (k % 2):1091# k even10921093if k == 2:1094return self.genus()10951096else:1097return (k-1) * (self.genus() - 1) + (k // ZZ(4))*self.nu2() + (k // ZZ(3))*self.nu3() + (k // ZZ(2) - 1)*self.ncusps()10981099else:1100# k odd11011102if self.is_even():1103return ZZ(0)11041105else:1106e_reg = self.nregcusps()1107e_irr = self.nirregcusps()11081109if k > 1:1110return (k-1)*(self.genus()-1) + (k // ZZ(3)) * self.nu3() + (k-2)/ZZ(2) * e_reg + (k-1)/ZZ(2) * e_irr1111else:1112if e_reg > 2*self.genus() - 2:1113return ZZ(0)1114else:1115raise NotImplementedError, "Computation of dimensions of weight 1 cusp forms spaces not implemented in general"11161117def dimension_eis(self, k=2):1118r"""1119Return the dimension of the space of weight k Eisenstein series for1120this group, which is a subspace of the space of modular forms1121complementary to the space of cusp forms.11221123INPUT:11241125- ``k`` - an integer (default 2).11261127EXAMPLES::11281129sage: GammaH(33,[2]).dimension_eis()113071131sage: GammaH(33,[2]).dimension_eis(3)113201133sage: GammaH(33, [2,5]).dimension_eis(2)113431135sage: GammaH(33, [4]).dimension_eis(1)113641137"""11381139if k < 0: return ZZ(0)1140if k == 0: return ZZ(1)11411142if not (k % 2): # k even1143if k > 2:1144return self.ncusps()1145else: # k = 21146return self.ncusps() - 111471148else: # k odd1149if self.is_even():1150return 01151if k > 1:1152return self.nregcusps()1153else: # k = 11154return ZZ(self.nregcusps()/ ZZ(2))11551156def as_permutation_group(self):1157r"""1158Return self as an arithmetic subgroup defined in terms of the1159permutation action of `SL(2,\ZZ)` on its right cosets.11601161This method uses Todd-coxeter enumeration (via the method1162:meth:`~todd_coxeter`) which can be extremely slow for arithmetic1163subgroups with relatively large index in `SL(2,\ZZ)`.11641165EXAMPLES::11661167sage: G = Gamma(3)1168sage: P = G.as_permutation_group(); P1169Arithmetic subgroup of index 241170sage: G.ncusps() == P.ncusps()1171True1172sage: G.nu2() == P.nu2()1173True1174sage: G.nu3() == P.nu3()1175True1176sage: G.an_element() in P1177True1178sage: P.an_element() in G1179True1180"""1181_,_,l_edges,s2_edges=self.todd_coxeter()1182n = len(l_edges)1183s3_edges = [None] * n1184r_edges = [None] * n1185for i in xrange(n):1186ii = s2_edges[l_edges[i]]1187s3_edges[ii] = i1188r_edges[ii] = s2_edges[i]1189if self.is_even():1190from sage.modular.arithgroup.arithgroup_perm import EvenArithmeticSubgroup_Permutation1191g=EvenArithmeticSubgroup_Permutation(S2=s2_edges,S3=s3_edges,L=l_edges,R=r_edges)1192else:1193from sage.modular.arithgroup.arithgroup_perm import OddArithmeticSubgroup_Permutation1194g=OddArithmeticSubgroup_Permutation(S2=s2_edges,S3=s3_edges,L=l_edges,R=r_edges)1195g.relabel()1196return g11971198def sturm_bound(self, weight=2):1199r"""1200Returns the Sturm bound for modular forms of the given weight and level1201this subgroup.12021203INPUT:12041205- ``weight`` - an integer `\geq 2` (default: 2)12061207EXAMPLES::1208sage: Gamma0(11).sturm_bound(2)120921210sage: Gamma0(389).sturm_bound(2)1211651212sage: Gamma0(1).sturm_bound(12)121311214sage: Gamma0(100).sturm_bound(2)1215301216sage: Gamma0(1).sturm_bound(36)121731218sage: Gamma0(11).sturm_bound()121921220sage: Gamma0(13).sturm_bound()122131222sage: Gamma0(16).sturm_bound()122341224sage: GammaH(16,[13]).sturm_bound()122581226sage: GammaH(16,[15]).sturm_bound()1227161228sage: Gamma1(16).sturm_bound()1229321230sage: Gamma1(13).sturm_bound()1231281232sage: Gamma1(13).sturm_bound(5)12337012341235FURTHER DETAILS: This function returns a positive integer1236`n` such that the Hecke operators1237`T_1,\ldots, T_n` acting on *cusp forms* generate the1238Hecke algebra as a `\ZZ`-module when the character1239is trivial or quadratic. Otherwise, `T_1,\ldots,T_n`1240generate the Hecke algebra at least as a1241`\ZZ[\varepsilon]`-module, where1242`\ZZ[\varepsilon]` is the ring generated by the1243values of the Dirichlet character `\varepsilon`.1244Alternatively, this is a bound such that if two cusp forms1245associated to this space of modular symbols are congruent modulo1246`(\lambda, q^n)`, then they are congruent modulo1247`\lambda`.12481249REFERENCES:12501251- See the Agashe-Stein appendix to Lario and Schoof,1252*Some computations with Hecke rings and deformation rings*,1253Experimental Math., 11 (2002), no. 2, 303-311.12541255- This result originated in the paper Sturm,1256*On the congruence of modular forms*,1257Springer LNM 1240, 275-280, 1987.12581259REMARK: Kevin Buzzard pointed out to me (William Stein) in Fall12602002 that the above bound is fine for `\Gamma_1(N)` with1261character, as one sees by taking a power of `f`. More1262precisely, if `f \cong 0 \pmod{p}` for first1263`s` coefficients, then `f^r \cong 0 \pmod{p}` for1264first `sr` coefficients. Since the weight of `f^r`1265is `r\cdot k(f)`, it follows that if1266`s \geq b`, where `b` is the Sturm bound for1267`\Gamma_0(N)` at weight `k(f)`, then `f^r`1268has valuation large enough to be forced to be `0` at1269`r*k(f)` by Sturm bound (which is valid if we choose1270`r` correctly). Thus `f \cong 0 \pmod{p}`.1271Conclusion: For `\Gamma_1(N)` with fixed character, the1272Sturm bound is *exactly* the same as for `\Gamma_0(N)`.12731274A key point is that we are finding1275`\ZZ[\varepsilon]` generators for the Hecke algebra1276here, not `\ZZ`-generators. So if one wants1277generators for the Hecke algebra over `\ZZ`, this1278bound must be suitably modified (and I'm not sure what the1279modification is).12801281AUTHORS:12821283- William Stein1284"""1285return ZZ((self.index() * weight / ZZ(12)).ceil())128612871288