Path: blob/master/sage/modular/arithgroup/congroup_generic.py
4057 views
r"""1Congruence arithmetic subgroups of `{\rm SL}_2(\ZZ)`23Sage can compute extensively with the standard congruence subgroups4`\Gamma_0(N)`, `\Gamma_1(N)`, and `\Gamma_H(N)`.56AUTHORS:78- William Stein9- David Loeffler (2009, 10) -- modifications to work with more general arithmetic subgroups10"""1112################################################################################13#14# Copyright (C) 2004, 2006 William Stein <[email protected]>15#16# Distributed under the terms of the GNU General Public License (GPL)17#18# The full text of the GPL is available at:19#20# http://www.gnu.org/licenses/21#22################################################################################2324from sage.rings.all import QQ, ZZ, Zmod25from sage.rings.arith import gcd26from sage.sets.set import Set27from sage.groups.matrix_gps.matrix_group import MatrixGroup, MatrixGroup_generic28from sage.matrix.matrix_space import MatrixSpace29from sage.misc.misc_c import prod3031from arithgroup_element import ArithmeticSubgroupElement32from arithgroup_generic import ArithmeticSubgroup, is_ArithmeticSubgroup3334def CongruenceSubgroup_constructor(*args):35r"""36Attempt to create a congruence subgroup from the given data.3738The allowed inputs are as follows:3940- A :class:`~sage.groups.matrix_gps.matrix_group.MatrixGroup` object. This41must be a group of matrices over `\ZZ / N\ZZ` for some `N`, with42determinant 1, in which case the function will return the group of43matrices in `SL(2, \ZZ)` whose reduction mod `N` is in the given group.4445- A list of matrices over `\ZZ / N\ZZ` for some `N`. The function will then46compute the subgroup of `SL(2, \ZZ)` generated by these matrices, and47proceed as above.4849- An integer `N` and a list of matrices (over any ring coercible to `\ZZ /50N\ZZ`, e.g. over `\ZZ`). The matrices will then be coerced to `\ZZ /51N\ZZ`.5253The function checks that the input G is valid. It then tests to see if54`G` is the preimage mod `N` of some group of matrices modulo a proper55divisor `M` of `N`, in which case it replaces `G` with this group before56continuing.5758EXAMPLES::5960sage: from sage.modular.arithgroup.congroup_generic import CongruenceSubgroup_constructor as CS61sage: CS(2, [[1,1,0,1]])62Congruence subgroup of SL(2,Z) of level 2, preimage of:63Matrix group over Ring of integers modulo 2 with 1 generators:64[[[1, 1], [0, 1]]]65sage: CS([matrix(Zmod(2), 2, [1,1,0,1])])66Congruence subgroup of SL(2,Z) of level 2, preimage of:67Matrix group over Ring of integers modulo 2 with 1 generators:68[[[1, 1], [0, 1]]]69sage: CS(MatrixGroup([matrix(Zmod(2), 2, [1,1,0,1])]))70Congruence subgroup of SL(2,Z) of level 2, preimage of:71Matrix group over Ring of integers modulo 2 with 1 generators:72[[[1, 1], [0, 1]]]73sage: CS(SL(2, 2))74Modular Group SL(2,Z)7576Some invalid inputs::7778sage: CS(SU(2, 7))79Traceback (most recent call last):80...81TypeError: Ring of definition must be Z / NZ for some N82"""83if isinstance(args[0], MatrixGroup_generic):84G = args[0]8586elif type(args[0]) == type([]):87G = MatrixGroup(args[0])8889elif args[0] in ZZ:90M = MatrixSpace(Zmod(args[0]), 2)91G = MatrixGroup([M(x) for x in args[1]])9293R = G.matrix_space().base_ring()94if not hasattr(R, "cover_ring") or R.cover_ring() != ZZ:95raise TypeError, "Ring of definition must be Z / NZ for some N"9697if not all([x.matrix().det() == 1 for x in G.gens()]):98raise ValueError, "Group must be contained in SL(2, Z / N)"99GG = _minimize_level(G)100if GG in ZZ:101from all import Gamma102return Gamma(GG)103else:104return CongruenceSubgroupFromGroup(GG)105106def is_CongruenceSubgroup(x):107"""108Return True if x is of type CongruenceSubgroup.109110Note that this may be False even if `x` really is a congruence subgroup --111it tests whether `x` is "obviously" congruence, i.e.~whether it has a112congruence subgroup datatype. To test whether or not an arithmetic subgroup113of `SL(2, \ZZ)` is congruence, use the ``is_congruence()`` method instead.114115EXAMPLES::116117sage: from sage.modular.arithgroup.congroup_generic import is_CongruenceSubgroup118sage: is_CongruenceSubgroup(SL2Z)119True120sage: is_CongruenceSubgroup(Gamma0(13))121True122sage: is_CongruenceSubgroup(Gamma1(6))123True124sage: is_CongruenceSubgroup(GammaH(11, [3]))125True126sage: G = ArithmeticSubgroup_Permutation(L = "(1, 2)", R = "(1, 2)"); is_CongruenceSubgroup(G)127False128sage: G.is_congruence()129True130sage: is_CongruenceSubgroup(SymmetricGroup(3))131False132"""133return isinstance(x, CongruenceSubgroupBase)134135class CongruenceSubgroupBase(ArithmeticSubgroup):136137def __init__(self, level):138"""139Create a congruence subgroup with given level.140141EXAMPLES::142143sage: Gamma0(500)144Congruence Subgroup Gamma0(500)145"""146level = ZZ(level)147if level <= 0:148raise ArithmeticError, "Congruence groups only defined for positive levels."149self.__level = level150ArithmeticSubgroup.__init__(self)151152def is_congruence(self):153r"""154Return True, since this is a congruence subgroup.155156EXAMPLE::157158sage: Gamma0(7).is_congruence()159True160"""161162return True163164def level(self):165"""166Return the level of this congruence subgroup.167168EXAMPLES::169170sage: SL2Z.level()1711172sage: Gamma0(20).level()17320174sage: Gamma1(11).level()17511176sage: GammaH(14, [5]).level()17714178"""179return self.__level180181def __cmp__(self, other):182r"""183EXAMPLE::184185sage: CongruenceSubgroup(3,[ [1,1,0,1] ]) == Gamma1(3)186True187sage: CongruenceSubgroup(3,[ [1,1,0,1] ]) == Gamma(3)188False189sage: CongruenceSubgroup(3,[ [1,1,0,1] ]) == QQ190False191"""192193if is_CongruenceSubgroup(other):194t = cmp(self.level(), other.level())195if t: return t196if self.level() == 1: return 0 # shouldn't come up except with pickling/unpickling197t = cmp(self.index(), other.index())198if t: return t199return cmp(self.image_mod_n(),other.image_mod_n())200201elif is_ArithmeticSubgroup(other):202return cmp(self.as_permutation_group(), other)203204else:205return cmp(type(self), type(other))206207class CongruenceSubgroupFromGroup(CongruenceSubgroupBase):208r"""209A congruence subgroup, defined by the data of an integer `N` and a subgroup210`G` of the finite group `SL(2, \ZZ / N\ZZ)`; the congruence subgroup211consists of all the matrices in `SL(2, \ZZ)` whose reduction modulo `N`212lies in `G`.213214This class should not be instantiated directly, but created using the215factory function216:func:`~sage.modular.arithgroup.congroup_generic.CongruenceSubgroup_constructor`,217which accepts much more flexible input, and checks the input to make sure218it is valid.219220TESTS::221222sage: G = CongruenceSubgroup(5, [[0,-1,1,0]]); G223Congruence subgroup of SL(2,Z) of level 5, preimage of:224Matrix group over Ring of integers modulo 5 with 1 generators:225[[[0, 4], [1, 0]]]226sage: G == loads(dumps(G))227True228"""229230def __init__(self, G):231r"""232Standard init function.233234TESTS::235236sage: from sage.modular.arithgroup.congroup_generic import CongruenceSubgroupFromGroup237sage: G = MatrixGroup([matrix(Zmod(2), 2, [1,1,1,0])])238sage: CongruenceSubgroupFromGroup(G).index() # indirect doctest2392240"""241N = G.base_ring().characteristic()242self.__G = G243CongruenceSubgroupBase.__init__(self, N)244245def __reduce__(self):246r"""247Data defining self (for pickling).248249EXAMPLE::250251sage: G = CongruenceSubgroup(5, [[0,-1,1,0]])252sage: G.__reduce__()253(<function CongruenceSubgroup_constructor at ...>, (Matrix group over Ring of integers modulo 5 with 1 generators:254[[[0, 4], [1, 0]]],))255"""256return CongruenceSubgroup_constructor, (self.image_mod_n(),)257258def __call__(self, x, check=True):259r"""260Attempt to convert `x` into an element of self. This converts `x` into261an element of `SL(2, \ZZ)`. If ``check`` is True (the default) it262checks if the resulting element is in self, and otherwise raises an263error.264265EXAMPLE::266267sage: G = MatrixGroup([matrix(Zmod(2), 2, [1,1,1,0])])268sage: H = sage.modular.arithgroup.congroup_generic.CongruenceSubgroupFromGroup(G)269sage: H(1)270[1 0]271[0 1]272sage: H([0,-1,1,0])273Traceback (most recent call last):274...275TypeError: Element [ 0 -1]276[ 1 0] not in group277sage: H([1,2,0,1])278[1 2]279[0 1]280sage: H(SL2Z([0,-1,1,0]), check=False)281[ 0 -1]282[ 1 0]283sage: H([1,2,0,1]).parent()284Modular Group SL(2,Z)285"""286from sage.modular.arithgroup.all import SL2Z287x = SL2Z(x,check=check)288if not check:289return x290else:291y = x.matrix().change_ring(Zmod(self.level()))292if y in self.image_mod_n():293return x294else:295raise TypeError, "Element %s not in group" % x296297def to_even_subgroup(self):298r"""299Return the smallest even subgroup of `SL(2, \ZZ)` containing self.300301EXAMPLE::302303sage: G = Gamma(3)304sage: G.to_even_subgroup()305Congruence subgroup of SL(2,Z) of level 3, preimage of:306Matrix group over Ring of integers modulo 3 with 1 generators:307[[[2, 0], [0, 2]]]308"""309if self.is_even():310return self311else:312G = self.image_mod_n()313H = MatrixGroup(G.gens() + [G.matrix_space()(-1)])314return CongruenceSubgroup_constructor(H)315316def _repr_(self):317r"""318String representation of self.319320EXAMPLE::321322sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroupFromGroup(MatrixGroup([matrix(Zmod(2), 2, [1,1,1,0])]))._repr_()323'Congruence subgroup of SL(2,Z) of level 2, preimage of:\n Matrix group over Ring of integers modulo 2 with 1 generators: \n [[[1, 1], [1, 0]]]'324"""325return "Congruence subgroup of SL(2,Z) of level %s, preimage of:\n %s" % (self.level(), self.image_mod_n())326327def index(self):328r"""329Return the index of self in the full modular group. This is equal to330the index in `SL(2, \ZZ / N\ZZ)` of the image of this group modulo331`\Gamma(N)`.332333EXAMPLE::334335sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroupFromGroup(MatrixGroup([matrix(Zmod(2), 2, [1,1,1,0])])).index()3362337"""338return prod([p**(3*e-2)*(p*p-1) for (p,e) in self.level().factor()]) // self.image_mod_n().order()339340def image_mod_n(self):341r"""342Return the subgroup of `SL(2, \ZZ / N\ZZ)` of which this is the preimage, where `N` is the level of self.343344EXAMPLE::345346sage: G = MatrixGroup([matrix(Zmod(2), 2, [1,1,1,0])])347sage: H = sage.modular.arithgroup.congroup_generic.CongruenceSubgroupFromGroup(G); H.image_mod_n()348Matrix group over Ring of integers modulo 2 with 1 generators:349[[[1, 1], [1, 0]]]350sage: H.image_mod_n() == G351True352"""353return self.__G354355class CongruenceSubgroup(CongruenceSubgroupFromGroup):356r"""357One of the "standard" congruence subgroups `\Gamma_0(N)`, `\Gamma_1(N)`,358`\Gamma(N)`, or `\Gamma_H(N)` (for some `H`).359360This class is not intended to be instantiated directly. Derived subclasses361must override ``__call__``, ``_repr_``, and ``image_mod_n``.362"""363364def image_mod_n(self):365r"""366Raise an error: all derived subclasses should override this function.367368EXAMPLE:369370sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroup(5).image_mod_n()371Traceback (most recent call last):372...373NotImplementedError374"""375raise NotImplementedError376377def __init__(self,*args, **kwds):378r"""379Bypass the init function of the CongruenceSubgroupFromGroup class.380381EXAMPLE::382383sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroup(5) # indirect doctest384Generic congruence subgroup of level 5385"""386return CongruenceSubgroupBase.__init__(self, *args, **kwds)387388def _repr_(self):389"""390Return the string representation of self.391392NOTE: This function should be overridden by all subclasses.393394EXAMPLES::395396sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroup(5)._repr_()397'Generic congruence subgroup of level 5'398"""399return "Generic congruence subgroup of level %s" % self.level()400401def modular_symbols(self, sign=0, weight=2, base_ring=QQ):402"""403Return the space of modular symbols of the specified weight and sign404on the congruence subgroup self.405406EXAMPLES::407408sage: G = Gamma0(23)409sage: G.modular_symbols()410Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field411sage: G.modular_symbols(weight=4)412Modular Symbols space of dimension 12 for Gamma_0(23) of weight 4 with sign 0 over Rational Field413sage: G.modular_symbols(base_ring=GF(7))414Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Finite Field of size 7415sage: G.modular_symbols(sign=1)416Modular Symbols space of dimension 3 for Gamma_0(23) of weight 2 with sign 1 over Rational Field417"""418from sage.modular.modsym.modsym import ModularSymbols419return ModularSymbols(self, sign=sign, weight=weight, base_ring=base_ring)420421def modular_abelian_variety(self):422"""423Return the modular abelian variety corresponding to the congruence424subgroup self.425426EXAMPLES::427428sage: Gamma0(11).modular_abelian_variety()429Abelian variety J0(11) of dimension 1430sage: Gamma1(11).modular_abelian_variety()431Abelian variety J1(11) of dimension 1432sage: GammaH(11,[3]).modular_abelian_variety()433Abelian variety JH(11,[3]) of dimension 1434"""435from sage.modular.abvar.abvar_ambient_jacobian import ModAbVar_ambient_jacobian436return ModAbVar_ambient_jacobian(self)437438def _new_group_from_level(self, level):439r"""440Return a new group of the same type (Gamma0, Gamma1, or441GammaH) as self of the given level. In the case that self is of type442GammaH, we take the largest H inside `(\ZZ/ \text{level}\ZZ)^\times`443which maps to H, namely its inverse image under the natural reduction444map.445446EXAMPLES::447448sage: G = Gamma0(20)449sage: G._new_group_from_level(4)450Congruence Subgroup Gamma0(4)451sage: G._new_group_from_level(40)452Congruence Subgroup Gamma0(40)453454sage: G = Gamma1(10)455sage: G._new_group_from_level(6)456Traceback (most recent call last):457...458ValueError: one level must divide the other459460sage: G = GammaH(50,[7]); G461Congruence Subgroup Gamma_H(50) with H generated by [7]462sage: G._new_group_from_level(25)463Congruence Subgroup Gamma_H(25) with H generated by [7]464sage: G._new_group_from_level(10)465Congruence Subgroup Gamma0(10)466sage: G._new_group_from_level(100)467Congruence Subgroup Gamma_H(100) with H generated by [7, 57]468"""469from congroup_gamma0 import is_Gamma0470from congroup_gamma1 import is_Gamma1471from congroup_gammaH import is_GammaH472from all import Gamma0, Gamma1, GammaH473N = self.level()474if (level%N) and (N%level):475raise ValueError, "one level must divide the other"476if is_Gamma0(self):477return Gamma0(level)478elif is_Gamma1(self):479return Gamma1(level)480elif is_GammaH(self):481H = self._generators_for_H()482if level > N:483d = level // N484diffs = [ N*i for i in range(d) ]485newH = [ h + diff for h in H for diff in diffs ]486return GammaH(level, [x for x in newH if gcd(level, x) == 1])487else:488return GammaH(level, [ h%level for h in H ])489else:490raise NotImplementedError491492def _minimize_level(G):493r"""494Utility function. Given a matrix group `G` contained in `SL(2, \ZZ / N\ZZ)`495for some `N`, test whether or not `G` is the preimage of a subgroup of496smaller level, and if so, return that subgroup.497498The trivial group is handled specially: instead of returning a group, it499returns an integer `N`, representing the trivial subgroup of `SL(2, \ZZ /500N\ZZ)`.501502EXAMPLE::503504sage: M = MatrixSpace(Zmod(9), 2, 2)505sage: G = MatrixGroup([M(x) for x in [[1,1,0,1],[1,3,0,1],[1,0,3,1],[4,0,0,7]]]); G506Matrix group over Ring of integers modulo 9 with 4 generators:507[[[1, 1], [0, 1]], [[1, 3], [0, 1]], [[1, 0], [3, 1]], [[4, 0], [0, 7]]]508sage: sage.modular.arithgroup.congroup_generic._minimize_level(G)509Matrix group over Ring of integers modulo 3 with 1 generators:510[[[1, 1], [0, 1]]]511512sage: G = MatrixGroup([M(x) for x in [[1,3,0,1],[1,0,3,1],[4,0,0,7]]]); G513Matrix group over Ring of integers modulo 9 with 3 generators:514[[[1, 3], [0, 1]], [[1, 0], [3, 1]], [[4, 0], [0, 7]]]515sage: sage.modular.arithgroup.congroup_generic._minimize_level(G)5163517"""518from congroup_gamma import Gamma_constructor as Gamma519Glist = list(G)520N = G.base_ring().characteristic()521i = Gamma(N).index()522523for p in N.prime_divisors():524j = Gamma(N // p).index()525k = len([g for g in Glist if g.matrix().change_ring(Zmod(N // p)) == 1])526if k == i // j:527if N // p == 1:528return ZZ(1)529H = MatrixGroup([g.matrix().change_ring(Zmod(N//p)) for g in G.gens()])530return _minimize_level(H)531532# now sanitize the generators (remove duplicates and copies of the identity)533new_gens = [x.matrix() for x in G.gens() if x.matrix() != 1]534all([x.set_immutable() for x in new_gens])535new_gens = list(Set(new_gens))536if new_gens == []:537return ZZ(G.base_ring().characteristic())538return MatrixGroup(new_gens)539540541