Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/arithgroup/tests.py
4047 views
1
r"""
2
Testing Arithmetic subgroup
3
"""
4
################################################################################
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
################################################################################
15
16
from arithgroup_perm import ArithmeticSubgroup_Permutation, EvenArithmeticSubgroup_Permutation, OddArithmeticSubgroup_Permutation
17
from sage.modular.arithgroup.all import Gamma, Gamma0, Gamma1, GammaH
18
from sage.rings.finite_rings.integer_mod_ring import Zmod
19
20
import sage.misc.prandom as prandom
21
from sage.misc.misc import cputime
22
23
def random_even_arithgroup(index,nu2_max=None,nu3_max=None):
24
r"""
25
Return a random even arithmetic subgroup
26
27
EXAMPLES::
28
29
sage: import sage.modular.arithgroup.tests as tests
30
sage: G = tests.random_even_arithgroup(30); G # random
31
Arithmetic subgroup of index 30
32
sage: G.is_even()
33
True
34
"""
35
from sage.groups.perm_gps.permgroup import PermutationGroup
36
37
test = False
38
39
if nu2_max is None:
40
nu2_max = index//5
41
elif nu2_max == 0:
42
assert index%2 == 0
43
if nu3_max is None:
44
nu3_max = index//7
45
elif nu3_max == 0:
46
assert index%3 == 0
47
48
while not test:
49
nu2 = prandom.randint(0,nu2_max)
50
nu2 = index%2 + nu2*2
51
nu3 = prandom.randint(0,nu3_max)
52
nu3 = index%3 + nu3*3
53
54
l = range(1,index+1)
55
prandom.shuffle(l)
56
S2 = []
57
for i in xrange(nu2):
58
S2.append((l[i],))
59
for i in xrange(nu2,index,2):
60
S2.append((l[i],l[i+1]))
61
prandom.shuffle(l)
62
S3 = []
63
for i in xrange(nu3):
64
S3.append((l[i],))
65
for i in xrange(nu3,index,3):
66
S3.append((l[i],l[i+1],l[i+2]))
67
G = PermutationGroup([S2,S3])
68
test = G.is_transitive()
69
70
return ArithmeticSubgroup_Permutation(S2=S2,S3=S3)
71
72
def random_odd_arithgroup(index,nu3_max=None):
73
r"""
74
Return a random odd arithmetic subgroup
75
76
EXAMPLES::
77
78
sage: from sage.modular.arithgroup.tests import random_odd_arithgroup
79
sage: G = random_odd_arithgroup(20); G #random
80
Arithmetic subgroup of index 20
81
sage: G.is_odd()
82
True
83
"""
84
assert index%4 == 0
85
G = random_even_arithgroup(index//2,nu2_max=0,nu3_max=nu3_max)
86
return G.one_odd_subgroup(random=True)
87
88
class Test:
89
r"""
90
Testing class for arithmetic subgroup implemented via permutations.
91
"""
92
def __init__(self, index=20, index_max=50, odd_probability=0.5):
93
r"""
94
Create an arithmetic subgroup testing object.
95
96
INPUT:
97
98
- ``index`` - the index of random subgroup to test
99
100
- ``index_max`` - the maximum index for congruence subgroup to test
101
102
EXAMPLES::
103
104
sage: from sage.modular.arithgroup.tests import Test
105
sage: Test()
106
Arithmetic subgroup testing class
107
"""
108
self.congroups = []
109
i = 1
110
self.odd_probability = odd_probability
111
if index%2:
112
self.odd_probability=0
113
while Gamma(i).index() < index_max:
114
self.congroups.append(Gamma(i))
115
i += 1
116
i = 1
117
while Gamma0(i).index() < index_max:
118
self.congroups.append(Gamma0(i))
119
i += 1
120
i = 2
121
while Gamma1(i).index() < index_max:
122
self.congroups.append(Gamma1(i))
123
M = Zmod(i)
124
U = filter(lambda x: x.is_unit(), M)
125
for j in xrange(1,len(U)-1):
126
self.congroups.append(GammaH(i,prandom.sample(U,j)))
127
i += 1
128
129
self.index = index
130
131
def __repr__(self):
132
r"""
133
Return the string representation of self
134
135
EXAMPLES::
136
137
sage: from sage.modular.arithgroup.tests import Test
138
sage: Test().__repr__()
139
'Arithmetic subgroup testing class'
140
"""
141
return "Arithmetic subgroup testing class"
142
143
def _do(self, name):
144
"""
145
Perform the test 'test_name', where name is specified as an
146
argument. This function exists to avoid a call to eval.
147
148
EXAMPLES::
149
150
sage: from sage.modular.arithgroup.tests import Test
151
sage: Test()._do("random")
152
test_random
153
...
154
"""
155
156
print "test_%s"%name
157
Test.__dict__["test_%s"%name](self)
158
159
def random(self, seconds=0):
160
"""
161
Perform random tests for a given number of seconds, or
162
indefinitely if seconds is not specified.
163
164
EXAMPLES::
165
166
sage: from sage.modular.arithgroup.tests import Test
167
sage: Test().random(1)
168
test_random
169
...
170
"""
171
self.test("random", seconds)
172
173
def test(self, name, seconds=0):
174
"""
175
Repeatedly run 'test_name', where name is passed as an
176
argument. If seconds is nonzero, run for that many seconds. If
177
seconds is 0, run indefinitely.
178
179
EXAMPLES::
180
181
sage: from sage.modular.arithgroup.tests import Test
182
sage: T = Test()
183
sage: T.test('relabel',seconds=1)
184
test_relabel
185
...
186
sage: T.test('congruence_groups',seconds=1)
187
test_congruence_groups
188
...
189
sage: T.test('contains',seconds=1)
190
test_contains
191
...
192
sage: T.test('todd_coxeter',seconds=1)
193
test_todd_coxeter
194
...
195
"""
196
seconds = float(seconds)
197
total = cputime()
198
n = 1
199
while seconds == 0 or cputime(total) < seconds:
200
s = "** test_dimension: number %s"%n
201
if seconds > 0:
202
s += " (will stop after about %s seconds)"%seconds
203
t = cputime()
204
self._do(name)
205
print "\ttime=%s\telapsed=%s"%(cputime(t),cputime(total))
206
n += 1
207
208
def test_random(self):
209
"""
210
Do a random test from all the possible tests.
211
212
EXAMPLES::
213
214
sage: from sage.modular.arithgroup.tests import Test
215
sage: Test().test_random() #random
216
Doing random test
217
"""
218
tests = [a for a in Test.__dict__.keys() if a[:5] == "test_" and a != "test_random"]
219
name = prandom.choice(tests)
220
print "Doing random test %s"%name
221
Test.__dict__[name](self)
222
223
def test_relabel(self):
224
r"""
225
Try the function canonic labels for a random even modular subgroup.
226
227
EXAMPLES::
228
229
sage: from sage.modular.arithgroup.tests import Test
230
sage: Test().test_relabel() # random
231
"""
232
if prandom.uniform(0,1) < self.odd_probability:
233
G = random_odd_arithgroup(self.index)
234
else:
235
G = random_even_arithgroup(self.index)
236
237
G.relabel()
238
s2 = G._S2
239
s3 = G._S3
240
l = G._L
241
r = G._R
242
243
# 0 should be stabilized by the mapping
244
# used for renumbering so we start at 1
245
p = range(1,self.index)
246
247
for _ in xrange(10):
248
prandom.shuffle(p)
249
# we add 0 to the mapping
250
pp = [0] + p
251
ss2 = [None]*self.index
252
ss3 = [None]*self.index
253
ll = [None]*self.index
254
rr = [None]*self.index
255
for i in xrange(self.index):
256
ss2[pp[i]] = pp[s2[i]]
257
ss3[pp[i]] = pp[s3[i]]
258
ll[pp[i]] = pp[l[i]]
259
rr[pp[i]] = pp[r[i]]
260
if G.is_even():
261
GG = EvenArithmeticSubgroup_Permutation(ss2,ss3,ll,rr)
262
else:
263
GG = OddArithmeticSubgroup_Permutation(ss2,ss3,ll,rr)
264
GG.relabel()
265
266
for elt in ['_S2','_S3','_L','_R']:
267
if getattr(G,elt) != getattr(GG,elt):
268
print "s2 = %s" %str(s2)
269
print "s3 = %s" %str(s3)
270
print "ss2 = %s" %str(ss2)
271
print "ss3 = %s" %str(ss3)
272
print "pp = %s" %str(pp)
273
raise AssertionError, "%s does not coincide" %elt
274
275
def test_congruence_groups(self):
276
r"""
277
Check whether the different implementations of methods for congruence
278
groups and generic arithmetic group by permutations return the same
279
results.
280
281
EXAMPLES::
282
283
sage: from sage.modular.arithgroup.tests import Test
284
sage: Test().test_congruence_groups() #random
285
"""
286
G = prandom.choice(self.congroups)
287
GG = G.as_permutation_group()
288
289
if not GG.is_congruence():
290
raise AssertionError, "Hsu congruence test failed"
291
292
methods = [
293
'index',
294
'is_odd',
295
'is_even',
296
'is_normal',
297
'ncusps',
298
'nregcusps',
299
'nirregcusps',
300
'nu2',
301
'nu3',
302
'generalised_level']
303
304
for f in methods:
305
if getattr(G,f)() != getattr(GG,f)():
306
raise AssertionError, "results of %s does not coincide for %s" %(f,G)
307
308
if sorted((G.cusp_width(c) for c in G.cusps())) != GG.cusp_widths():
309
raise AssertionError, "Cusps widths are different for %s" %G
310
311
for _ in xrange(20):
312
m = GG.random_element()
313
if m not in G:
314
raise AssertionError, "random element generated by perm. group not in %s" %(str(m),str(G))
315
316
def test_contains(self):
317
r"""
318
Test whether the random generator for arithgroup perms gives matrices in
319
the group.
320
321
EXAMPLES::
322
323
sage: from sage.modular.arithgroup.tests import Test
324
sage: Test().test_contains() #random
325
"""
326
if prandom.uniform(0,1) < self.odd_probability:
327
G = random_odd_arithgroup(self.index)
328
else:
329
G = random_even_arithgroup(self.index)
330
331
for _ in xrange(20):
332
g = G.random_element()
333
if G.random_element() not in G:
334
raise AssertionError, "%s not in %s" %(g,G)
335
336
def test_spanning_trees(self):
337
r"""
338
Test coset representatives obtained from spanning trees for even
339
subgroup (Kulkarni's method with generators ``S2``, ``S3`` and Verrill's
340
method with generators ``L``, ``S2``).
341
342
EXAMPLES::
343
344
sage: from sage.modular.arithgroup.tests import Test
345
sage: Test().test_spanning_trees() #random
346
"""
347
from sage.all import prod
348
from all import SL2Z
349
from arithgroup_perm import S2m,S3m,Lm
350
351
G = random_even_arithgroup(self.index)
352
353
m = {'l':Lm, 's':S2m}
354
tree,reps,wreps,gens = G._spanning_tree_verrill()
355
assert reps[0] == SL2Z([1,0,0,1])
356
assert wreps[0] == ''
357
for i in xrange(1,self.index):
358
assert prod(m[letter] for letter in wreps[i]) == reps[i]
359
tree,reps,wreps,gens = G._spanning_tree_verrill(on_right=False)
360
assert reps[0] == SL2Z([1,0,0,1])
361
assert wreps[0] == ''
362
for i in xrange(1,self.index):
363
assert prod(m[letter] for letter in wreps[i]) == reps[i]
364
365
m = {'s2':S2m, 's3':S3m}
366
tree,reps,wreps,gens = G._spanning_tree_kulkarni()
367
assert reps[0] == SL2Z([1,0,0,1])
368
assert wreps[0] == []
369
for i in xrange(1,self.index):
370
assert prod(m[letter] for letter in wreps[i]) == reps[i]
371
tree,reps,wreps,gens = G._spanning_tree_kulkarni(on_right=False)
372
assert reps[0] == SL2Z([1,0,0,1])
373
assert wreps[0] == []
374
for i in xrange(1,self.index):
375
assert prod(m[letter] for letter in wreps[i]) == reps[i]
376
377
def test_todd_coxeter(self):
378
r"""
379
Test representatives of todd coxeter algorithm
380
381
EXAMPLES::
382
383
sage: from sage.modular.arithgroup.tests import Test
384
sage: Test().test_todd_coxeter() #random
385
"""
386
from all import SL2Z
387
from arithgroup_perm import S2m,S3m,Lm,Rm
388
389
G = random_even_arithgroup(self.index)
390
391
reps,gens,l,s2 = G.todd_coxeter_l_s2()
392
assert reps[0] == SL2Z([1,0,0,1])
393
assert len(reps) == G.index()
394
for i in xrange(1,len(reps)):
395
assert reps[i] not in G
396
assert reps[i]*S2m*~reps[s2[i]] in G
397
assert reps[i]*Lm*~reps[l[i]] in G
398
for j in xrange(i+1,len(reps)):
399
assert reps[i] * ~reps[j] not in G
400
assert reps[j] * ~reps[i] not in G
401
402
reps,gens,s2,s3 = G.todd_coxeter_s2_s3()
403
assert reps[0] == SL2Z([1,0,0,1])
404
assert len(reps) == G.index()
405
for i in xrange(1,len(reps)):
406
assert reps[i] not in G
407
assert reps[i]*S2m*~reps[s2[i]] in G
408
assert reps[i]*S3m*~reps[s3[i]] in G
409
for j in xrange(i+1,len(reps)):
410
assert reps[i] * ~reps[j] not in G
411
assert reps[j] * ~reps[i] not in G
412
413
414