Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/arithgroup/congroup_pyx.pyx
4079 views
1
"""
2
Helper functions for congruence group class
3
"""
4
5
################################################################################
6
#
7
# Copyright (C) 2009, The Sage Group -- http://www.sagemath.org/
8
#
9
# Distributed under the terms of the GNU General Public License (GPL)
10
#
11
# The full text of the GPL is available at:
12
#
13
# http://www.gnu.org/licenses/
14
#
15
################################################################################
16
17
import random
18
from congroup_gamma1 import Gamma1_constructor as Gamma1
19
from congroup_gamma0 import Gamma0_constructor as Gamma0
20
21
import sage.rings.arith
22
23
cimport sage.rings.fast_arith
24
import sage.rings.fast_arith
25
cdef sage.rings.fast_arith.arith_int arith_int
26
arith_int = sage.rings.fast_arith.arith_int()
27
from sage.matrix.matrix_integer_2x2 cimport Matrix_integer_2x2
28
from sage.modular.modsym.p1list import lift_to_sl2z
29
30
include "../../ext/cdefs.pxi"
31
include '../../ext/stdsage.pxi'
32
33
34
# This is the C version of a function formerly implemented in python in
35
# sage.modular.congroup. It is orders of magnitude faster (e.g., 30
36
# times). The key speedup is in replacing looping through the
37
# elements of the Python list R with looping through the elements of a
38
# C-array.
39
40
def degeneracy_coset_representatives_gamma0(int N, int M, int t):
41
r"""
42
Let $N$ be a positive integer and $M$ a divisor of $N$. Let $t$ be a
43
divisor of $N/M$, and let $T$ be the $2x2$ matrix $T=[1,0; 0,t]$.
44
This function returns representatives for the orbit set
45
$\Gamma_0(N) \backslash T \Gamma_0(M)$, where $\Gamma_0(N)$
46
acts on the left on $T \Gamma_0(M)$.
47
48
INPUT:
49
N -- int
50
M -- int (divisor of N)
51
t -- int (divisors of N/M)
52
53
OUTPUT:
54
list -- list of lists [a,b,c,d], where [a,b,c,d] should
55
be viewed as a 2x2 matrix.
56
57
This function is used for computation of degeneracy maps between
58
spaces of modular symbols, hence its name.
59
60
We use that $T^{-1}*(a,b;c,d)*T = (a,bt,c/t,d),$
61
that the group $T^{-1}Gamma_0(N) T$ is contained in $\Gamma_0(M)$,
62
and that $\Gamma_0(N) T$ is contained in $T \Gamma_0(M)$.
63
64
ALGORITHM:
65
\begin{enumerate}
66
\item Compute representatives for $\Gamma_0(N/t,t)$ inside of $\Gamma_0(M)$:
67
COSET EQUIVALENCE:
68
Two right cosets represented by $[a,b;c,d]$ and
69
$[a',b';c',d']$ of $\Gamma_0(N/t,t)$ in $\SL_2(\Z)$
70
are equivalent if and only if
71
$(a,b)=(a',b')$ as points of $\P^1(\Z/t\Z)$,
72
i.e., $ab' \con ba' \pmod{t}$,
73
and $(c,d) = (c',d')$ as points of $\P^1(\Z/(N/t)\Z)$.
74
75
ALGORITHM to list all cosets:
76
\begin{enumerate}
77
\item Compute the number of cosets.
78
\item Compute a random element x of Gamma_0(M).
79
\item Check if x is equivalent to anything generated so
80
far; if not, add x to the list.
81
\item Continue until the list is as long as the bound
82
computed in A.
83
\end{enumerate}
84
85
\item There is a bijection between $\Gamma_0(N)\backslash T
86
\Gamma_0(M)$ and $\Gamma_0(N/t,t) \backslash \Gamma_0(M)$
87
given by $T r$ corresponds to $r$. Consequently we obtain
88
coset representatives for $\Gamma_0(N)\backslash T
89
\Gamma_0(M)$ by left multiplying by $T$ each coset
90
representative of $\Gamma_0(N/t,t) \Gamma_0(M)$ found in
91
step 1.
92
93
\end{enumerate}
94
95
EXAMPLES:
96
sage: from sage.modular.arithgroup.all import degeneracy_coset_representatives_gamma0
97
sage: len(degeneracy_coset_representatives_gamma0(13, 1, 1))
98
14
99
sage: len(degeneracy_coset_representatives_gamma0(13, 13, 1))
100
1
101
sage: len(degeneracy_coset_representatives_gamma0(13, 1, 13))
102
14
103
"""
104
105
if N % M != 0:
106
raise ArithmeticError, "M (=%s) must be a divisor of N (=%s)"%(M,N)
107
108
if (N/M) % t != 0:
109
raise ArithmeticError, "t (=%s) must be a divisor of N/M (=%s)"%(t,N/M)
110
111
cdef int n, i, j, k, aa, bb, cc, dd, g, Ndivt, halfmax, is_new
112
cdef int* R
113
114
# total number of coset representatives that we'll find
115
n = Gamma0(N).index() / Gamma0(M).index()
116
k = 0 # number found so far
117
Ndivt = N / t
118
R = <int*> sage_malloc(sizeof(int) * (4*n))
119
if R == <int*>0:
120
raise MemoryError
121
halfmax = 2*(n+10)
122
while k < n:
123
# try to find another coset representative.
124
cc = M*random.randrange(-halfmax, halfmax+1)
125
dd = random.randrange(-halfmax, halfmax+1)
126
g = arith_int.c_xgcd_int(-cc,dd,&bb,&aa)
127
if g == 0: continue
128
cc = cc / g
129
if cc % M != 0: continue
130
dd = dd / g
131
# Test if we've found a new coset representative.
132
is_new = 1
133
for i from 0 <= i < k:
134
j = 4*i
135
if (R[j+1]*aa - R[j]*bb)%t == 0 and \
136
(R[j+3]*cc - R[j+2]*dd)%Ndivt == 0:
137
is_new = 0
138
break
139
# If our matrix is new add it to the list.
140
if is_new:
141
R[4*k] = aa
142
R[4*k+1] = bb
143
R[4*k+2] = cc
144
R[4*k+3] = dd
145
k = k + 1
146
147
# Return the list left multiplied by T.
148
S = []
149
for i from 0 <= i < k:
150
j = 4*i
151
S.append([R[j], R[j+1], R[j+2]*t, R[j+3]*t])
152
sage_free(R)
153
return S
154
155
156
157
158
def degeneracy_coset_representatives_gamma1(int N, int M, int t):
159
r"""
160
Let $N$ be a positive integer and $M$ a divisor of $N$. Let $t$ be a
161
divisor of $N/M$, and let $T$ be the $2x2$ matrix $T=[1,0; 0,t]$.
162
This function returns representatives for the orbit set
163
$\Gamma_1(N) \backslash T \Gamma_1(M)$, where $\Gamma_1(N)$
164
acts on the left on $T \Gamma_1(M)$.
165
166
INPUT:
167
N -- int
168
M -- int (divisor of N)
169
t -- int (divisors of N/M)
170
171
OUTPUT:
172
list -- list of lists [a,b,c,d], where [a,b,c,d] should
173
be viewed as a 2x2 matrix.
174
175
This function is used for computation of degeneracy maps between
176
spaces of modular symbols, hence its name.
177
178
ALGORITHM:
179
Everything is the same as for degeneracy_coset_representatives_gamma0,
180
except for coset equivalence. Here $\Gamma_1(N/t,t)$ consists
181
of matrices that are of the form $[1,*;0,1]$ module $N/t$ and
182
$[1,0;*,1]$ modulo $t$.
183
184
COSET EQUIVALENCE:
185
Two right cosets represented by $[a,b;c,d]$ and
186
$[a',b';c',d']$ of $\Gamma_1(N/t,t)$ in $\SL_2(\Z)$
187
are equivalent if and only if
188
$$
189
a \con a' \pmod{t},
190
b \con b' \pmod{t},
191
c \con c' \pmod{N/t},
192
d \con d' \pmod{N/t}.
193
$$
194
195
EXAMPLES:
196
sage: from sage.modular.arithgroup.all import degeneracy_coset_representatives_gamma1
197
sage: len(degeneracy_coset_representatives_gamma1(13, 1, 1))
198
168
199
sage: len(degeneracy_coset_representatives_gamma1(13, 13, 1))
200
1
201
sage: len(degeneracy_coset_representatives_gamma1(13, 1, 13))
202
168
203
"""
204
205
if N % M != 0:
206
raise ArithmeticError, "M (=%s) must be a divisor of N (=%s)"%(M,N)
207
208
if (N/M) % t != 0:
209
raise ArithmeticError, "t (=%s) must be a divisor of N/M (=%s)"%(t,N/M)
210
211
cdef int d, g, i, j, k, n, aa, bb, cc, dd, Ndivt, halfmax, is_new
212
cdef int* R
213
214
215
# total number of coset representatives that we'll find
216
n = Gamma1(N).index() / Gamma1(M).index()
217
d = arith_int.c_gcd_int(t, N/t)
218
n = n / d
219
k = 0 # number found so far
220
Ndivt = N / t
221
R = <int*> sage_malloc(sizeof(int) * (4*n))
222
if R == <int*>0:
223
raise MemoryError
224
halfmax = 2*(n+10)
225
while k < n:
226
# try to find another coset representative.
227
cc = M*random.randrange(-halfmax, halfmax+1)
228
dd = 1 + M*random.randrange(-halfmax, halfmax+1)
229
g = arith_int.c_xgcd_int(-cc,dd,&bb,&aa)
230
if g == 0: continue
231
cc = cc / g
232
if cc % M != 0: continue
233
dd = dd / g
234
if M != 1 and dd % M != 1: continue
235
# Test if we've found a new coset representative.
236
is_new = 1
237
for i from 0 <= i < k:
238
j = 4*i
239
if (R[j] - aa)%t == 0 and \
240
(R[j+1] - bb)%t == 0 and \
241
(R[j+2] - cc)%(Ndivt) == 0 and \
242
(R[j+3] - dd)%(Ndivt) == 0:
243
is_new = 0
244
break
245
# If our matrix is new add it to the list.
246
if is_new:
247
if k > n:
248
sage_free(R)
249
raise RuntimeError, "bug!!"
250
R[4*k] = aa
251
R[4*k+1] = bb
252
R[4*k+2] = cc
253
R[4*k+3] = dd
254
k = k + 1
255
256
# Return the list left multiplied by T.
257
S = []
258
for i from 0 <= i < k:
259
j = 4*i
260
S.append([R[j], R[j+1], R[j+2]*t, R[j+3]*t])
261
sage_free(R)
262
return S
263
264
def generators_helper(coset_reps, level, Mat2Z):
265
r"""
266
Helper function for generators of Gamma0, Gamma1 and GammaH.
267
268
These are computed using coset representatives, via an "inverse
269
Todd-Coxeter" algorithm, and generators for ${\rm SL}_2(\Z)$.
270
271
ALGORITHM: Given coset representatives for a finite index
272
subgroup~$G$ of ${\rm SL}_2(\Z)$ we compute generators for~$G$ as
273
follows. Let $R$ be a set of coset representatives for $G$.
274
Let $S, T \in {\rm SL}_2(\Z)$ be defined by \code{0,-1,1,0]} and
275
\code{1,1,0,1}, respectively. Define maps $s, t: R \to G$ as
276
follows. If $r \in R$, then there exists a unique $r' \in R$
277
such that $GrS = Gr'$. Let $s(r) = rSr'^{-1}$. Likewise, there
278
is a unique $r'$ such that $GrT = Gr'$ and we let $t(r) =
279
rTr'^{-1}$. Note that $s(r)$ and $t(r)$ are in $G$ for
280
all~$r$. Then $G$ is generated by $s(R)\cup t(R)$. There are
281
more sophisticated algorithms using group actions on trees
282
(and Farey symbols) that give smaller generating sets.
283
284
EXAMPLES::
285
286
sage: Gamma0(7).generators(algorithm="todd-coxeter") # indirect doctest
287
[
288
[1 1] [-1 0] [ 1 -1] [1 0] [1 1] [-3 -1] [-2 -1] [-5 -1]
289
[0 1], [ 0 -1], [ 0 1], [7 1], [0 1], [ 7 2], [ 7 3], [21 4],
290
<BLANKLINE>
291
[-4 -1] [-1 0] [ 1 0]
292
[21 5], [ 7 -1], [-7 1]
293
]
294
"""
295
cdef Matrix_integer_2x2 S,T,I,x,y,z,v,vSmod,vTmod
296
297
S = Matrix_integer_2x2(Mat2Z,[0,-1,1,0],False,True)
298
T = Matrix_integer_2x2(Mat2Z,[1,1,0,1],False,True)
299
I = Matrix_integer_2x2(Mat2Z,[1,0,0,1],False,True)
300
301
crs = coset_reps.list()
302
# print [type(lift_to_sl2z(c, d, level)) for c,d in crs]
303
try:
304
reps = [Matrix_integer_2x2(Mat2Z,lift_to_sl2z(c, d, level),False,True) for c,d in crs]
305
except:
306
raise ArithmeticError, "Error lifting to SL2Z: level=%s crs=%s" % (level, crs)
307
ans = []
308
for i from 0 <= i < len(crs):
309
x = reps[i]
310
v = Matrix_integer_2x2(Mat2Z,[crs[i][0],crs[i][1],0,0],False,True)
311
vSmod = (v*S)
312
vTmod = (v*T)
313
y_index = coset_reps.normalize(vSmod[0,0],vSmod[0,1])
314
z_index = coset_reps.normalize(vTmod[0,0],vTmod[0,1])
315
y_index = crs.index(y_index)
316
z_index = crs.index(z_index)
317
y = reps[y_index]
318
z = reps[z_index]
319
y = y._invert_unit()
320
z = z._invert_unit()
321
ans.append(x*S*y)
322
ans.append(x*T*z)
323
output = []
324
for x in ans:
325
if (x[0,0] != 1) or \
326
(x[0,1] != 0) or \
327
(x[1,0] != 0) or \
328
(x[1,1] != 1):
329
output.append(x)
330
# should be able to do something like:
331
# ans = [x for x in ans if x != I]
332
# however, this raises a somewhat mysterious error:
333
# <type 'exceptions.SystemError'>: error return without exception set
334
return output
335
336
337
338