Path: blob/master/src/sage/modular/arithgroup/arithgroup_generic.py
8820 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.old 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 Cusp2425from sage.misc.lazy_import import lazy_import26lazy_import('sage.modular.arithgroup.congroup_sl2z', 'SL2Z')27from sage.structure.element import parent2829from arithgroup_element import ArithmeticSubgroupElement3031def is_ArithmeticSubgroup(x):32r"""33Return True if x is of type ArithmeticSubgroup.3435EXAMPLE::3637sage: from sage.modular.arithgroup.all import is_ArithmeticSubgroup38sage: is_ArithmeticSubgroup(GL(2, GF(7)))39False40sage: is_ArithmeticSubgroup(Gamma0(4))41True42"""4344return isinstance(x, ArithmeticSubgroup)454647class ArithmeticSubgroup(group.Group):48r"""49Base class for arithmetic subgroups of `{\rm SL}_2(\ZZ)`. Not50intended to be used directly, but still includes quite a few51general-purpose routines which compute data about an arithmetic subgroup52assuming that it has a working element testing routine.53"""5455Element = ArithmeticSubgroupElement5657def __init__(self):58r"""59Standard init routine.6061EXAMPLE::6263sage: G = Gamma1(7)64sage: G.category() # indirect doctest65Category of groups66"""67group.Group.__init__(self)6869def _repr_(self):70r"""71Return the string representation of self.7273NOTE: This function should be overridden by all subclasses.7475EXAMPLES::7677sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup()._repr_()78'Generic arithmetic subgroup of SL2Z'79"""80return "Generic arithmetic subgroup of SL2Z"8182def _repr_option(self, key):83"""84Metadata about the :meth:`_repr_` output.8586See :meth:`sage.structure.parent._repr_option` for details.8788EXAMPLES::8990sage: Gamma1(7)._repr_option('element_ascii_art')91True92"""93if key == 'element_ascii_art':94return True95return super(ArithmeticSubgroup, self)._repr_option(key)9697def __reduce__(self):98r"""99Used for pickling self.100101NOTE: This function should be overridden by all subclasses.102103EXAMPLES::104105sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().__reduce__()106Traceback (most recent call last):107...108NotImplementedError: all subclasses must define a __reduce__ method109"""110raise NotImplementedError, "all subclasses must define a __reduce__ method"111112def _element_constructor_(self, x, check=True):113r"""114Create an element of this congruence subgroup from x.115116If the optional flag check is True (default), check whether117x actually gives an element of self.118119EXAMPLES::120121sage: G = Gamma(5)122sage: G([1, 0, -10, 1]) # indirect doctest123[ 1 0]124[-10 1]125sage: G(matrix(ZZ, 2, [26, 5, 5, 1]))126[26 5]127[ 5 1]128sage: G([1, 1, 6, 7])129Traceback (most recent call last):130...131TypeError: matrix [1 1]132[6 7] is not an element of Congruence Subgroup Gamma(5)133"""134# Do not override this function! Derived classes should override135# _contains_sl2.136x = SL2Z(x, check)137if not check or x in self:138return x139raise TypeError, "matrix %s is not an element of %s" % (x, self)140141def __contains__(self, x):142r"""143Test if x is an element of this group. This checks that x defines (is?) a 2x2 integer matrix of determinant 1, and144then hands over to the routine _contains_sl2, which derived classes should implement.145146EXAMPLES::147148sage: [1,2] in SL2Z # indirect doctest149False150sage: [1,2,0,1] in SL2Z # indirect doctest151True152sage: SL2Z([1,2,0,1]) in Gamma(3) # indirect doctest153False154sage: -1 in SL2Z155True156sage: 2 in SL2Z157False158"""159# Do not override this function! Derived classes should override160# _contains_sl2.161if type(x) == type([]) and len(x) == 4:162if not (x[0] in ZZ and x[1] in ZZ and x[2] in ZZ and x[3] in ZZ):163return False164a,b,c,d = map(ZZ, x)165if a*d - b*c != 1: return False166return self._contains_sl2(a,b,c,d)167else:168if parent(x) is not SL2Z:169try:170y = SL2Z(x)171except TypeError:172return False173x = y174return self._contains_sl2(x.a(),x.b(),x.c(),x.d())175176def _contains_sl2(self, a,b,c,d):177r"""178Test whether the matrix [a,b;c,d], which may be assumed to have179determinant 1, is an element of self. This must be overridden by all180subclasses.181182EXAMPLE::183184sage: G = sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup()185sage: 1 in G186Traceback (most recent call last):187...188NotImplementedError: Please implement _contains_sl2 for <class 'sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup_with_category'>189"""190raise NotImplementedError, "Please implement _contains_sl2 for %s" % self.__class__191192def __hash__(self):193r"""194Return a hash of self.195196EXAMPLES::197198sage: Gamma0(11).__hash__()199-545929996 # 32-bit200466678398374495476 # 64-bit201sage: Gamma1(11).__hash__()202-830809815 # 32-bit2034909638266971150633 # 64-bit204"""205return hash(str(self))206207def is_parent_of(self, x):208r"""209Check whether this group is a valid parent for the element x. Required210by Sage's testing framework.211212EXAMPLE::213214sage: Gamma(3).is_parent_of(ZZ(1))215False216sage: Gamma(3).is_parent_of([1,0,0,1])217False218sage: Gamma(3).is_parent_of(SL2Z([1,1,0,1]))219False220sage: Gamma(3).is_parent_of(SL2Z(1))221True222"""223return (parent(x) == SL2Z and x in self)224225def coset_reps(self, G=None):226r"""227Return right coset representatives for self \\ G, where G is another228arithmetic subgroup that contains self. If G = None, default to G =229SL2Z.230231For generic arithmetic subgroups G this is carried out by Todd-Coxeter232enumeration; here G is treated as a black box, implementing nothing but233membership testing.234235EXAMPLES::236237sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().coset_reps()238Traceback (most recent call last):239...240NotImplementedError: Please implement _contains_sl2 for <class 'sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup_with_category'>241sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.coset_reps(Gamma0(3))242[243[1 0] [ 0 -1] [ 0 -1] [ 0 -1]244[0 1], [ 1 0], [ 1 1], [ 1 2]245]246"""247return self.todd_coxeter(G)[0]248249@cached_method250def todd_coxeter(self, G=None, on_right=True):251r"""252Compute coset representatives for self \\ G and action of standard253generators on them via Todd-Coxeter enumeration.254255If ``G`` is ``None``, default to ``SL2Z``. The method also computes256generators of the subgroup at same time.257258INPUT:259260- ``G`` - intermediate subgroup (currently not implemented if diffferent261from SL(2,Z))262263- ``on_right`` - boolean (default: True) - if True return right coset264enumeration, if False return left one.265266This is *extremely* slow in general.267268OUTPUT:269270- a list of coset representatives271272- a list of generators for the group273274- ``l`` - list of integers that correspond to the action of the275standard parabolic element [[1,1],[0,1]] of `SL(2,\ZZ)` on the cosets276of self.277278- ``s`` - list of integers that correspond to the action of the standard279element of order `2` [[0,-1],[1,0]] on the cosets of self.280281EXAMPLES::282283sage: L = SL2Z([1,1,0,1])284sage: S = SL2Z([0,-1,1,0])285286sage: G = Gamma(2)287sage: reps, gens, l, s = G.todd_coxeter()288sage: len(reps) == G.index()289True290sage: all(reps[i] * L * ~reps[l[i]] in G for i in xrange(6))291True292sage: all(reps[i] * S * ~reps[s[i]] in G for i in xrange(6))293True294295sage: G = Gamma0(7)296sage: reps, gens, l, s = G.todd_coxeter()297sage: len(reps) == G.index()298True299sage: all(reps[i] * L * ~reps[l[i]] in G for i in xrange(8))300True301sage: all(reps[i] * S * ~reps[s[i]] in G for i in xrange(8))302True303304sage: G = Gamma1(3)305sage: reps, gens, l, s = G.todd_coxeter(on_right=False)306sage: len(reps) == G.index()307True308sage: all(~reps[l[i]] * L * reps[i] in G for i in xrange(8))309True310sage: all(~reps[s[i]] * S * reps[i] in G for i in xrange(8))311True312313sage: G = Gamma0(5)314sage: reps, gens, l, s = G.todd_coxeter(on_right=False)315sage: len(reps) == G.index()316True317sage: all(~reps[l[i]] * L * reps[i] in G for i in xrange(6))318True319sage: all(~reps[s[i]] * S * reps[i] in G for i in xrange(6))320True321"""322if G is None:323G = SL2Z324if G != SL2Z:325raise NotImplementedError, "Don't know how to compute coset reps for subgroups yet"326327id = SL2Z([1,0,0,1])328l = SL2Z([1,1,0,1])329s = SL2Z([0,-1,1,0])330331reps = [id] # coset representatives332reps_inv = {id:0} # coset representatives index333334l_wait_back = [id] # rep with no incoming s_edge335s_wait_back = [id] # rep with no incoming l_edge336l_wait = [id] # rep with no outgoing l_edge337s_wait = [id] # rep with no outgoing s_edge338339l_edges = [None] # edges for l340s_edges = [None] # edges for s341342gens = []343344while l_wait or s_wait:345if l_wait:346x = l_wait.pop(0)347y = x348not_end = True349while not_end:350if on_right:351y = y*l352else:353y = l*y354for i in xrange(len(l_wait_back)):355v = l_wait_back[i]356if on_right:357yy = y*~v358else:359yy = ~v*y360if yy in self:361l_edges[reps_inv[x]] = reps_inv[v]362del l_wait_back[i]363if yy != id:364gens.append(self(yy))365not_end = False366break367else:368reps_inv[y] = len(reps)369l_edges[reps_inv[x]] = len(reps)370reps.append(y)371l_edges.append(None)372s_edges.append(None)373s_wait_back.append(y)374s_wait.append(y)375x = y376377if s_wait:378x = s_wait.pop(0)379y = x380not_end = True381while not_end:382if on_right:383y = y*s384else:385y = s*y386for i in xrange(len(s_wait_back)):387v = s_wait_back[i]388if on_right:389yy = y*~v390else:391yy = ~v*y392if yy in self:393s_edges[reps_inv[x]] = reps_inv[v]394del s_wait_back[i]395if yy != id:396gens.append(self(yy))397not_end = False398break399else:400reps_inv[y] = len(reps)401s_edges[reps_inv[x]] = len(reps)402reps.append(y)403l_edges.append(None)404s_edges.append(None)405l_wait_back.append(y)406l_wait.append(y)407x = y408409return reps, gens, l_edges, s_edges410411def nu2(self):412r"""413Return the number of orbits of elliptic points of order 2 for this414arithmetic subgroup.415416EXAMPLES::417418sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().nu2()419Traceback (most recent call last):420...421NotImplementedError: Please implement _contains_sl2 for <class 'sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup_with_category'>422sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nu2(Gamma0(1105)) == 8423True424"""425426# Subgroups not containing -1 have no elliptic points of order 2.427428if not self.is_even():429return 0430431# Cheap trick: if self is a subgroup of something with no elliptic points,432# then self has no elliptic points either.433434from all import Gamma0, is_CongruenceSubgroup435if is_CongruenceSubgroup(self):436if self.is_subgroup(Gamma0(self.level())) and Gamma0(self.level()).nu2() == 0:437return 0438439# Otherwise, the number of elliptic points is the number of g in self \440# SL2Z such that the stabiliser of g * i in self is not trivial. (Note441# that the points g*i for g in the coset reps are not distinct, but it442# still works, since the failure of these points to be distinct happens443# precisely when the preimages are not elliptic.)444445count = 0446for g in self.coset_reps():447if g * SL2Z([0,1,-1,0]) * (~g) in self:448count += 1449return count450451def nu3(self):452r"""453Return the number of orbits of elliptic points of order 3 for this454arithmetic subgroup.455456EXAMPLES::457458sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().nu3()459Traceback (most recent call last):460...461NotImplementedError: Please implement _contains_sl2 for <class 'sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup_with_category'>462sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nu3(Gamma0(1729)) == 8463True464465We test that a bug in handling of subgroups not containing -1 is fixed: ::466467sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nu3(GammaH(7, [2]))4682469"""470471# Cheap trick: if self is a subgroup of something with no elliptic points,472# then self has no elliptic points either.473474from all import Gamma0, is_CongruenceSubgroup475if is_CongruenceSubgroup(self):476if self.is_subgroup(Gamma0(self.level())) and Gamma0(self.level()).nu3() == 0:477return 0478479count = 0480for g in self.coset_reps():481if g * SL2Z([0,1,-1,-1]) * (~g) in self:482count += 1483484if self.is_even():485return count486else:487return count/2488489def __cmp__(self, other):490r"""491Compare self to other.492493NOTE: This function must be overridden by all subclasses.494495EXAMPLES::496497sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().__cmp__(ZZ)498Traceback (most recent call last):499...500NotImplementedError501"""502raise NotImplementedError503504def is_abelian(self):505r"""506Return True if this arithmetic subgroup is abelian.507508Since arithmetic subgroups are always nonabelian, this always509returns False.510511EXAMPLES::512513sage: SL2Z.is_abelian()514False515sage: Gamma0(3).is_abelian()516False517sage: Gamma1(12).is_abelian()518False519sage: GammaH(4, [3]).is_abelian()520False521"""522return False523524def is_finite(self):525r"""526Return True if this arithmetic subgroup is finite.527528Since arithmetic subgroups are always infinite, this always529returns False.530531EXAMPLES::532533sage: SL2Z.is_finite()534False535sage: Gamma0(3).is_finite()536False537sage: Gamma1(12).is_finite()538False539sage: GammaH(4, [3]).is_finite()540False541"""542return False543544def is_subgroup(self, right):545r"""546Return True if self is a subgroup of right, and False otherwise. For547generic arithmetic subgroups this is done by the absurdly slow548algorithm of checking all of the generators of self to see if they are549in right.550551EXAMPLES::552553sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().is_subgroup(SL2Z)554Traceback (most recent call last):555...556NotImplementedError557sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.is_subgroup(Gamma1(18), Gamma0(6))558True559"""560# ridiculously slow generic algorithm561562w = self.gens()563for g in w:564if not (g in right):565return False566return True567568def is_normal(self):569r"""570Return True precisely if this subgroup is a normal subgroup of SL2Z.571572EXAMPLES::573574sage: Gamma(3).is_normal()575True576sage: Gamma1(3).is_normal()577False578"""579for x in self.gens():580for y in SL2Z.gens():581if y*SL2Z(x)*(~y) not in self:582return False583return True584585def is_odd(self):586r"""587Return True precisely if this subgroup does not contain the588matrix -1.589590EXAMPLES::591592sage: SL2Z.is_odd()593False594sage: Gamma0(20).is_odd()595False596sage: Gamma1(5).is_odd()597True598sage: GammaH(11, [3]).is_odd()599True600"""601return not self.is_even()602603def is_even(self):604r"""605Return True precisely if this subgroup contains the matrix -1.606607EXAMPLES::608609sage: SL2Z.is_even()610True611sage: Gamma0(20).is_even()612True613sage: Gamma1(5).is_even()614False615sage: GammaH(11, [3]).is_even()616False617"""618return [-1, 0, 0, -1] in self619620def to_even_subgroup(self):621r"""622Return the smallest even subgroup of `SL(2, \ZZ)` containing self.623624EXAMPLE::625626sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().to_even_subgroup()627Traceback (most recent call last):628...629NotImplementedError: Please implement _contains_sl2 for <class 'sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup_with_category'>630"""631if self.is_even():632return self633else:634raise NotImplementedError635636def order(self):637r"""638Return the number of elements in this arithmetic subgroup.639640Since arithmetic subgroups are always infinite, this always returns641infinity.642643EXAMPLES::644645sage: SL2Z.order()646+Infinity647sage: Gamma0(5).order()648+Infinity649sage: Gamma1(2).order()650+Infinity651sage: GammaH(12, [5]).order()652+Infinity653"""654from sage.rings.infinity import infinity655return infinity656657def reduce_cusp(self, c):658r"""659Given a cusp `c \in \mathbb{P}^1(\QQ)`, return the unique reduced cusp660equivalent to c under the action of self, where a reduced cusp is an661element `\tfrac{r}{s}` with r,s coprime non-negative integers, s as662small as possible, and r as small as possible for that s.663664NOTE: This function should be overridden by all subclasses.665666EXAMPLES::667668sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().reduce_cusp(1/4)669Traceback (most recent call last):670...671NotImplementedError672"""673raise NotImplementedError674675def cusps(self, algorithm='default'):676r"""677Return a sorted list of inequivalent cusps for self, i.e. a set of678representatives for the orbits of self on `\mathbb{P}^1(\QQ)`.679These should be returned in a reduced form where this makes sense.680681INPUTS:682683- ``algorithm`` -- which algorithm to use to compute the cusps of self.684``'default'`` finds representatives for a known complete set of685cusps. ``'modsym'`` computes the boundary map on the space of weight686two modular symbols associated to self, which finds the cusps for687self in the process.688689EXAMPLES::690691sage: Gamma0(36).cusps()692[0, 1/18, 1/12, 1/9, 1/6, 1/4, 1/3, 5/12, 1/2, 2/3, 5/6, Infinity]693sage: Gamma0(36).cusps(algorithm='modsym') == Gamma0(36).cusps()694True695sage: GammaH(36, [19,29]).cusps() == Gamma0(36).cusps()696True697sage: Gamma0(1).cusps()698[Infinity]699"""700try:701return copy(self._cusp_list[algorithm])702except (AttributeError,KeyError):703self._cusp_list = {}704705from congroup_sl2z import is_SL2Z706if is_SL2Z(self):707s = [Cusp(1,0)]708709if algorithm == 'default':710s = self._find_cusps()711elif algorithm == 'modsym':712s = sorted([self.reduce_cusp(c) for c in self.modular_symbols().cusps()])713else:714raise ValueError, "unknown algorithm: %s"%algorithm715716self._cusp_list[algorithm] = s717return copy(s)718719def _find_cusps(self):720r"""721Calculate a list of inequivalent cusps.722723EXAMPLES::724725sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroup(5)._find_cusps()726Traceback (most recent call last):727...728NotImplementedError729730NOTE: There is a generic algorithm implemented at the top level that731uses the coset representatives of self. This is *very slow* and for all732the standard congruence subgroups there is a quicker way of doing it,733so this should usually be overridden in subclasses; but it doesn't have734to be.735"""736i = Cusp([1,0])737L = [i]738for a in self.coset_reps():739ai = i.apply([a.a(), a.b(), a.c(), a.d()])740new = 1741for v in L:742if self.are_equivalent(ai, v):743new = 0744break745if new == 1:746L.append(ai)747return L748749def are_equivalent(self, x, y, trans = False):750r"""751Test whether or not cusps x and y are equivalent modulo self. If self752has a reduce_cusp() method, use that; otherwise do a slow explicit753test.754755If trans = False, returns True or False. If trans = True, then return756either False or an element of self mapping x onto y.757758EXAMPLE::759760sage: Gamma0(7).are_equivalent(Cusp(1/3), Cusp(0), trans=True)761[ 3 -1]762[-14 5]763sage: Gamma0(7).are_equivalent(Cusp(1/3), Cusp(1/7))764False765"""766x = Cusp(x)767y = Cusp(y)768if not trans:769try:770xr = self.reduce_cusp(x)771yr = self.reduce_cusp(y)772if xr != yr:773return False774if xr == yr:775return True776except NotImplementedError:777pass778779vx = lift_to_sl2z(x.numerator(),x.denominator(), 0)780dx = SL2Z([vx[2], -vx[0], vx[3], -vx[1]])781vy = lift_to_sl2z(y.numerator(),y.denominator(), 0)782dy = SL2Z([vy[2], -vy[0], vy[3], -vy[1]])783784for i in xrange(self.index()):785# Note that the width of any cusp is bounded above by the index of self.786# If self is congruence, then the level of self is a much better bound, but787# this method is written to work with non-congruence subgroups as well,788if dy * SL2Z([1,i,0,1])*(~dx) in self:789if trans:790return dy * SL2Z([1,i,0,1]) * ~dx791else:792return True793elif (self.is_odd() and dy * SL2Z([-1,-i,0,-1]) * ~dx in self):794if trans:795return dy * SL2Z([-1,-i,0,-1]) * ~dx796else:797return True798return False799800def cusp_data(self, c):801r"""802Return a triple (g, w, t) where g is an element of self generating the803stabiliser of the given cusp, w is the width of the cusp, and t is 1 if804the cusp is regular and -1 if not.805806EXAMPLES::807808sage: Gamma1(4).cusp_data(Cusps(1/2))809(810[ 1 -1]811[ 4 -3], 1, -1812)813"""814c = Cusp(c)815816# first find an element of SL2Z sending infinity to the given cusp817w = lift_to_sl2z(c.denominator(), c.numerator(), 0)818g = SL2Z([w[3], w[1], w[2],w[0]])819820for d in xrange(1,1+self.index()):821if g * SL2Z([1,d,0,1]) * (~g) in self:822return (g * SL2Z([1,d,0,1]) * (~g), d, 1)823elif g * SL2Z([-1,-d,0,-1]) * (~g) in self:824return (g * SL2Z([-1,-d,0,-1]) * (~g), d, -1)825raise ArithmeticError, "Can't get here!"826827def is_regular_cusp(self, c):828r"""829Return True if the orbit of the given cusp is a regular cusp for self,830otherwise False. This is automatically true if -1 is in self.831832EXAMPLES::833834sage: Gamma1(4).is_regular_cusp(Cusps(1/2))835False836sage: Gamma1(4).is_regular_cusp(Cusps(oo))837True838"""839if self.is_even(): return True840return (self.cusp_data(c)[2] == 1)841842def cusp_width(self, c):843r"""844Return the width of the orbit of cusps represented by c.845846EXAMPLES::847848sage: Gamma0(11).cusp_width(Cusps(oo))8491850sage: Gamma0(11).cusp_width(0)85111852sage: [Gamma0(100).cusp_width(c) for c in Gamma0(100).cusps()]853[100, 1, 4, 1, 1, 1, 4, 25, 1, 1, 4, 1, 25, 4, 1, 4, 1, 1]854"""855return self.cusp_data(c)[1]856857def index(self):858r"""859Return the index of self in the full modular group.860861EXAMPLES::862863sage: Gamma0(17).index()86418865sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroup(5).index()866Traceback (most recent call last):867...868NotImplementedError869"""870871return len(list(self.coset_reps()))872873def generalised_level(self):874r"""875Return the generalised level of self, i.e. the least common multiple of876the widths of all cusps.877878If self is *even*, Wohlfart's theorem tells us that this is equal to879the (conventional) level of self when self is a congruence subgroup.880This can fail if self is odd, but the actual level is at most twice the881generalised level. See the paper by Kiming, Schuett and Verrill for882more examples.883884EXAMPLE::885886sage: Gamma0(18).generalised_level()88718888sage: sage.modular.arithgroup.arithgroup_perm.HsuExample18().generalised_level()88924890891In the following example, the actual level is twice the generalised892level. This is the group `G_2` from Example 17 of K-S-V.893894::895896sage: G = CongruenceSubgroup(8, [ [1,1,0,1], [3,-1,4,-1] ])897sage: G.level()8988899sage: G.generalised_level()9004901"""902return arith.lcm([self.cusp_width(c) for c in self.cusps()])903904def projective_index(self):905r"""906Return the index of the image of self in `{\rm PSL}_2(\ZZ)`. This is equal907to the index of self if self contains -1, and half of this otherwise.908909This is equal to the degree of the natural map from the modular curve910of self to the `j`-line.911912EXAMPLE::913914sage: Gamma0(5).projective_index()9156916sage: Gamma1(5).projective_index()91712918"""919920if self.is_even():921return self.index()922else:923return self.index() // 2924925def is_congruence(self):926r"""927Return True if self is a congruence subgroup.928929EXAMPLE::930931sage: Gamma0(5).is_congruence()932True933sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup().is_congruence()934Traceback (most recent call last):935...936NotImplementedError937"""938939raise NotImplementedError940941def genus(self):942r"""943Return the genus of the modular curve of self.944945EXAMPLES::946947sage: Gamma1(5).genus()9480949sage: Gamma1(31).genus()95026951sage: Gamma1(157).genus() == dimension_cusp_forms(Gamma1(157), 2)952True953sage: GammaH(7, [2]).genus()9540955sage: [Gamma0(n).genus() for n in [1..23]]956[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 2, 2]957sage: [n for n in [1..200] if Gamma0(n).genus() == 1]958[11, 14, 15, 17, 19, 20, 21, 24, 27, 32, 36, 49]959960961"""962963return ZZ(1 + (self.projective_index()) / ZZ(12) - (self.nu2())/ZZ(4) - (self.nu3())/ZZ(3) - self.ncusps()/ZZ(2))964965def farey_symbol(self):966r"""967Return the Farey symbol associated to this subgroup. See the968:mod:`~sage.modular.arithgroup.farey_symbol` module for more969information.970971EXAMPLE::972973sage: Gamma1(4).farey_symbol()974FareySymbol(Congruence Subgroup Gamma1(4))975"""976from farey_symbol import Farey977return Farey(self)978979@cached_method980def generators(self, algorithm="farey"):981r"""982Return a list of generators for this congruence subgroup. The result is cached.983984INPUT:985986- ``algorithm`` (string): either ``farey`` or ``todd-coxeter``.987988If ``algorithm`` is set to ``"farey"``, then the generators will be989calculated using Farey symbols, which will always return a *minimal*990generating set. See :mod:`~sage.modular.arithgroup.farey_symbol` for991more information.992993If ``algorithm`` is set to ``"todd-coxeter"``, a simpler algorithm994based on Todd-Coxeter enumeration will be used. This is *exceedingly*995slow for general subgroups, and the list of generators will be far from996minimal (indeed it may contain repetitions).997998EXAMPLE::9991000sage: Gamma(2).generators()1001[1002[1 2] [ 3 -2] [-1 0]1003[0 1], [ 2 -1], [ 0 -1]1004]1005sage: Gamma(2).generators(algorithm="todd-coxeter")1006[1007[1 2] [-1 0] [ 1 0] [-1 0] [-1 2] [-1 0] [1 0]1008[0 1], [ 0 -1], [-2 1], [ 0 -1], [-2 3], [ 2 -1], [2 1]1009]1010"""1011if algorithm=="farey":1012return self.farey_symbol().generators()1013elif algorithm == "todd-coxeter":1014return self.todd_coxeter()[1]1015else:1016raise ValueError, "Unknown algorithm '%s' (should be either 'farey' or 'todd-coxeter')" % algorithm10171018def gens(self, *args, **kwds):1019r"""1020Return a tuple of generators for this congruence subgroup.10211022The generators need not be minimal. For arguments, see :meth:`~generators`.10231024EXAMPLES::10251026sage: SL2Z.gens()1027(1028[ 0 -1] [1 1]1029[ 1 0], [0 1]1030)1031"""1032return tuple(self.generators(*args, **kwds))10331034def gen(self, i):1035r"""1036Return the i-th generator of self, i.e. the i-th element of the1037tuple self.gens().10381039EXAMPLES::10401041sage: SL2Z.gen(1)1042[1 1]1043[0 1]1044"""1045return self.generators()[i]10461047def ngens(self):1048r"""1049Return the size of the minimal generating set of self returned by1050:meth:`generators`.10511052EXAMPLES::10531054sage: Gamma0(22).ngens()105581056sage: Gamma1(14).ngens()1057131058sage: GammaH(11, [3]).ngens()105931060sage: SL2Z.ngens()106121062"""1063return len(self.generators())10641065def ncusps(self):1066r"""1067Return the number of cusps of this arithmetic subgroup. This is1068provided as a separate function since for dimension formulae in even1069weight all we need to know is the number of cusps, and this can be1070calculated very quickly, while enumerating all cusps is much slower.10711072EXAMPLES::10731074sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.ncusps(Gamma0(7))107521076"""10771078return ZZ(len(self.cusps()))10791080def nregcusps(self):1081r"""1082Return the number of cusps of self that are "regular", i.e. their1083stabiliser has a generator with both eigenvalues +1 rather than -1. If1084the group contains -1, every cusp is clearly regular.10851086EXAMPLES::10871088sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nregcusps(Gamma1(4))108921090"""1091return self.ncusps() - self.nirregcusps()10921093def nirregcusps(self):1094r"""1095Return the number of cusps of self that are "irregular", i.e. their1096stabiliser can only be generated by elements with both eigenvalues -11097rather than +1. If the group contains -1, every cusp is clearly1098regular.10991100EXAMPLES::11011102sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.nirregcusps(Gamma1(4))110311104"""1105if self.is_even():1106return 01107else:1108return ZZ(len([c for c in self.cusps() if not self.is_regular_cusp(c)]))11091110def dimension_modular_forms(self, k=2):1111r"""1112Return the dimension of the space of weight k modular forms for this1113group. This is given by a standard formula in terms of k and various1114invariants of the group; see Diamond + Shurman, "A First Course in1115Modular Forms", section 3.5 and 3.6. If k is not given, defaults to k =11162.11171118For dimensions of spaces of modular forms with character for Gamma1, use1119the standalone function dimension_modular_forms().11201121For weight 1 modular forms this function only works in cases where one1122can prove solely in terms of Riemann-Roch theory that there aren't any1123cusp forms (i.e. when the number of regular cusps is strictly greater1124than the degree of the canonical divisor). Otherwise a1125NotImplementedError is raised.11261127EXAMPLE::11281129sage: Gamma1(31).dimension_modular_forms(2)1130551131sage: Gamma1(3).dimension_modular_forms(1)113211133sage: Gamma1(4).dimension_modular_forms(1) # irregular cusp113411135sage: Gamma1(31).dimension_modular_forms(1)1136Traceback (most recent call last):1137...1138NotImplementedError: Computation of dimensions of weight 1 cusp forms spaces not implemented in general1139"""11401141k = ZZ(k)1142if k < 0: return ZZ(0)1143if k == 0: return ZZ(1)11441145if not (k % 2):1146# k even11471148return (k-1) * (self.genus() - 1) + (k // ZZ(4))*self.nu2() + (k // ZZ(3))*self.nu3() + (k // ZZ(2))*self.ncusps()11491150else:1151# k odd1152if self.is_even():1153return ZZ(0)1154else:1155e_reg = self.nregcusps()1156e_irr = self.nirregcusps()11571158if k > 1:1159return (k-1)*(self.genus()-1) + (k // ZZ(3)) * self.nu3() + (k * e_reg)/ZZ(2) + (k-1)/ZZ(2) * e_irr1160else:1161if e_reg > 2*self.genus() - 2:1162return e_reg / ZZ(2)1163else:1164raise NotImplementedError, "Computation of dimensions of weight 1 modular forms spaces not implemented in general"11651166def dimension_cusp_forms(self, k=2):1167r"""1168Return the dimension of the space of weight k cusp forms for this1169group. This is given by a standard formula in terms of k and various1170invariants of the group; see Diamond + Shurman, "A First Course in1171Modular Forms", section 3.5 and 3.6. If k is not given, default to k =11722.11731174For dimensions of spaces of cusp forms with character for Gamma1, use1175the standalone function dimension_cusp_forms().11761177For weight 1 cusp forms this function only works in cases where one can1178prove solely in terms of Riemann-Roch theory that there aren't any cusp1179forms (i.e. when the number of regular cusps is strictly greater than1180the degree of the canonical divisor). Otherwise a NotImplementedError is1181raised.11821183EXAMPLE::11841185sage: Gamma1(31).dimension_cusp_forms(2)1186261187sage: Gamma1(3).dimension_cusp_forms(1)118801189sage: Gamma1(4).dimension_cusp_forms(1) # irregular cusp119001191sage: Gamma1(31).dimension_cusp_forms(1)1192Traceback (most recent call last):1193...1194NotImplementedError: Computation of dimensions of weight 1 cusp forms spaces not implemented in general1195"""1196k = ZZ(k)1197if k <= 0: return ZZ(0)11981199if not (k % 2):1200# k even12011202if k == 2:1203return self.genus()12041205else:1206return (k-1) * (self.genus() - 1) + (k // ZZ(4))*self.nu2() + (k // ZZ(3))*self.nu3() + (k // ZZ(2) - 1)*self.ncusps()12071208else:1209# k odd12101211if self.is_even():1212return ZZ(0)12131214else:1215e_reg = self.nregcusps()1216e_irr = self.nirregcusps()12171218if k > 1:1219return (k-1)*(self.genus()-1) + (k // ZZ(3)) * self.nu3() + (k-2)/ZZ(2) * e_reg + (k-1)/ZZ(2) * e_irr1220else:1221if e_reg > 2*self.genus() - 2:1222return ZZ(0)1223else:1224raise NotImplementedError, "Computation of dimensions of weight 1 cusp forms spaces not implemented in general"12251226def dimension_eis(self, k=2):1227r"""1228Return the dimension of the space of weight k Eisenstein series for1229this group, which is a subspace of the space of modular forms1230complementary to the space of cusp forms.12311232INPUT:12331234- ``k`` - an integer (default 2).12351236EXAMPLES::12371238sage: GammaH(33,[2]).dimension_eis()123971240sage: GammaH(33,[2]).dimension_eis(3)124101242sage: GammaH(33, [2,5]).dimension_eis(2)124331244sage: GammaH(33, [4]).dimension_eis(1)124541246"""12471248if k < 0: return ZZ(0)1249if k == 0: return ZZ(1)12501251if not (k % 2): # k even1252if k > 2:1253return self.ncusps()1254else: # k = 21255return self.ncusps() - 112561257else: # k odd1258if self.is_even():1259return 01260if k > 1:1261return self.nregcusps()1262else: # k = 11263return ZZ(self.nregcusps()/ ZZ(2))12641265def as_permutation_group(self):1266r"""1267Return self as an arithmetic subgroup defined in terms of the1268permutation action of `SL(2,\ZZ)` on its right cosets.12691270This method uses Todd-coxeter enumeration (via the method1271:meth:`~todd_coxeter`) which can be extremely slow for arithmetic1272subgroups with relatively large index in `SL(2,\ZZ)`.12731274EXAMPLES::12751276sage: G = Gamma(3)1277sage: P = G.as_permutation_group(); P1278Arithmetic subgroup of index 241279sage: G.ncusps() == P.ncusps()1280True1281sage: G.nu2() == P.nu2()1282True1283sage: G.nu3() == P.nu3()1284True1285sage: G.an_element() in P1286True1287sage: P.an_element() in G1288True1289"""1290_,_,l_edges,s2_edges=self.todd_coxeter()1291n = len(l_edges)1292s3_edges = [None] * n1293r_edges = [None] * n1294for i in xrange(n):1295ii = s2_edges[l_edges[i]]1296s3_edges[ii] = i1297r_edges[ii] = s2_edges[i]1298if self.is_even():1299from sage.modular.arithgroup.arithgroup_perm import EvenArithmeticSubgroup_Permutation1300g=EvenArithmeticSubgroup_Permutation(S2=s2_edges,S3=s3_edges,L=l_edges,R=r_edges)1301else:1302from sage.modular.arithgroup.arithgroup_perm import OddArithmeticSubgroup_Permutation1303g=OddArithmeticSubgroup_Permutation(S2=s2_edges,S3=s3_edges,L=l_edges,R=r_edges)1304g.relabel()1305return g13061307def sturm_bound(self, weight=2):1308r"""1309Returns the Sturm bound for modular forms of the given weight and level1310this subgroup.13111312INPUT:13131314- ``weight`` - an integer `\geq 2` (default: 2)13151316EXAMPLES::1317sage: Gamma0(11).sturm_bound(2)131821319sage: Gamma0(389).sturm_bound(2)1320651321sage: Gamma0(1).sturm_bound(12)132211323sage: Gamma0(100).sturm_bound(2)1324301325sage: Gamma0(1).sturm_bound(36)132631327sage: Gamma0(11).sturm_bound()132821329sage: Gamma0(13).sturm_bound()133031331sage: Gamma0(16).sturm_bound()133241333sage: GammaH(16,[13]).sturm_bound()133481335sage: GammaH(16,[15]).sturm_bound()1336161337sage: Gamma1(16).sturm_bound()1338321339sage: Gamma1(13).sturm_bound()1340281341sage: Gamma1(13).sturm_bound(5)13427013431344FURTHER DETAILS: This function returns a positive integer1345`n` such that the Hecke operators1346`T_1,\ldots, T_n` acting on *cusp forms* generate the1347Hecke algebra as a `\ZZ`-module when the character1348is trivial or quadratic. Otherwise, `T_1,\ldots,T_n`1349generate the Hecke algebra at least as a1350`\ZZ[\varepsilon]`-module, where1351`\ZZ[\varepsilon]` is the ring generated by the1352values of the Dirichlet character `\varepsilon`.1353Alternatively, this is a bound such that if two cusp forms1354associated to this space of modular symbols are congruent modulo1355`(\lambda, q^n)`, then they are congruent modulo1356`\lambda`.13571358REFERENCES:13591360- See the Agashe-Stein appendix to Lario and Schoof,1361*Some computations with Hecke rings and deformation rings*,1362Experimental Math., 11 (2002), no. 2, 303-311.13631364- This result originated in the paper Sturm,1365*On the congruence of modular forms*,1366Springer LNM 1240, 275-280, 1987.13671368REMARK: Kevin Buzzard pointed out to me (William Stein) in Fall13692002 that the above bound is fine for `\Gamma_1(N)` with1370character, as one sees by taking a power of `f`. More1371precisely, if `f \cong 0 \pmod{p}` for first1372`s` coefficients, then `f^r \cong 0 \pmod{p}` for1373first `sr` coefficients. Since the weight of `f^r`1374is `r\cdot k(f)`, it follows that if1375`s \geq b`, where `b` is the Sturm bound for1376`\Gamma_0(N)` at weight `k(f)`, then `f^r`1377has valuation large enough to be forced to be `0` at1378`r*k(f)` by Sturm bound (which is valid if we choose1379`r` correctly). Thus `f \cong 0 \pmod{p}`.1380Conclusion: For `\Gamma_1(N)` with fixed character, the1381Sturm bound is *exactly* the same as for `\Gamma_0(N)`.13821383A key point is that we are finding1384`\ZZ[\varepsilon]` generators for the Hecke algebra1385here, not `\ZZ`-generators. So if one wants1386generators for the Hecke algebra over `\ZZ`, this1387bound must be suitably modified (and I'm not sure what the1388modification is).13891390AUTHORS:13911392- William Stein1393"""1394return ZZ((self.index() * weight / ZZ(12)).ceil())139513961397