Path: blob/master/src/sage/modular/arithgroup/arithgroup_element.pyx
8821 views
"""1Elements of Arithmetic Subgroups2"""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################################################################################1516from sage.structure.element cimport MultiplicativeGroupElement, MonoidElement, Element17from sage.rings.all import ZZ18import sage.matrix.all as matrix19from sage.matrix.matrix_integer_2x2 import Matrix_integer_2x2 as mi2x220from sage.modular.cusps import Cusp2122M2Z = matrix.MatrixSpace(ZZ,2)2324cdef class ArithmeticSubgroupElement(MultiplicativeGroupElement):25r"""26An element of the group `{\rm SL}_2(\ZZ)`, i.e. a 2x2 integer matrix of27determinant 1.28"""2930cdef object __x3132def __init__(self, parent, x, check=True):33"""34Create an element of an arithmetic subgroup.3536INPUT:3738- ``parent`` -- an arithmetic subgroup3940- `x` -- data defining a 2x2 matrix over ZZ41which lives in parent4243- ``check`` -- if True, check that parent is an arithmetic44subgroup, and that `x` defines a matrix of45determinant `1`.4647We tend not to create elements of arithmetic subgroups that aren't48SL2Z, in order to avoid coercion issues (that is, the other arithmetic49subgroups are "facade parents").5051EXAMPLES::5253sage: G = Gamma0(27)54sage: sage.modular.arithgroup.arithgroup_element.ArithmeticSubgroupElement(G, [4,1,27,7])55[ 4 1]56[27 7]57sage: sage.modular.arithgroup.arithgroup_element.ArithmeticSubgroupElement(Integers(3), [4,1,27,7])58Traceback (most recent call last):59...60TypeError: parent (= Ring of integers modulo 3) must be an arithmetic subgroup61sage: sage.modular.arithgroup.arithgroup_element.ArithmeticSubgroupElement(G, [2,0,0,2])62Traceback (most recent call last):63...64TypeError: matrix must have determinant 165sage: sage.modular.arithgroup.arithgroup_element.ArithmeticSubgroupElement(G, [2,0,0,2], check=False)66[2 0]67[0 2]68sage: x = Gamma0(11)([2,1,11,6])69sage: TestSuite(x).run()7071sage: x = Gamma0(5).072sage: SL2Z(x)73[1 1]74[0 1]75sage: x in SL2Z76True77"""78if check:79from all import is_ArithmeticSubgroup80if not is_ArithmeticSubgroup(parent):81raise TypeError, "parent (= %s) must be an arithmetic subgroup"%parent8283x = mi2x2(M2Z, x, copy=True, coerce=True)84if x.determinant() != 1:85raise TypeError, "matrix must have determinant 1"86else:87x = mi2x2(M2Z, x, copy=True, coerce=False)88# Getting rid of this would result in a small speed gain for89# arithmetic operations, but it would have the disadvantage of90# causing strange and opaque errors when inappropriate data types91# are used with "check=False".9293x.set_immutable()94MultiplicativeGroupElement.__init__(self, parent)95self.__x = x9697def __setstate__(self, state):98r"""99For unpickling objects pickled with the old ArithmeticSubgroupElement class.100101EXAMPLE::102103sage: si = unpickle_newobj(sage.modular.arithgroup.arithgroup_element.ArithmeticSubgroupElement, ())104sage: x = sage.matrix.matrix_integer_2x2.Matrix_integer_2x2(MatrixSpace(ZZ, 2), [1,1,0,1], copy=True, coerce=True)105sage: unpickle_build(si, (Gamma0(13), {'_ArithmeticSubgroupElement__x': x}))106"""107from all import SL2Z108oldparent, kwdict = state109self._set_parent(SL2Z)110if kwdict.has_key('_ArithmeticSubgroupElement__x'):111self.__x = kwdict['_ArithmeticSubgroupElement__x']112elif kwdict.has_key('_CongruenceSubgroupElement__x'):113self.__x = kwdict['_CongruenceSubgroupElement__x']114else:115raise ValueError, "Don't know how to unpickle %s" % repr(state)116117def __iter__(self):118"""119EXAMPLES::120121sage: Gamma0(2).0122[1 1]123[0 1]124sage: list(Gamma0(2).0)125[1, 1, 0, 1]126"""127return iter(self.__x)128129def __repr__(self):130"""131Return the string representation of self.132133EXAMPLES::134135sage: Gamma1(5)([6,1,5,1]).__repr__()136'[6 1]\n[5 1]'137"""138return "%s"%self.__x139140def _latex_(self):141"""142Return latex representation of self.143144EXAMPLES::145146sage: Gamma1(5)([6,1,5,1])._latex_()147'\\left(\\begin{array}{rr}\n6 & 1 \\\\\n5 & 1\n\\end{array}\\right)'148"""149return '%s' % self.__x._latex_()150151def __richcmp__(left, right, int op):152r"""153Rich comparison.154155EXAMPLE::156157sage: SL2Z.0 > None158True159"""160return (<Element>left)._richcmp(right, op)161162cdef int _cmp_c_impl(self, Element right_r) except -2:163"""164Compare self to right, where right is guaranteed to have the same165parent as self.166167EXAMPLES::168169sage: x = Gamma0(18)([19,1,18,1])170sage: cmp(x, 3) is not 0171True172sage: cmp(x, x)1730174175sage: x = Gamma0(5)([1,1,0,1])176sage: x == 0177False178179This once caused a segfault (see trac #5443)::180181sage: r,s,t,u,v = map(SL2Z, [[1, 1, 0, 1], [-1, 0, 0, -1], [1, -1, 0, 1], [1, -1, 2, -1], [-1, 1, -2, 1]])182sage: v == s*u183True184sage: s*u == v185True186"""187cdef ArithmeticSubgroupElement right = <ArithmeticSubgroupElement>right_r188return cmp(self.__x, right.__x)189190def __nonzero__(self):191"""192Return True, since the self lives in SL(2,\Z), which does not193contain the zero matrix.194195EXAMPLES::196197sage: x = Gamma0(5)([1,1,0,1])198sage: x.__nonzero__()199True200"""201return True202203cpdef MonoidElement _mul_(self, MonoidElement right):204"""205Return self * right.206207EXAMPLES::208209sage: x = Gamma0(7)([1,0,7,1]) * Gamma0(7)([3,2,7,5]) ; x # indirect doctest210[ 3 2]211[28 19]212sage: x.parent()213Modular Group SL(2,Z)214215We check that #5048 is fixed::216217sage: a = Gamma0(10).1 * Gamma0(5).2; a # random218sage: a.parent()219Modular Group SL(2,Z)220221"""222return self.__class__(self.parent(), self.__x * (<ArithmeticSubgroupElement> right).__x, check=False)223224def __invert__(self):225"""226Return the inverse of self.227228EXAMPLES::229230sage: Gamma0(11)([1,-1,0,1]).__invert__()231[1 1]232[0 1]233"""234I = mi2x2(M2Z, [self.__x[1,1], -self.__x[0,1], -self.__x[1,0], self.__x[0,0]], copy=True, coerce=True)235return self.parent()(I, check=False)236237def matrix(self):238"""239Return the matrix corresponding to self.240241EXAMPLES::242243sage: x = Gamma1(3)([4,5,3,4]) ; x244[4 5]245[3 4]246sage: x.matrix()247[4 5]248[3 4]249sage: type(x.matrix())250<type 'sage.matrix.matrix_integer_2x2.Matrix_integer_2x2'>251"""252return self.__x253254def determinant(self):255"""256Return the determinant of self, which is always 1.257258EXAMPLES::259260sage: Gamma0(691)([1,0,691,1]).determinant()2611262"""263return ZZ(1)264265def det(self):266"""267Return the determinant of self, which is always 1.268269EXAMPLES::270271sage: Gamma1(11)([12,11,-11,-10]).det()2721273"""274return self.determinant()275276def a(self):277"""278Return the upper left entry of self.279280EXAMPLES::281282sage: Gamma0(13)([7,1,13,2]).a()2837284"""285return self.__x[0,0]286287def b(self):288"""289Return the upper right entry of self.290291EXAMPLES::292293sage: Gamma0(13)([7,1,13,2]).b()2941295"""296return self.__x[0,1]297298def c(self):299"""300Return the lower left entry of self.301302EXAMPLES::303304sage: Gamma0(13)([7,1,13,2]).c()30513306"""307return self.__x[1,0]308309def d(self):310"""311Return the lower right entry of self.312313EXAMPLES::314315sage: Gamma0(13)([7,1,13,2]).d()3162317"""318return self.__x[1,1]319320def acton(self, z):321"""322Return the result of the action of self on z as a fractional linear323transformation.324325EXAMPLES::326327sage: G = Gamma0(15)328sage: g = G([1, 2, 15, 31])329330An example of g acting on a symbolic variable::331332sage: z = var('z')333sage: g.acton(z)334(z + 2)/(15*z + 31)335336An example involving the Gaussian numbers::337338sage: K.<i> = NumberField(x^2 + 1)339sage: g.acton(i)3401/1186*i + 77/1186341342An example with complex numbers::343344sage: C.<i> = ComplexField()345sage: g.acton(i)3460.0649241146711636 + 0.000843170320404721*I347348An example with the cusp infinity::349350sage: g.acton(infinity)3511/15352353An example which maps a finite cusp to infinity::354355sage: g.acton(-31/15)356+Infinity357358Note that when acting on instances of cusps the return value359is still a rational number or infinity (Note the presence of360'+', which does not show up for cusp instances)::361362sage: g.acton(Cusp(-31/15))363+Infinity364365TESTS:366367We cover the remaining case, i.e., infinity mapped to infinity::368369sage: G([1, 4, 0, 1]).acton(infinity)370+Infinity371372"""373from sage.rings.infinity import is_Infinite, infinity374if is_Infinite(z):375if self.__x[1,0] != 0:376return self.__x[0,0]/self.__x[1,0]377else:378return infinity379if hasattr(z, 'denominator') and hasattr(z, 'numerator'):380p, q = z.numerator(), z.denominator()381P = self.__x[0,0]*p+self.__x[0,1]*q382Q = self.__x[1,0]*p+self.__x[1,1]*q383if Q == 0 and P != 0:384return infinity385else:386return P/Q387return (self.__x[0,0]*z + self.__x[0,1])/(self.__x[1,0]*z + self.__x[1,1])388389def __getitem__(self, q):390r"""391Fetch entries by direct indexing.392393EXAMPLE::394sage: SL2Z([3,2,1,1])[0,0]3953396"""397return self.__x[q]398399def __hash__(self):400r"""401Return a hash value.402403EXAMPLE::404405sage: hash(SL2Z.0)406-4407"""408return hash(self.__x)409410def __reduce__(self):411r"""412Used for pickling.413414EXAMPLE::415416sage: (SL2Z.1).__reduce__()417(Modular Group SL(2,Z), ([1 1]418[0 1],))419"""420from all import SL2Z421return SL2Z, (self.__x,)422423424