Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/abvar/torsion_subgroup.py
4100 views
1
"""
2
Torsion subgroups of modular abelian varieties
3
4
Sage can compute information about the structure of the torsion
5
subgroup of a modular abelian variety. Sage computes a multiple of
6
the order by computing the greatest common divisor of the orders of
7
the torsion subgroup of the reduction of the abelian variety modulo
8
p for various primes p. Sage computes a divisor of the order by
9
computing the rational cuspidal subgroup. When these two bounds
10
agree (which is often the case), we determine the exact structure
11
of the torsion subgroup.
12
13
AUTHORS:
14
15
- William Stein (2007-03)
16
17
EXAMPLES: First we consider `J_0(50)` where everything
18
works out nicely::
19
20
sage: J = J0(50)
21
sage: T = J.rational_torsion_subgroup(); T
22
Torsion subgroup of Abelian variety J0(50) of dimension 2
23
sage: T.multiple_of_order()
24
15
25
sage: T.divisor_of_order()
26
15
27
sage: T.gens()
28
[[(1/15, 3/5, 2/5, 14/15)]]
29
sage: T.invariants()
30
[15]
31
sage: d = J.decomposition(); d
32
[
33
Simple abelian subvariety 50a(1,50) of dimension 1 of J0(50),
34
Simple abelian subvariety 50b(1,50) of dimension 1 of J0(50)
35
]
36
sage: d[0].rational_torsion_subgroup().order()
37
3
38
sage: d[1].rational_torsion_subgroup().order()
39
5
40
41
Next we make a table of the upper and lower bounds for each new
42
factor.
43
44
::
45
46
sage: for N in range(1,38):
47
... for A in J0(N).new_subvariety().decomposition():
48
... T = A.rational_torsion_subgroup()
49
... print '%-5s%-5s%-5s%-5s'%(N, A.dimension(), T.divisor_of_order(), T.multiple_of_order())
50
11 1 5 5
51
14 1 6 6
52
15 1 8 8
53
17 1 4 4
54
19 1 3 3
55
20 1 6 6
56
21 1 8 8
57
23 2 11 11
58
24 1 8 8
59
26 1 3 3
60
26 1 7 7
61
27 1 3 3
62
29 2 7 7
63
30 1 6 12
64
31 2 5 5
65
32 1 4 4
66
33 1 4 4
67
34 1 6 6
68
35 1 3 3
69
35 2 16 16
70
36 1 6 6
71
37 1 1 1
72
37 1 3 3
73
74
TESTS::
75
76
sage: T = J0(54).rational_torsion_subgroup()
77
sage: loads(dumps(T)) == T
78
True
79
"""
80
81
###########################################################################
82
# Copyright (C) 2007 William Stein <[email protected]> #
83
# Distributed under the terms of the GNU General Public License (GPL) #
84
# http://www.gnu.org/licenses/ #
85
###########################################################################
86
87
from sage.modules.module import Module
88
from finite_subgroup import FiniteSubgroup, TorsionPoint
89
from sage.rings.all import divisors, gcd, ZZ, prime_range
90
from sage.sets.primes import Primes
91
from sage.modular.arithgroup.all import is_Gamma0
92
93
class RationalTorsionSubgroup(FiniteSubgroup):
94
"""
95
The torsion subgroup of a modular abelian variety.
96
"""
97
def __init__(self, abvar):
98
"""
99
Create the torsion subgroup.
100
101
INPUT:
102
103
104
- ``abvar`` - a modular abelian variety
105
106
107
EXAMPLES::
108
109
sage: T = J0(14).rational_torsion_subgroup(); T
110
Torsion subgroup of Abelian variety J0(14) of dimension 1
111
sage: type(T)
112
<class 'sage.modular.abvar.torsion_subgroup.RationalTorsionSubgroup'>
113
"""
114
FiniteSubgroup.__init__(self, abvar)
115
116
def _repr_(self):
117
"""
118
Return string representation of this torsion subgroup.
119
120
EXAMPLES::
121
122
sage: T = J1(13).rational_torsion_subgroup(); T
123
Torsion subgroup of Abelian variety J1(13) of dimension 2
124
sage: T._repr_()
125
'Torsion subgroup of Abelian variety J1(13) of dimension 2'
126
"""
127
return "Torsion subgroup of %s"%self.abelian_variety()
128
129
def __cmp__(self, other):
130
"""
131
Compare torsion subgroups.
132
133
INPUT:
134
135
136
- ``other`` - an object
137
138
139
If other is a torsion subgroup, the abelian varieties are compared.
140
Otherwise, the generic behavior for finite abelian variety
141
subgroups is used.
142
143
EXAMPLE::
144
145
sage: G = J0(11).rational_torsion_subgroup(); H = J0(13).rational_torsion_subgroup()
146
sage: G == G
147
True
148
sage: G < H # since 11 < 13
149
True
150
sage: G > H
151
False
152
sage: G < 5 # random (meaningless since it depends on memory layout)
153
False
154
"""
155
if isinstance(other, RationalTorsionSubgroup):
156
return cmp(self.abelian_variety(), other.abelian_variety())
157
return FiniteSubgroup.__cmp__(self, other)
158
159
def order(self):
160
"""
161
Return the order of the torsion subgroup of this modular abelian
162
variety.
163
164
This may fail if the multiple obtained by counting points modulo
165
`p` exceeds the divisor obtained from the rational cuspidal
166
subgroup.
167
168
EXAMPLES::
169
170
sage: a = J0(11)
171
sage: a.rational_torsion_subgroup().order()
172
5
173
sage: a = J0(23)
174
sage: a.rational_torsion_subgroup().order()
175
11
176
sage: t = J0(37)[1].rational_torsion_subgroup()
177
sage: t.order()
178
3
179
"""
180
try:
181
return self._order
182
except AttributeError:
183
pass
184
O = self.possible_orders()
185
if len(O) == 1:
186
n = O[0]
187
self._order = n
188
return n
189
raise RuntimeError, "Unable to compute order of torsion subgroup (it is in %s)"%O
190
191
def lattice(self):
192
"""
193
Return lattice that defines this torsion subgroup, if possible.
194
195
.. warning::
196
197
There is no known algorithm in general to compute the
198
rational torsion subgroup. Use rational_cusp_group to
199
obtain a subgroup of the rational torsion subgroup in
200
general.
201
202
EXAMPLES::
203
204
sage: J0(11).rational_torsion_subgroup().lattice()
205
Free module of degree 2 and rank 2 over Integer Ring
206
Echelon basis matrix:
207
[ 1 0]
208
[ 0 1/5]
209
210
The following fails because in fact I know of no (reasonable)
211
algorithm to provably compute the torsion subgroup in general.
212
213
::
214
215
sage: T = J0(33).rational_torsion_subgroup()
216
sage: T.lattice()
217
Traceback (most recent call last):
218
...
219
NotImplementedError: unable to compute the rational torsion subgroup in this case (there is no known general algorithm yet)
220
221
The problem is that the multiple of the order obtained by counting
222
points over finite fields is twice the divisor of the order got
223
from the rational cuspidal subgroup.
224
225
::
226
227
sage: T.multiple_of_order(30)
228
200
229
sage: J0(33).rational_cusp_subgroup().order()
230
100
231
"""
232
A = self.abelian_variety()
233
if A.dimension() == 0:
234
return []
235
R = A.rational_cusp_subgroup()
236
if R.order() == self.multiple_of_order():
237
return R.lattice()
238
else:
239
raise NotImplementedError, "unable to compute the rational torsion subgroup in this case (there is no known general algorithm yet)"
240
241
def possible_orders(self):
242
"""
243
Return the possible orders of this torsion subgroup, computed from
244
a known divisor and multiple of the order.
245
246
EXAMPLES::
247
248
sage: J0(11).rational_torsion_subgroup().possible_orders()
249
[5]
250
sage: J0(33).rational_torsion_subgroup().possible_orders()
251
[100, 200]
252
253
Note that this function has not been implemented for `J_1(N)`,
254
though it should be reasonably easy to do so soon (see Conrad,
255
Edixhoven, Stein)::
256
257
sage: J1(13).rational_torsion_subgroup().possible_orders()
258
Traceback (most recent call last):
259
...
260
NotImplementedError: torsion multiple only implemented for Gamma0
261
"""
262
try:
263
return self._possible_orders
264
except AttributeError:
265
pass
266
u = self.multiple_of_order()
267
l = self.divisor_of_order()
268
assert u % l == 0
269
O = [l * d for d in divisors(u//l)]
270
self._possible_orders = O
271
return O
272
273
def divisor_of_order(self):
274
"""
275
Return a divisor of the order of this torsion subgroup of a modular
276
abelian variety.
277
278
EXAMPLES::
279
280
sage: t = J0(37)[1].rational_torsion_subgroup()
281
sage: t.divisor_of_order()
282
3
283
"""
284
A = self.abelian_variety()
285
if A.dimension() == 0:
286
return ZZ(1)
287
R = A.rational_cusp_subgroup()
288
return R.order()
289
290
def multiple_of_order(self, maxp=None):
291
"""
292
Return a multiple of the order of this torsion group.
293
294
The multiple is computed using characteristic polynomials of Hecke
295
operators of odd index not dividing the level.
296
297
INPUT:
298
299
300
- ``maxp`` - (default: None) If maxp is None (the
301
default), return gcd of best bound computed so far with bound
302
obtained by computing GCD's of orders modulo p until this gcd
303
stabilizes for 3 successive primes. If maxp is given, just use all
304
primes up to and including maxp.
305
306
307
EXAMPLES::
308
309
sage: J = J0(11)
310
sage: G = J.rational_torsion_subgroup()
311
sage: G.multiple_of_order(11)
312
5
313
sage: J = J0(389)
314
sage: G = J.rational_torsion_subgroup(); G
315
Torsion subgroup of Abelian variety J0(389) of dimension 32
316
sage: G.multiple_of_order()
317
97
318
sage: [G.multiple_of_order(p) for p in prime_range(3,11)]
319
[92645296242160800, 7275, 291]
320
sage: [G.multiple_of_order(p) for p in prime_range(3,13)]
321
[92645296242160800, 7275, 291, 97]
322
sage: [G.multiple_of_order(p) for p in prime_range(3,19)]
323
[92645296242160800, 7275, 291, 97, 97, 97]
324
325
::
326
327
sage: J = J0(33) * J0(11) ; J.rational_torsion_subgroup().order()
328
Traceback (most recent call last):
329
...
330
NotImplementedError: torsion multiple only implemented for Gamma0
331
332
The next example illustrates calling this function with a larger
333
input and how the result may be cached when maxp is None::
334
335
sage: T = J0(43)[1].rational_torsion_subgroup()
336
sage: T.multiple_of_order()
337
14
338
sage: T.multiple_of_order(50)
339
7
340
sage: T.multiple_of_order()
341
7
342
"""
343
if maxp is None:
344
try:
345
return self.__multiple_of_order
346
except AttributeError:
347
pass
348
bnd = ZZ(0)
349
A = self.abelian_variety()
350
if A.dimension() == 0:
351
T = ZZ(1)
352
self.__multiple_of_order = T
353
return T
354
N = A.level()
355
if not (len(A.groups()) == 1 and is_Gamma0(A.groups()[0])):
356
# to generalize to this case, you'll need to
357
# (1) define a charpoly_of_frob function:
358
# this is tricky because I don't know a simple
359
# way to do this for Gamma1 and GammaH. Will
360
# probably have to compute explicit matrix for
361
# <p> operator (add to modular symbols code),
362
# then compute some charpoly involving
363
# that directly...
364
# (2) use (1) -- see my MAGMA code.
365
raise NotImplementedError, "torsion multiple only implemented for Gamma0"
366
cnt = 0
367
if maxp is None:
368
X = Primes()
369
else:
370
X = prime_range(maxp+1)
371
for p in X:
372
if (2*N) % p == 0:
373
continue
374
375
f = A.hecke_polynomial(p)
376
b = ZZ(f(p+1))
377
378
if bnd == 0:
379
bnd = b
380
else:
381
bnd_last = bnd
382
bnd = ZZ(gcd(bnd, b))
383
if bnd == bnd_last:
384
cnt += 1
385
else:
386
cnt = 0
387
if maxp is None and cnt >= 2:
388
break
389
390
# The code below caches the computed bound and
391
# will be used if this function is called
392
# again with maxp equal to None (the default).
393
if maxp is None:
394
# maxp is None but self.__multiple_of_order is
395
# not set, since otherwise we would have immediately
396
# returned at the top of this function
397
self.__multiple_of_order = bnd
398
else:
399
# maxp is given -- record new info we get as
400
# a gcd...
401
try:
402
self.__multiple_of_order = gcd(self.__multiple_of_order, bnd)
403
except AttributeError:
404
# ... except in the case when self.__multiple_of_order
405
# was never set. In this case, we just set
406
# it as long as the gcd stabilized for 3 in a row.
407
if cnt >= 2:
408
self.__multiple_of_order = bnd
409
return bnd
410
411
412
413
class QQbarTorsionSubgroup(Module):
414
def __init__(self, abvar):
415
"""
416
Group of all torsion points over the algebraic closure on an
417
abelian variety.
418
419
INPUT:
420
421
422
- ``abvar`` - an abelian variety
423
424
425
EXAMPLES::
426
427
sage: A = J0(23)
428
sage: A.qbar_torsion_subgroup()
429
Group of all torsion points in QQbar on Abelian variety J0(23) of dimension 2
430
"""
431
self.__abvar = abvar
432
Module.__init__(self, ZZ)
433
434
def _repr_(self):
435
"""
436
Print representation of QQbar points.
437
438
OUTPUT: string
439
440
EXAMPLES::
441
442
sage: J0(23).qbar_torsion_subgroup()._repr_()
443
'Group of all torsion points in QQbar on Abelian variety J0(23) of dimension 2'
444
"""
445
return 'Group of all torsion points in QQbar on %s'%self.__abvar
446
447
def field_of_definition(self):
448
"""
449
Return the field of definition of this subgroup. Since this is the
450
group of all torsion it is defined over the base field of this
451
abelian variety.
452
453
OUTPUT: a field
454
455
EXAMPLES::
456
457
sage: J0(23).qbar_torsion_subgroup().field_of_definition()
458
Rational Field
459
"""
460
return self.__abvar.base_field()
461
462
def __call__(self, x):
463
r"""
464
Create an element in this finite group.
465
466
INPUT:
467
468
469
- ``x`` - vector in `\QQ^{2d}`
470
471
472
OUTPUT: torsion point
473
474
EXAMPLES::
475
476
sage: P = J0(23).qbar_torsion_subgroup()([1,1/2,3/4,2]); P
477
[(1, 1/2, 3/4, 2)]
478
sage: P.order()
479
4
480
"""
481
v = self.__abvar.vector_space()(x)
482
return TorsionPoint(self, v)
483
484
def abelian_variety(self):
485
"""
486
Return the abelian variety that this is the set of all torsion
487
points on.
488
489
OUTPUT: abelian variety
490
491
EXAMPLES::
492
493
sage: J0(23).qbar_torsion_subgroup().abelian_variety()
494
Abelian variety J0(23) of dimension 2
495
"""
496
return self.__abvar
497
498
499