Path: blob/master/sage/modular/arithgroup/congroup_pyx.pyx
4079 views
"""1Helper functions for congruence group class2"""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################################################################################1516import random17from congroup_gamma1 import Gamma1_constructor as Gamma118from congroup_gamma0 import Gamma0_constructor as Gamma01920import sage.rings.arith2122cimport sage.rings.fast_arith23import sage.rings.fast_arith24cdef sage.rings.fast_arith.arith_int arith_int25arith_int = sage.rings.fast_arith.arith_int()26from sage.matrix.matrix_integer_2x2 cimport Matrix_integer_2x227from sage.modular.modsym.p1list import lift_to_sl2z2829include "../../ext/cdefs.pxi"30include '../../ext/stdsage.pxi'313233# This is the C version of a function formerly implemented in python in34# sage.modular.congroup. It is orders of magnitude faster (e.g., 3035# times). The key speedup is in replacing looping through the36# elements of the Python list R with looping through the elements of a37# C-array.3839def degeneracy_coset_representatives_gamma0(int N, int M, int t):40r"""41Let $N$ be a positive integer and $M$ a divisor of $N$. Let $t$ be a42divisor of $N/M$, and let $T$ be the $2x2$ matrix $T=[1,0; 0,t]$.43This function returns representatives for the orbit set44$\Gamma_0(N) \backslash T \Gamma_0(M)$, where $\Gamma_0(N)$45acts on the left on $T \Gamma_0(M)$.4647INPUT:48N -- int49M -- int (divisor of N)50t -- int (divisors of N/M)5152OUTPUT:53list -- list of lists [a,b,c,d], where [a,b,c,d] should54be viewed as a 2x2 matrix.5556This function is used for computation of degeneracy maps between57spaces of modular symbols, hence its name.5859We use that $T^{-1}*(a,b;c,d)*T = (a,bt,c/t,d),$60that the group $T^{-1}Gamma_0(N) T$ is contained in $\Gamma_0(M)$,61and that $\Gamma_0(N) T$ is contained in $T \Gamma_0(M)$.6263ALGORITHM:64\begin{enumerate}65\item Compute representatives for $\Gamma_0(N/t,t)$ inside of $\Gamma_0(M)$:66COSET EQUIVALENCE:67Two right cosets represented by $[a,b;c,d]$ and68$[a',b';c',d']$ of $\Gamma_0(N/t,t)$ in $\SL_2(\Z)$69are equivalent if and only if70$(a,b)=(a',b')$ as points of $\P^1(\Z/t\Z)$,71i.e., $ab' \con ba' \pmod{t}$,72and $(c,d) = (c',d')$ as points of $\P^1(\Z/(N/t)\Z)$.7374ALGORITHM to list all cosets:75\begin{enumerate}76\item Compute the number of cosets.77\item Compute a random element x of Gamma_0(M).78\item Check if x is equivalent to anything generated so79far; if not, add x to the list.80\item Continue until the list is as long as the bound81computed in A.82\end{enumerate}8384\item There is a bijection between $\Gamma_0(N)\backslash T85\Gamma_0(M)$ and $\Gamma_0(N/t,t) \backslash \Gamma_0(M)$86given by $T r$ corresponds to $r$. Consequently we obtain87coset representatives for $\Gamma_0(N)\backslash T88\Gamma_0(M)$ by left multiplying by $T$ each coset89representative of $\Gamma_0(N/t,t) \Gamma_0(M)$ found in90step 1.9192\end{enumerate}9394EXAMPLES:95sage: from sage.modular.arithgroup.all import degeneracy_coset_representatives_gamma096sage: len(degeneracy_coset_representatives_gamma0(13, 1, 1))971498sage: len(degeneracy_coset_representatives_gamma0(13, 13, 1))991100sage: len(degeneracy_coset_representatives_gamma0(13, 1, 13))10114102"""103104if N % M != 0:105raise ArithmeticError, "M (=%s) must be a divisor of N (=%s)"%(M,N)106107if (N/M) % t != 0:108raise ArithmeticError, "t (=%s) must be a divisor of N/M (=%s)"%(t,N/M)109110cdef int n, i, j, k, aa, bb, cc, dd, g, Ndivt, halfmax, is_new111cdef int* R112113# total number of coset representatives that we'll find114n = Gamma0(N).index() / Gamma0(M).index()115k = 0 # number found so far116Ndivt = N / t117R = <int*> sage_malloc(sizeof(int) * (4*n))118if R == <int*>0:119raise MemoryError120halfmax = 2*(n+10)121while k < n:122# try to find another coset representative.123cc = M*random.randrange(-halfmax, halfmax+1)124dd = random.randrange(-halfmax, halfmax+1)125g = arith_int.c_xgcd_int(-cc,dd,&bb,&aa)126if g == 0: continue127cc = cc / g128if cc % M != 0: continue129dd = dd / g130# Test if we've found a new coset representative.131is_new = 1132for i from 0 <= i < k:133j = 4*i134if (R[j+1]*aa - R[j]*bb)%t == 0 and \135(R[j+3]*cc - R[j+2]*dd)%Ndivt == 0:136is_new = 0137break138# If our matrix is new add it to the list.139if is_new:140R[4*k] = aa141R[4*k+1] = bb142R[4*k+2] = cc143R[4*k+3] = dd144k = k + 1145146# Return the list left multiplied by T.147S = []148for i from 0 <= i < k:149j = 4*i150S.append([R[j], R[j+1], R[j+2]*t, R[j+3]*t])151sage_free(R)152return S153154155156157def degeneracy_coset_representatives_gamma1(int N, int M, int t):158r"""159Let $N$ be a positive integer and $M$ a divisor of $N$. Let $t$ be a160divisor of $N/M$, and let $T$ be the $2x2$ matrix $T=[1,0; 0,t]$.161This function returns representatives for the orbit set162$\Gamma_1(N) \backslash T \Gamma_1(M)$, where $\Gamma_1(N)$163acts on the left on $T \Gamma_1(M)$.164165INPUT:166N -- int167M -- int (divisor of N)168t -- int (divisors of N/M)169170OUTPUT:171list -- list of lists [a,b,c,d], where [a,b,c,d] should172be viewed as a 2x2 matrix.173174This function is used for computation of degeneracy maps between175spaces of modular symbols, hence its name.176177ALGORITHM:178Everything is the same as for degeneracy_coset_representatives_gamma0,179except for coset equivalence. Here $\Gamma_1(N/t,t)$ consists180of matrices that are of the form $[1,*;0,1]$ module $N/t$ and181$[1,0;*,1]$ modulo $t$.182183COSET EQUIVALENCE:184Two right cosets represented by $[a,b;c,d]$ and185$[a',b';c',d']$ of $\Gamma_1(N/t,t)$ in $\SL_2(\Z)$186are equivalent if and only if187$$188a \con a' \pmod{t},189b \con b' \pmod{t},190c \con c' \pmod{N/t},191d \con d' \pmod{N/t}.192$$193194EXAMPLES:195sage: from sage.modular.arithgroup.all import degeneracy_coset_representatives_gamma1196sage: len(degeneracy_coset_representatives_gamma1(13, 1, 1))197168198sage: len(degeneracy_coset_representatives_gamma1(13, 13, 1))1991200sage: len(degeneracy_coset_representatives_gamma1(13, 1, 13))201168202"""203204if N % M != 0:205raise ArithmeticError, "M (=%s) must be a divisor of N (=%s)"%(M,N)206207if (N/M) % t != 0:208raise ArithmeticError, "t (=%s) must be a divisor of N/M (=%s)"%(t,N/M)209210cdef int d, g, i, j, k, n, aa, bb, cc, dd, Ndivt, halfmax, is_new211cdef int* R212213214# total number of coset representatives that we'll find215n = Gamma1(N).index() / Gamma1(M).index()216d = arith_int.c_gcd_int(t, N/t)217n = n / d218k = 0 # number found so far219Ndivt = N / t220R = <int*> sage_malloc(sizeof(int) * (4*n))221if R == <int*>0:222raise MemoryError223halfmax = 2*(n+10)224while k < n:225# try to find another coset representative.226cc = M*random.randrange(-halfmax, halfmax+1)227dd = 1 + M*random.randrange(-halfmax, halfmax+1)228g = arith_int.c_xgcd_int(-cc,dd,&bb,&aa)229if g == 0: continue230cc = cc / g231if cc % M != 0: continue232dd = dd / g233if M != 1 and dd % M != 1: continue234# Test if we've found a new coset representative.235is_new = 1236for i from 0 <= i < k:237j = 4*i238if (R[j] - aa)%t == 0 and \239(R[j+1] - bb)%t == 0 and \240(R[j+2] - cc)%(Ndivt) == 0 and \241(R[j+3] - dd)%(Ndivt) == 0:242is_new = 0243break244# If our matrix is new add it to the list.245if is_new:246if k > n:247sage_free(R)248raise RuntimeError, "bug!!"249R[4*k] = aa250R[4*k+1] = bb251R[4*k+2] = cc252R[4*k+3] = dd253k = k + 1254255# Return the list left multiplied by T.256S = []257for i from 0 <= i < k:258j = 4*i259S.append([R[j], R[j+1], R[j+2]*t, R[j+3]*t])260sage_free(R)261return S262263def generators_helper(coset_reps, level, Mat2Z):264r"""265Helper function for generators of Gamma0, Gamma1 and GammaH.266267These are computed using coset representatives, via an "inverse268Todd-Coxeter" algorithm, and generators for ${\rm SL}_2(\Z)$.269270ALGORITHM: Given coset representatives for a finite index271subgroup~$G$ of ${\rm SL}_2(\Z)$ we compute generators for~$G$ as272follows. Let $R$ be a set of coset representatives for $G$.273Let $S, T \in {\rm SL}_2(\Z)$ be defined by \code{0,-1,1,0]} and274\code{1,1,0,1}, respectively. Define maps $s, t: R \to G$ as275follows. If $r \in R$, then there exists a unique $r' \in R$276such that $GrS = Gr'$. Let $s(r) = rSr'^{-1}$. Likewise, there277is a unique $r'$ such that $GrT = Gr'$ and we let $t(r) =278rTr'^{-1}$. Note that $s(r)$ and $t(r)$ are in $G$ for279all~$r$. Then $G$ is generated by $s(R)\cup t(R)$. There are280more sophisticated algorithms using group actions on trees281(and Farey symbols) that give smaller generating sets.282283EXAMPLES::284285sage: Gamma0(7).generators(algorithm="todd-coxeter") # indirect doctest286[287[1 1] [-1 0] [ 1 -1] [1 0] [1 1] [-3 -1] [-2 -1] [-5 -1]288[0 1], [ 0 -1], [ 0 1], [7 1], [0 1], [ 7 2], [ 7 3], [21 4],289<BLANKLINE>290[-4 -1] [-1 0] [ 1 0]291[21 5], [ 7 -1], [-7 1]292]293"""294cdef Matrix_integer_2x2 S,T,I,x,y,z,v,vSmod,vTmod295296S = Matrix_integer_2x2(Mat2Z,[0,-1,1,0],False,True)297T = Matrix_integer_2x2(Mat2Z,[1,1,0,1],False,True)298I = Matrix_integer_2x2(Mat2Z,[1,0,0,1],False,True)299300crs = coset_reps.list()301# print [type(lift_to_sl2z(c, d, level)) for c,d in crs]302try:303reps = [Matrix_integer_2x2(Mat2Z,lift_to_sl2z(c, d, level),False,True) for c,d in crs]304except:305raise ArithmeticError, "Error lifting to SL2Z: level=%s crs=%s" % (level, crs)306ans = []307for i from 0 <= i < len(crs):308x = reps[i]309v = Matrix_integer_2x2(Mat2Z,[crs[i][0],crs[i][1],0,0],False,True)310vSmod = (v*S)311vTmod = (v*T)312y_index = coset_reps.normalize(vSmod[0,0],vSmod[0,1])313z_index = coset_reps.normalize(vTmod[0,0],vTmod[0,1])314y_index = crs.index(y_index)315z_index = crs.index(z_index)316y = reps[y_index]317z = reps[z_index]318y = y._invert_unit()319z = z._invert_unit()320ans.append(x*S*y)321ans.append(x*T*z)322output = []323for x in ans:324if (x[0,0] != 1) or \325(x[0,1] != 0) or \326(x[1,0] != 0) or \327(x[1,1] != 1):328output.append(x)329# should be able to do something like:330# ans = [x for x in ans if x != I]331# however, this raises a somewhat mysterious error:332# <type 'exceptions.SystemError'>: error return without exception set333return output334335336337338