Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
r"""
2
Siegel modular forms
3
4
Implementation of a class describing (scalar and vector valued) Siegel
5
modular forms of degree 2 and arbitrary group and weight.
6
7
8
AUTHORS:
9
10
- CC: Craig Citro
11
12
- MR: Martin Raum
13
14
- NR: Nathan Ryan
15
16
- NS: Nils-Peter Skoruppa
17
18
19
HISTORY:
20
21
- NS: Class SiegelModularForm_class.
22
23
- NS: Factory function SiegelModularForm().
24
Code parts concerning the Maass lift are partly based on code
25
written by David Gruenewald in August 2006 which in turn is
26
based on the PARI/GP code by Nils-Peter Skoruppa from 2003.
27
28
- CC, NR: _mult_, _reduce_GL using Cython.
29
30
- NR: Hecke operators.
31
32
- CC: Rewriting of fastmult.spyx for arbitrary base rings.
33
34
- NS: Class Morp.
35
36
- MR, NS: SiegelModularFormsAlgebra_class, SiegelModularFormsAlgebra
37
38
39
REFERENCES:
40
41
- [Sko] Nils-Peter Skoruppa, ...
42
43
- [I-H] Tomoyoshi Ibukiyama and Shuichi Hayashida, ...
44
"""
45
46
#*****************************************************************************
47
# Copyright (C) 2008 Nils-Peter Skoruppa <[email protected]>
48
#
49
# Distributed under the terms of the GNU General Public License (GPL)
50
# http://www.gnu.org/licenses/
51
#*****************************************************************************
52
53
54
import cPickle
55
import urllib
56
from siegel_modular_form_prec import SiegelModularFormPrecision
57
from sage.rings.all import ZZ
58
from sage.algebras.all import AlgebraElement
59
60
SMF_DEFAULT_PREC = 101
61
62
class SiegelModularForm_class(AlgebraElement):
63
r"""
64
Describes a Siegel modular form of degree 2.
65
"""
66
def __init__(self, parent, weight, coeffs, prec=SMF_DEFAULT_PREC, name=None):
67
r"""
68
Create a Siegel modular form of degree 2.
69
70
INPUT:
71
72
- ``parent`` -- SiegelModularFormsAlgebra (ambient space).
73
74
- ``weight`` -- the weight of the form.
75
76
- ``coeffs`` -- a dictionary whose keys are triples `(a,b,c)`
77
of integers representing `GL(2,\ZZ)`-reduced quadratic forms
78
(i.e. forms satisfying `0 \le b \le a \le c`).
79
80
- ``name`` -- an optional string giving a name to the form,
81
e.g. 'Igusa_4'. This modifies the text and latex
82
representations of the form.
83
84
OUTPUT:
85
86
- a Siegel modular form
87
88
EXAMPLES::
89
90
sage: E10 = ModularForms(1, 10).0
91
sage: Delta = CuspForms(1, 12).0
92
sage: F = SiegelModularForm(E10, Delta); F
93
Siegel modular form on Sp(4,Z) of weight 10
94
95
TESTS::
96
97
sage: TestSuite(F).run()
98
"""
99
self.__group = parent.group()
100
self.__weight = weight
101
self.__coeffs = coeffs
102
# TODO: check whether we have enough coeffs
103
self.__coeff_ring = parent.coeff_ring()
104
self.__precision = SiegelModularFormPrecision(prec)
105
self.__prec = _normalized_prec(prec)
106
self.__name = name
107
self.__rep_lists = dict()
108
AlgebraElement.__init__(self, parent)
109
110
def base_ring(self):
111
"""
112
Return the ring of coefficients of the Siegel modular form ``self``.
113
114
EXAMPLES::
115
116
sage: S = SiegelModularFormsAlgebra()
117
sage: A = S.gen(0)
118
sage: A.base_ring()
119
Integer Ring
120
sage: C = S.gen(2)
121
sage: onehalfC = C * (-1/2)
122
sage: onehalfC.base_ring()
123
Rational Field
124
sage: B = S.gen(1)
125
sage: AB = A.satoh_bracket(B)
126
sage: AB.base_ring()
127
Multivariate Polynomial Ring in x, y over Rational Field
128
"""
129
return self.__coeff_ring
130
131
def _repr_(self):
132
r"""
133
Return the plain text representation of ``self``.
134
135
EXAMPLES::
136
137
sage: C = SiegelModularFormsAlgebra().gen(2)
138
sage: C._repr_()
139
'Igusa_10'
140
sage: (C^2)._repr_()
141
'Siegel modular form on Sp(4,Z) of weight 20'
142
"""
143
if self.name() is None:
144
return 'Siegel modular form on %s of weight %d' % (self.group(), self.weight())
145
else:
146
return self.name()
147
148
def _latex_(self):
149
r"""
150
Return the latex representation of ``self``.
151
152
EXAMPLES::
153
154
sage: A = SiegelModularFormsAlgebra().gen(0)
155
sage: A._latex_()
156
'Igusa_4'
157
sage: (A^2)._latex_()
158
'\\texttt{Siegel modular form on }Sp(4,Z)\\texttt{ of weight }8'
159
"""
160
if self.name() is None:
161
return r'\texttt{Siegel modular form on }%s\texttt{ of weight }%d' % (self.group(), self.weight())
162
else:
163
return self.name()
164
165
def group(self):
166
r"""
167
Return the modular group of ``self`` as a string.
168
169
EXAMPLES::
170
171
sage: C = SiegelModularFormsAlgebra().gen(2)
172
sage: C.group()
173
'Sp(4,Z)'
174
"""
175
return self.__group
176
177
def weight(self):
178
r"""
179
Return the weight of ``self``.
180
181
EXAMPLES::
182
183
sage: A, B, C, D = SiegelModularFormsAlgebra().gens()
184
sage: A.weight()
185
4
186
sage: B.weight()
187
6
188
sage: C.weight()
189
10
190
sage: D.weight()
191
12
192
sage: (A * B).weight()
193
10
194
sage: (A*B + C).weight()
195
10
196
"""
197
return self.__weight
198
199
def precision(self):
200
r"""
201
Return the Precision class object that describes the precision of ``self``.
202
203
EXAMPLES::
204
205
sage: A = SiegelModularFormsAlgebra().gen(0)
206
sage: A.precision()
207
Discriminant precision for Siegel modular form with bound 101
208
"""
209
return self.__precision
210
211
def __getitem__(self, key):
212
r"""
213
Return the coefficient indexed by ``key`` in the Fourier expansion
214
of ``self``.
215
216
INPUT:
217
218
- ``key`` -- a triple of integers `(a, b, c)` defining a quadratic form
219
220
OUTPUT:
221
222
- the coefficient of `q^{(a,b,c)}` as an element of the coefficient
223
ring of ``self``
224
225
EXAMPLES::
226
227
sage: A, B, C, D = SiegelModularFormsAlgebra().gens()
228
sage: A[(0, 0, 10)]
229
272160
230
sage: A[(0, 0, 25)]
231
3780240
232
sage: A[(5, 0, 5)]
233
97554240
234
sage: A[(0, 0, 26)]
235
Traceback (most recent call last):
236
...
237
ValueError: precision 101 is not high enough to extract coefficient at (0, 0, 26)
238
sage: A[(100, 0, 1)]
239
Traceback (most recent call last):
240
...
241
ValueError: precision 101 is not high enough to extract coefficient at (100, 0, 1)
242
sage: C[(2, 1, 3)]
243
2736
244
sage: C[(3, 1, 2)]
245
2736
246
247
Any coefficient indexed by a quadratic form that is not semi-positive
248
definite is by definition zero::
249
250
sage: A[(-1, 1, 1)]
251
0
252
sage: A[(1, 10, 1)]
253
0
254
255
TESTS::
256
257
sage: A[(1/2, 0, 6)]
258
Traceback (most recent call last):
259
...
260
TypeError: the key (1/2, 0, 6) must be an integral quadratic form
261
"""
262
a, b, c = key
263
try:
264
a = ZZ(a)
265
b = ZZ(b)
266
c = ZZ(c)
267
except TypeError:
268
raise TypeError, "the key %s must be an integral quadratic form" %str(key)
269
270
if b**2 - 4*a*c > 0 or a < 0 or c < 0:
271
return self.base_ring()(0)
272
## otherwise we have a semi-positive definite form
273
if self.__coeffs.has_key((a, b, c)):
274
return self.__coeffs[(a, b, c)]
275
## otherwise GL2(ZZ)-reduce (a,b,c) and try again
276
from fastmult import reduce_GL
277
(a0, b0, c0) = reduce_GL(a, b, c)
278
if self.precision().is_in_bound((a0, b0, c0)):
279
## return get_coeff_with_action( a,b,c,self.coeffs(),self.base_ring())
280
return self.__coeffs.get((a0, b0, c0), self.base_ring()(0))
281
## otherwise error - precision is too low
282
raise ValueError, 'precision %s is not high enough to extract coefficient at %s' %(self.prec(), str(key))
283
284
def coeffs(self, disc=None):
285
r"""
286
Return the dictionary of coefficients of ``self``. If ``disc`` is
287
specified, return the dictionary of coefficients indexed by
288
semi-positive definite quadratic forms of discriminant ``disc``.
289
290
INPUT:
291
292
- ``disc`` -- optional (default: None); a negative integer giving
293
the discriminant of a semi-positive definite quadratic form
294
295
EXAMPLES::
296
297
sage: A, B, C, D = SiegelModularFormsAlgebra().gens(prec=20)
298
sage: C.coeffs().has_key((3, 0, 1))
299
False
300
sage: C.coeffs().has_key((1, 0, 3))
301
True
302
sage: C.coeffs()[(1, 0, 3)]
303
-272
304
sage: len(D.coeffs(disc=-16).keys())
305
2
306
sage: D.coeffs(disc=-16)[(2, 0, 2)]
307
17600
308
309
TESTS::
310
311
sage: A.coeffs(disc=-20)
312
Traceback (most recent call last):
313
...
314
ValueError: precision is not high enough to extract coefficients of discriminant -20
315
"""
316
if disc is None:
317
return self.__coeffs
318
elif -disc < self.prec():
319
if disc < 0 and (disc % 4) in [0, 1]:
320
from sage.quadratic_forms.binary_qf import BinaryQF_reduced_representatives
321
forms = [f[:] for f in BinaryQF_reduced_representatives(disc)]
322
return dict([(Q, self[Q]) for Q in forms])
323
else:
324
return {}
325
else:
326
raise ValueError, 'precision is not high enough to extract coefficients of discriminant %s' %disc
327
328
def support(self):
329
r"""
330
Return the support of ``self``, i.e. the list of reduced quadratic
331
forms indexing non-zero Fourier coefficients of ``self``.
332
333
EXAMPLES::
334
335
sage: A, B, C, D = SiegelModularFormsAlgebra().gens(prec=15)
336
sage: A.support()
337
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (1, 0, 1), (1, 0, 2), (1, 0, 3), (1, 1, 1), (1, 1, 2), (1, 1, 3), (2, 2, 2)]
338
sage: (0, 0, 2) in C._keys()
339
True
340
sage: C[(0, 0, 2)]
341
0
342
sage: (0, 0, 2) in C.support()
343
False
344
"""
345
return [k for k in self._keys() if self[k] != 0]
346
347
def max_disc(self):
348
r"""
349
Return the largest discriminant corresponding to a non-zero Fourier
350
coefficient of ``self``.
351
352
Note that since these discriminants are all non-positive, this
353
corresponds in some sense to the "smallest" non-zero Fourier
354
coefficient. It is analogous to the valuation of a power series
355
(=smallest degree of a non-zero term).
356
357
EXAMPLES::
358
359
sage: gens = SiegelModularFormsAlgebra().gens()
360
sage: [f.max_disc() for f in gens]
361
[0, 0, -3, -3]
362
"""
363
return max([b**2 - 4*a*c for (a, b, c) in self.support()])
364
365
def _keys(self):
366
r"""
367
Return the keys of the dictionary of coefficients of ``self``.
368
369
EXAMPLES::
370
371
sage: A, B, C, D = SiegelModularFormsAlgebra().gens(prec=15)
372
sage: A._keys()
373
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (1, 0, 1), (1, 0, 2), (1, 0, 3), (1, 1, 1), (1, 1, 2), (1, 1, 3), (2, 2, 2)]
374
"""
375
return sorted(self.coeffs().keys())
376
377
def prec(self):
378
r"""
379
Return the precision of ``self``.
380
381
EXAMPLES::
382
383
sage: B = SiegelModularFormsAlgebra().gen(1)
384
sage: B.prec()
385
101
386
"""
387
return self.precision().prec()
388
389
def name(self):
390
r"""
391
Return the name of the Siegel modular form ``self``, or None if
392
``self`` does not have a custom name.
393
394
EXAMPLES::
395
396
sage: A, B = SiegelModularFormsAlgebra().gens()[:2]
397
sage: A.name()
398
'Igusa_4'
399
sage: (A*B).name() is None
400
True
401
"""
402
return self.__name
403
404
def truncate(self, prec):
405
r"""
406
Return a Siegel modular form with the same parent as ``self``, but
407
with Fourier expansion truncated at the new precision ``prec``.
408
409
EXAMPLES::
410
411
sage: A = SiegelModularFormsAlgebra().gen(0, prec=20); A
412
Igusa_4
413
sage: A.prec()
414
20
415
sage: len(A._keys())
416
18
417
sage: A[(1, 1, 5)]
418
1330560
419
sage: At = A.truncate(16); At
420
Igusa_4
421
sage: At.prec()
422
16
423
sage: len(At._keys())
424
14
425
sage: At[(1, 1, 5)]
426
Traceback (most recent call last):
427
...
428
ValueError: precision 16 is not high enough to extract coefficient at (1, 1, 5)
429
sage: At[(1, 1, 4)] == A[(1, 1, 4)]
430
True
431
432
TESTS::
433
sage: A.truncate(30)
434
Traceback (most recent call last):
435
...
436
ValueError: truncated precision 30 cannot be larger than the current precision 20
437
"""
438
if prec > self.prec():
439
raise ValueError, 'truncated precision %s cannot be larger than the current precision %s' %(prec, self.prec())
440
else:
441
return _SiegelModularForm_from_dict(group=self.group(), weight=self.weight(), coeffs=self.coeffs(), prec=prec, parent=None, name=self.name())
442
443
################
444
## Arithmetic ##
445
################
446
447
def _add_(left, right):
448
r"""
449
Return the sum of ``left`` and ``right``.
450
451
There are some compatibility conditions that the forms ``left``
452
and ``right`` must satisfy in order for addition to work:
453
454
- they must have the same weight
455
- they must be defined on the same group, or one of them must
456
be defined on the whole group 'Sp(4,Z)'
457
458
The precision of the sum of ``left`` and ``right`` is the minimum
459
of the precisions of ``left`` and ``right``.
460
461
EXAMPLES::
462
463
sage: A, B, C, D = SiegelModularFormsAlgebra().gens()
464
sage: twoA = A + A
465
sage: A2 = A * 2
466
sage: A2 == twoA
467
True
468
sage: A*B + C
469
Siegel modular form on Sp(4,Z) of weight 10
470
sage: E = C._add_(A*B)
471
sage: E
472
Siegel modular form on Sp(4,Z) of weight 10
473
sage: C[(1, 1, 1)]
474
1
475
sage: (A*B)[(1, 1, 1)]
476
57792
477
sage: E[(1, 1, 1)]
478
57793
479
480
sage: F = SiegelModularForm('Gamma0(2)', 4, A.coeffs())
481
sage: F
482
Siegel modular form on Gamma0(2) of weight 4
483
sage: A + F
484
Siegel modular form on Gamma0(2) of weight 4
485
sage: F + A == F + A
486
True
487
sage: (A + F)[(1, 1, 1)] == A[(1, 1, 1)] + F[(1, 1, 1)]
488
True
489
sage: A1 = SiegelModularFormsAlgebra().gen(0, prec=20)
490
sage: (A1 + F).prec()
491
20
492
sage: (A1 + F)[(1, 1, 1)] == (A + F)[(1, 1, 1)]
493
True
494
495
TESTS::
496
497
sage: A + B
498
Traceback (most recent call last):
499
...
500
ValueError: cannot add Siegel modular forms of different weights
501
502
sage: F = SiegelModularForm('Gamma0(2)', 4, A.coeffs())
503
sage: G = SiegelModularForm('Gamma0(5)', 4, A.coeffs())
504
sage: F + G
505
Traceback (most recent call last):
506
...
507
TypeError: unsupported operand parent(s) for '+': 'Algebra of Siegel modular forms of degree 2 and even weights on Gamma0(2) over Integer Ring' and 'Algebra of Siegel modular forms of degree 2 and even weights on Gamma0(5) over Integer Ring'
508
sage: Z = A + (-A)
509
sage: Z
510
Siegel modular form on Sp(4,Z) of weight 4
511
sage: Z.prec()
512
101
513
sage: Z.coeffs()
514
{}
515
"""
516
# take the minimum of the precisions and truncate the forms if necessary
517
lp = left.prec()
518
rp = right.prec()
519
if lp < rp:
520
prec = lp
521
right = right.truncate(prec)
522
elif rp < lp:
523
prec = rp
524
left = left.truncate(prec)
525
else:
526
prec = lp
527
528
# figure out the group of the sum = intersection of the groups
529
# of the two forms
530
# right now, we only allow two identical groups, or different
531
# groups where one of them is all of 'Sp(4,Z)'
532
lg = left.group()
533
rg = right.group()
534
if lg is None or lg == 'Sp(4,Z)':
535
group = rg
536
elif rg is None or rg == 'Sp(4,Z)':
537
group = lg
538
elif lg != rg:
539
raise NotImplementedError, "addition of forms on different groups not yet implemented"
540
else:
541
group = lg
542
543
# the sum of two Siegel modular forms is another Siegel modular
544
# form only if the weights are equal
545
if left.weight() != right.weight():
546
raise ValueError, 'cannot add Siegel modular forms of different weights'
547
else:
548
wt = left.weight()
549
550
# compute the coefficients of the sum
551
d = dict()
552
for f in set(left._keys() + right._keys()):
553
v = left[f] + right[f]
554
if not v.is_zero(): d[f] = v
555
par = left.parent()
556
from sage.modular.siegel.siegel_modular_forms_algebra import SiegelModularFormsAlgebra
557
par2 = SiegelModularFormsAlgebra(coeff_ring=par.coeff_ring(), group=group, weights=par.weights(), degree=par.degree())
558
return par2.element_class(parent=par, weight=wt, coeffs=d, prec=prec)
559
560
def _mul_(left, right):
561
r"""
562
Return the product of the Siegel modular form ``left`` by the
563
element ``right``, which can be a scalar or another Siegel modular
564
form.
565
566
The multiplication of two forms on arbitrary groups is not yet
567
implemented. At the moment, the forms must either be on the same
568
group, or one of the groups must be the full 'Sp(4,Z)'.
569
570
EXAMPLES::
571
572
sage: A, B, C, D = SiegelModularFormsAlgebra().gens()
573
sage: A3 = A * 3
574
sage: B2 = 2 * B
575
sage: Conehalf = C / 2
576
sage: Donehalf = (1/2) * D
577
sage: A3[(1, 1, 1)] / A[(1, 1, 1)]
578
3
579
sage: B2[(2, 1, 3)] / B[(2, 1, 3)]
580
2
581
sage: Conehalf[(2, 0, 1)] / C[(2, 0, 1)]
582
1/2
583
sage: Donehalf[(3, 3, 3)] / D[(3, 3, 3)]
584
1/2
585
sage: E = C._mul_(D)
586
sage: E[(0, 0, 5)]
587
0
588
sage: E[(2, 3, 3)]
589
8
590
591
TESTS::
592
593
sage: A = SiegelModularFormsAlgebra(default_prec=61).0
594
sage: A.prec()
595
61
596
sage: C = SiegelModularFormsAlgebra(default_prec=81).2
597
sage: C.prec()
598
81
599
sage: A*C == C*A
600
True
601
sage: (A*C).prec()
602
64
603
"""
604
from sage.modular.siegel.siegel_modular_forms_algebra import SiegelModularFormsAlgebra
605
par = left.parent()
606
from sage.rings.all import infinity
607
if left.prec() is infinity:
608
tmp = right
609
right = left
610
left = tmp
611
612
wt = left.weight() + right.weight()
613
if wt % 2:
614
weights = 'all'
615
else:
616
weights = 'even'
617
if right.prec() is infinity:
618
prec = left.prec()
619
c = right[(0, 0, 0)]
620
d = dict()
621
for f in left.coeffs():
622
v = left[f] * c
623
if not v.is_zero(): d[f] = v
624
par = SiegelModularFormsAlgebra(coeff_ring=par.coeff_ring(), group=par.group(), weights=weights, degree=par.degree())
625
return par.element_class(parent=par, weight=left.weight(), coeffs=d, prec=prec)
626
627
lp = left.prec()
628
rp = right.prec()
629
if lp < rp:
630
right = right.truncate(lp)
631
elif rp < lp:
632
left = left.truncate(rp)
633
prec = min(lp - right.max_disc(), rp - left.max_disc())
634
635
if left.group() is None:
636
group = right.group()
637
elif right.group() is None:
638
group = left.group()
639
elif left.group() != right.group():
640
raise NotImplementedError, "multiplication for differing groups not yet implemented"
641
else:
642
group = left.group()
643
644
s1, s2, R = left.coeffs(), right.coeffs(), left.base_ring()
645
d = dict()
646
_prec = SiegelModularFormPrecision(prec)
647
if ZZ == R:
648
from fastmult import mult_coeff_int
649
for x in _prec:
650
v = mult_coeff_int(x[0], x[1], x[2], s1, s2)
651
if not v.is_zero(): d[x] = v
652
elif left.parent().base_ring() == left.parent().coeff_ring():
653
from fastmult import mult_coeff_generic
654
for x in _prec:
655
v = mult_coeff_generic(x[0], x[1], x[2], s1, s2, R)
656
if not v.is_zero(): d[x] = v
657
else:
658
from fastmult import mult_coeff_generic_with_action
659
for x in _prec:
660
v = mult_coeff_generic_with_action(x[0], x[1], x[2], s1, s2, R)
661
if not v.is_zero(): d[x] = v
662
663
par = SiegelModularFormsAlgebra(coeff_ring=par.coeff_ring(), group=group, weights=weights, degree=par.degree())
664
return par.element_class(parent=par, weight=wt, coeffs=d, prec=prec)
665
666
def _rmul_(self, c):
667
r"""
668
Right multiplication -- only by scalars.
669
670
EXAMPLES::
671
672
sage: A, B, C, D = SiegelModularFormsAlgebra().gens()
673
sage: onehalfC = C._rmul_(-1/2)
674
sage: C[(2, 1, 3)]
675
2736
676
sage: onehalfC[(2, 1, 3)]
677
-1368
678
679
TESTS::
680
681
sage: Z = A._rmul_(0)
682
sage: Z
683
Siegel modular form on Sp(4,Z) of weight 4
684
sage: Z.coeffs()
685
{}
686
"""
687
d = dict()
688
for f in self.coeffs():
689
v = self[f] * c
690
if not v.is_zero(): d[f] = v
691
par = self.parent()
692
return par.element_class(parent=par, weight=self.weight(), coeffs=d, prec=self.prec())
693
694
def _lmul_(self, c):
695
r"""
696
Left multiplication -- only by scalars.
697
698
EXAMPLES::
699
700
sage: A = SiegelModularFormsAlgebra(default_prec=51).0
701
sage: A3 = A._lmul_(3)
702
sage: A[(1, 1, 1)]
703
13440
704
sage: A3[(1, 1, 1)]
705
40320
706
"""
707
return self._rmul_(c)
708
709
def __eq__(left, right):
710
r"""
711
Return True if the Siegel modular forms ``left`` and ``right``
712
have the same group and weight, and the same coefficients up to
713
the smaller of the two precisions.
714
715
EXAMPLES::
716
717
sage: A, B, C, D = SiegelModularFormsAlgebra(default_prec=20).gens()
718
sage: A2, B2, C2, D2 = SiegelModularFormsAlgebra().gens()
719
sage: A2 == A
720
True
721
sage: A == A
722
True
723
sage: A == B
724
False
725
726
TESTS::
727
728
sage: E = SiegelModularForm('Gamma0(2)', 6, B.coeffs())
729
sage: E == B
730
False
731
sage: S = SiegelModularFormsAlgebra(default_prec=21)
732
sage: S(0) == S(0)
733
True
734
sage: S(0) == S(1)
735
False
736
"""
737
if not isinstance(right, SiegelModularForm_class):
738
return False
739
if left.group() != right.group():
740
return False
741
if left.weight() != right.weight():
742
return False
743
744
# we compare up to the minimum of the two precisions
745
new_prec = min(left.prec(), right.prec())
746
# if new_prec is infinity, then left and right are both
747
# constant Siegel modular forms
748
from sage.rings.all import infinity
749
if new_prec is infinity:
750
return left[0, 0, 0] == right[0, 0, 0]
751
752
left = left.truncate(new_prec)
753
right = right.truncate(new_prec)
754
new_smf_prec = SiegelModularFormPrecision(new_prec)
755
756
lc = left.coeffs()
757
rc = right.coeffs()
758
# make coefficients that are implicitly zero be actually zero
759
for k in new_smf_prec:
760
if not lc.has_key(k):
761
lc[k] = 0
762
if not rc.has_key(k):
763
rc[k] = 0
764
765
return lc == rc
766
767
def pickle(self, file, format=1, name=None):
768
r"""
769
Dump to a file in a portable format.
770
771
EXAMPLES::
772
773
sage: A = SiegelModularFormsAlgebra(default_prec=20).0
774
sage: FILE = open('A.sobj', 'w')
775
sage: A.pickle(FILE)
776
777
TO DO
778
I don't really think I have the right syntax since I couldn't
779
load it after doing this
780
"""
781
from sage.rings.all import QQ
782
if self.base_ring().fraction_field() == QQ:
783
pol = [0, 1]
784
coeffs = self.coeffs()
785
else:
786
pol = self.base_ring().polynomial().list()
787
coeffs = dict()
788
for k in self.coeffs():
789
coeffs[k] = self.coeffs()[k].list()
790
if None == name:
791
_name = self._repr_()
792
f1 = 'format %d: [this string, wt, name, pol., prec., dict. of coefficients]' %1
793
data = [f1, self.weight(), _name, pol, self.prec(), coeffs]
794
cPickle.dump(data, file)
795
return
796
797
def fourier_jacobi_coeff(self, N):
798
r"""
799
Return the `N`-th Fourier-Jacobi coefficient of the Siegel modular
800
form ``self`` as a dictionary indexed by pairs `(disc,r)` with
801
`disc<0` and `r^2 \equiv disc \bmod 4N`.
802
803
EXAMPLES::
804
805
sage: A = SiegelModularFormsAlgebra(default_prec=51).0
806
sage: fj = A.fourier_jacobi_coeff(1)
807
sage: fj[(-8, 0)]
808
181440
809
"""
810
prec = self.prec()
811
NN = 4*N
812
keys = [(disc, r) for disc in range(prec) for r in range(NN) if (r**2 - disc)%NN == 0]
813
coeff = dict()
814
for disc, r in keys:
815
(a, b, c) = (-(r**2 - disc)/NN, r, N)
816
coeff[(-disc, r)] = self[(a, b, c)]
817
return coeff
818
819
def satoh_bracket(left, right, names = ['x', 'y']):
820
r"""
821
Return the Satoh bracket [``left``, ``right``], where ``left``
822
and ``right`` are scalar-valued Siegel modular forms.
823
824
The result is a vector-valued Siegel modular form whose coefficients
825
are polynomials in the two variables specified by ``names``.
826
827
EXAMPLES::
828
829
sage: A, B = SiegelModularFormsAlgebra().gens()[:2]
830
sage: AB = A.satoh_bracket(B)
831
sage: AB[(1, 0, 1)]
832
-20160*x^2 - 40320*y^2
833
"""
834
from sage.rings.all import PolynomialRing
835
R = PolynomialRing(ZZ, names)
836
x, y = R.gens()
837
d_left_coeffs = dict((f, (f[0]*x*x + f[1]*x*y + f[2]*y*y)*left[f])
838
for f in left.coeffs())
839
d_left = SiegelModularForm(left.group(), left.weight(),
840
d_left_coeffs, left.prec())
841
d_right_coeffs = dict((f, (f[0]*x*x + f[1]*x*y + f[2]*y*y)*right[f])
842
for f in right.coeffs())
843
d_right = SiegelModularForm(right.group(), right.weight(),
844
d_right_coeffs, right.prec())
845
return d_left*right/left.weight() - d_right*left/right.weight()
846
847
#################
848
# Hecke operators
849
#################
850
851
def hecke_image(self, ell):
852
r"""
853
Return the Siegel modular form which is the image of ``self`` under
854
the Hecke operator T(``ell``).
855
856
EXAMPLES::
857
858
sage: A, B, C, D = SiegelModularFormsAlgebra().gens()
859
sage: Ups20 = -1/1785600*A*B*C - 1/1785600*A^2*D + C^2
860
sage: TUps20 = Ups20.hecke_image(2)
861
sage: TUps20[(1, 1, 1)] / Ups20[(1, 1, 1)]
862
-840960
863
sage: TUps20
864
Siegel modular form on Sp(4,Z) of weight 20
865
sage: A.hecke_image(5)
866
T(5)(Igusa_4)
867
"""
868
# TODO: compute precision for T(ell)F
869
from sage.functions.all import ceil
870
try:
871
# TODO: I am not sure whether this sets the right prec
872
a, b, c = self.prec()
873
prec = (ceil(a/ell), ceil(b/ell), ceil(c/ell))
874
except TypeError:
875
prec = ceil(self.prec()/ell/ell)
876
prec = _normalized_prec(prec)
877
d = dict((f, self.hecke_coefficient(ell, f)) for f in self._keys() if _is_bounded(f, prec))
878
if self.name():
879
name = 'T(' + str(ell) + ')(' + self.name() + ')'
880
else:
881
name = None
882
par = self.parent()
883
from sage.modular.siegel.siegel_modular_forms_algebra import SiegelModularFormsAlgebra
884
par = SiegelModularFormsAlgebra(coeff_ring=par.coeff_ring(), group=par.group(), weights=par.weights(), degree=par.degree())
885
return par.element_class(parent=par, weight=self.weight(), coeffs=d, prec=prec, name=name)
886
887
def hecke_coefficient(self, ell, (a, b, c)):
888
r"""
889
Return the `(a, b, c)`-indexed coefficient of the image of ``self``
890
under the Hecke operator T(``ell``).
891
892
EXAMPLES::
893
894
sage: A, B, C, D = SiegelModularFormsAlgebra().gens()
895
sage: Ups20 = -1/1785600*A*B*C - 1/1785600*A^2*D + C^2
896
sage: Ups20.hecke_coefficient(5, (1, 1, 1))
897
5813608045/992
898
sage: Ups20.hecke_coefficient(5, (1, 0, 1))
899
5813608045/248
900
sage: Ups20.hecke_coefficient(5, (1, 0, 1)) / Ups20[(1, 0, 1)]
901
-5232247240500
902
"""
903
k = self.weight()
904
coeff = 0
905
from sage.rings.all import divisors
906
from sage.quadratic_forms.binary_qf import BinaryQF
907
qf = BinaryQF([a, b, c])
908
for t1 in divisors(ell):
909
for t2 in divisors(t1):
910
cosets = self._get_representatives(ell, t1/t2)
911
for V in cosets:
912
aprime, bprime, cprime = qf.matrix_action_right(V)[:]
913
if aprime % t1 == 0 and bprime % t2 == 0 and cprime % t2 == 0:
914
try:
915
coeff = coeff + t1**(k-2)*t2**(k-1)*self[(ell*aprime/t1**2, ell*bprime/t1/t2, ell*cprime/t2**2)]
916
except KeyError, msg:
917
raise ValueError, '%s' %(self,msg)
918
return coeff
919
920
def _get_representatives(self, ell, t):
921
r"""
922
A helper function used in hecke_coefficient that computes the right
923
coset representatives of `\Gamma^0(t)\SL(2,Z)` where `\Gamma^0(t)`
924
is the subgroup of `SL(2,Z)` where the upper left hand corner is
925
divisible by `t`.
926
927
EXAMPLES::
928
929
sage: A = SiegelModularFormsAlgebra().0
930
sage: A._get_representatives(5, 3)
931
[
932
[ 0 1] [1 0] [1 1] [1 2]
933
[-1 0], [0 1], [0 1], [0 1]
934
]
935
936
NOTE
937
We use the bijection $\Gamma^0(t)\SL(2,Z) \rightarrow P^1(\Z/t\Z)$
938
given by $A \mapsto [1:0]A$.
939
"""
940
try:
941
return self.__rep_lists[(ell, t)]
942
except KeyError:
943
from sage.matrix.all import MatrixSpace
944
M = MatrixSpace(ZZ, 2, 2)
945
if t == 1:
946
return [M([1, 0, 0, 1])]
947
from sage.modular.all import P1List
948
P = list(P1List(t))
949
from sage.rings.all import IntegerModRing, xgcd
950
ZZt = IntegerModRing(t)
951
rep_list = []
952
for x, y in P1List(t):
953
e, d, c = xgcd(x, y)
954
rep = M([x, y, -c, d])
955
rep_list.append(rep)
956
self.__rep_lists[(ell, t)] = rep_list
957
return rep_list
958
959
960
961
def SiegelModularForm(arg0, arg1=None, arg2=None, prec=None, name=None, hint=None):
962
r"""
963
Construct a Siegel modular form.
964
965
INPUT:
966
967
Supported formats
968
969
1. SiegelModularForm(f, g):
970
creates the Siegel modular form VI(f,g) from the elliptic
971
modular forms f, g as in [Sko].
972
Shortforms:
973
SiegelModularForm(f) for SiegelModularForm(f, 0-form),
974
SiegelModularForm(f, 0) for SiegelModularForm(f, 0-form),
975
SiegelModularForm(0, f) for SiegelModularForm(0-form, f).
976
977
2. SiegelModularForm(x):
978
if x is an element of a commutative ring creates the constant
979
Siegel modular form with value x.
980
981
3. SiegelModularForm(string):
982
creates the Siegel modular form pickled at the location
983
described by string (url or path_to_file).
984
985
4. SiegelModularForm(qf):
986
constructs the degree 2 theta series associated to the given
987
quadratic form.
988
989
5. SiegelModularForm(f):
990
--- TODO: Borcherds lift
991
992
6. SiegelModularForm(f, g):
993
--- TODO: Yoshida lift
994
995
7. SiegelModularForm(repr):
996
--- TODO: Lift from Weil representation
997
998
8. SiegelModularForm(char):
999
--- TODO: Singular weight
1000
1001
9. SiegelModularForm(group, weight, dict):
1002
if group is a string, weight an integer and dict a dictionary,
1003
creates a Siegel modular form whose coefficients are contained
1004
in dict.
1005
1006
EXAMPLES::
1007
1008
sage: M4 = ModularForms(1, 4)
1009
sage: M6 = ModularForms(1, 6)
1010
sage: E4 = M4.basis()[0]
1011
sage: F = SiegelModularForm(E4, M6(0), 16); F
1012
Siegel modular form on Sp(4,Z) of weight 4
1013
1014
sage: url = 'http://sage.math.washington.edu/home/nils/Siegel-Modular-Forms/data/upsilon-forms_20-32_1000/Upsilon_20.p' # optional -- internet
1015
sage: H = SiegelModularForm(url); H # optional - internet
1016
Upsilon_20
1017
sage: H[(4, 4, 4)] # optional - internet
1018
248256200704
1019
1020
sage: url = 'http://sage.math.washington.edu/home/nils/Siegel-Modular-Forms/data/upsilon-forms_20-32_1000/Upsilon_28.p' # optional -- internet
1021
sage: L = SiegelModularForm(url); L # optional - internet
1022
Upsilon_28
1023
sage: L.prec() # optional - internet
1024
1001
1025
sage: L[(3, 3, 3)] # optional - internet
1026
-27352334316369546*a^2 + 3164034718941090318*a + 2949217207771097198880
1027
sage: L[(3, 3, 3)].parent() # optional - internet
1028
Number Field in a with defining polynomial x^3 - x^2 - 294086*x - 59412960
1029
1030
sage: l = [(0, 0, 0, 0)]*2 + [(1, 0, 0, 0)] + [(0, 1, 0, 0)] + [(0, 0, 0, 1)] + [(0, 0, 1, 1)]
1031
sage: char_dict = {tuple(l): 1/4}
1032
sage: F = SiegelModularForm(char_dict, prec=100, name="van Geemen F_7"); F
1033
van Geemen F_7
1034
sage: F.coeffs()[(1, 0, 9)]
1035
-7
1036
1037
sage: Q37 = QuadraticForm(ZZ, 4, [1,0,1,1, 2,2,3, 10,2, 6])
1038
sage: Q37.level()
1039
37
1040
sage: F37 = SiegelModularForm(Q37, prec=100); F37
1041
Siegel modular form on Gamma0(37) of weight 2
1042
sage: F37[(2, 1, 3)]
1043
0
1044
sage: F37[(2, 1, 7)]
1045
4
1046
"""
1047
try:
1048
from sage.structure.element import py_scalar_to_element
1049
arg0 = py_scalar_to_element(arg0)
1050
except TypeError:
1051
pass
1052
1053
from sage.modular.modform.element import ModularFormElement
1054
from sage.rings.all import RingElement
1055
if isinstance(arg0, ModularFormElement)\
1056
and isinstance(arg1, ModularFormElement):
1057
return _SiegelModularForm_as_Maass_spezial_form(arg0, arg1, prec, name)
1058
if isinstance(arg0, ModularFormElement) \
1059
and (0 == arg1 or arg1 is None):
1060
M = ModularForms(1, arg0.weight() + 2)
1061
return _SiegelModularForm_as_Maass_spezial_form(arg0, M(0), prec, name)
1062
if 0 == arg0 and isinstance(arg1, ModularFormElement):
1063
M = ModularForms(1, arg1.weight() - 2)
1064
return _SiegelModularForm_as_Maass_spezial_form(M(0), arg1, prec, name)
1065
from sage.quadratic_forms.all import QuadraticForm
1066
if isinstance(arg0, QuadraticForm):
1067
return _SiegelModularForm_from_QuadraticForm(arg0, prec, name)
1068
if isinstance(arg0, RingElement) and arg1 is None:
1069
from sage.rings.all import infinity
1070
return _SiegelModularForm_from_dict(group='Sp(4,Z)', weight=0, coeffs={(0, 0, 0): arg0}, prec=infinity)
1071
if isinstance(arg0, str) and arg1 is None:
1072
return _SiegelModularForm_from_file(arg0)
1073
if isinstance(arg0, dict) and arg1 is None:
1074
return _SiegelModularForm_from_theta_characteristics(arg0, prec=prec, name=name, hint=hint)
1075
from sage.rings.all import Integer
1076
if isinstance(arg0, str) and isinstance(arg1, (int, Integer)) and isinstance(arg2, dict):
1077
return _SiegelModularForm_from_dict(group=arg0, weight=arg1, coeffs=arg2, prec=prec, name=name)
1078
raise TypeError, "wrong arguments"
1079
1080
1081
def _SiegelModularForm_as_Maass_spezial_form(f, g, prec=SMF_DEFAULT_PREC, name=None):
1082
"""
1083
Return the Siegel modular form I(f,g) (Notation as in [Sko]).
1084
1085
EXAMPLES::
1086
1087
sage: M14 = ModularForms(group=1, weight=14)
1088
sage: E14 = M14.eisenstein_subspace()
1089
sage: f = M14.basis()[0]
1090
sage: S16 = ModularForms(group=1, weight=16).cuspidal_subspace()
1091
sage: g = S16.basis()[0]
1092
sage: from sage.modular.siegel.siegel_modular_form import _SiegelModularForm_as_Maass_spezial_form
1093
sage: IFG = _SiegelModularForm_as_Maass_spezial_form(f, g, prec=100, name=None)
1094
sage: IFG[(2, 1, 3)]
1095
-1080946527072
1096
1097
INPUT
1098
f: -- modular form of level 1
1099
g: -- cusp form of level 1 amd wt = wt of f + 2
1100
prec -- either a triple (amax,bmac,cmax) or an integer Dmax
1101
"""
1102
k = f.weight()
1103
assert(k+2 == g.weight()) | (f==0) | (g==0), "incorrect weights!"
1104
assert(g.q_expansion(1) == 0), "second argument is not a cusp form"
1105
1106
if isinstance(prec, tuple):
1107
(amax, bmax, cmax) = prec
1108
amax = min(amax, cmax)
1109
bmax = min(bmax, amax)
1110
clean_prec = (amax, bmax, cmax)
1111
if bmax <= 0:
1112
# no reduced forms below prec
1113
return _SiegelModularForm_from_dict(group='Sp(4,Z)', weight=k, coeffs=dict(), prec=0)
1114
if 1 == amax:
1115
# here prec = (0,0,>=0)
1116
Dtop = 0
1117
else:
1118
Dtop = 4*(amax-1)*(cmax-1)
1119
else:
1120
clean_prec = max(0, prec)
1121
if 0 == clean_prec:
1122
# no reduced forms below prec
1123
return _SiegelModularForm_from_dict(group='Sp(4,Z)', weight=k, coeffs=dict(), prec=0)
1124
while 0 != clean_prec%4 and 1 != clean_prec%4:
1125
clean_prec -= 1
1126
Dtop = clean_prec - 1
1127
precision = (Dtop+1)//4 + 1
1128
# TODO: examine error when called with 1 == prec
1129
if 1 == precision:
1130
precision = 2
1131
1132
"""
1133
Create the Jacobi form I(f,g) as in [Sko].
1134
1135
It suffices to construct for all Jacobi forms phi only the part
1136
sum_{r=0,1;n} c_phi(r^2-4n) q^n zeta^r.
1137
When, in this code part, we speak of Jacobi form we only mean this part.
1138
1139
We need to compute Ifg = \sum_{r=0,1; n} c(r^2-4n) q^n zeta^r up to
1140
4n-r^2 <= Dtop, i.e. n < precision
1141
"""
1142
## print 'Creating I(f,g)'
1143
1144
from sage.rings.all import PowerSeriesRing, QQ
1145
PS = PowerSeriesRing(QQ, name='q')
1146
q = PS.gens()[0]
1147
1148
## Create the quasi Dedekind eta^-6 power series:
1149
pari_prec = max(1, precision - 1) # next line yields error if 0 == pari_prec
1150
from sage.libs.pari.gen import pari
1151
from sage.rings.all import O
1152
pari.set_series_precision(pari_prec)
1153
eta_quasi = PS(pari('Vec(eta(q))')) + O(q**precision)
1154
etapow = eta_quasi**-6
1155
1156
## Create the Jacobi forms A=a*etapow and B=b*etapow in stages.
1157
## Recall a = sum_{s != r mod 2} s^2*(-1)^r*q^((s^2+r^2-1)/4)*zeta^r
1158
## b = sum_{s != r mod 2} (-1)^r*q^((s^2+r^2-1)/4)*zeta^r
1159
## r, s run over ZZ but with opposite parities.
1160
## For r=0, we need s odd, (s^2-1)/4 < precision, with s=2t+1 hence t^2+t < precision.
1161
## For r=1, we need s even, s^2/4 < precision, with s=2t hence t^2 < precision.
1162
1163
from sage.misc.all import xsrange
1164
1165
a1 = -2*sum((2*t)**2 * q**(t**2) for t in xsrange(1, precision) if t*t < precision)
1166
b1 = -2*sum( q**(t**2) for t in xsrange(1, precision) if t*t < precision)
1167
a0 = 2*sum((2*t+1)**2 * q**(t**2+t) for t in xsrange(precision) if t*t +t < precision)
1168
b0 = 2*sum( q**(t**2+t) for t in xsrange(precision) if t*t +t < precision)
1169
b1 = b1 - 1
1170
1171
## print 'Done'
1172
## Form A and B - the Jacobi forms used in [Sko]'s I map.
1173
1174
(A0, A1, B0, B1) = (a0*etapow, a1*etapow, b0*etapow, b1*etapow)
1175
1176
## Calculate the image of the pair of modular forms (f,g) under
1177
## [Sko]'s isomorphism I : M_{k} \oplus S_{k+2} -> J_{k,1}.
1178
1179
fderiv = PS(q * f.qexp(precision).derivative())
1180
(f, g) = (PS(f.qexp(precision)), PS(g.qexp(precision)))
1181
1182
## Finally: I(f,g) is given by the formula below:
1183
Ifg0 = k/2*f*A0 - fderiv*B0 + g*B0 + O(q**precision)
1184
Ifg1 = k/2*f*A1 - fderiv*B1 + g*B1 + O(q**precision)
1185
1186
## For applying the Maass' lifting to genus 2 modular forms.
1187
## we put the coefficients og Ifg into a dictionary Chi
1188
## so that we can access the coefficient corresponding to
1189
## discriminant D by going Chi[D].
1190
1191
## Note: Ifg.list()[i].list()[j] gives the coefficient of q^i*zeta^j
1192
1193
Cphi = {0: 0} ## initialise dictionary. Value changed in the loop if we have a 'noncusp form'
1194
qcoeffs0 = Ifg0.list()
1195
qcoeffs1 = Ifg1.list()
1196
for i in xsrange(len(qcoeffs0)):
1197
Cphi[-4*i] = qcoeffs0[i]
1198
Cphi[1-4*i] = qcoeffs1[i]
1199
1200
## the most negative discriminant occurs when i is largest
1201
## and j is zero. That is, discriminant 0^2-4*i
1202
## Note that i < precision.
1203
maxD = -4*i
1204
1205
"""
1206
Create the Maass lift F := VI(f,g) as in [Sko].
1207
"""
1208
1209
## The constant term is given by -Cphi[0]*B_{2k}/(4*k)
1210
## (note in [Sko] this coeff has typos).
1211
## For nonconstant terms,
1212
## The Siegel coefficient of q^n * zeta^r * qdash^m is given
1213
## by the formula \sum_{ a | gcd(n,r,m) } Cphi[D/a^2] where
1214
## D = r^2-4*n*m is the discriminant.
1215
## Hence in either case the coefficient
1216
## is fully deterimined by the pair (D,gcd(n,r,m)).
1217
## Put (D,t) -> \sum_{ a | t } Cphi[D/a^2]
1218
## in a dictionary (hash table) maassc.
1219
maassc = dict();
1220
## First calculate maass coefficients corresponding to strictly positive definite matrices:
1221
from sage.rings.all import is_fundamental_discriminant
1222
from sage.misc.all import isqrt
1223
for disc in [d for d in xsrange(maxD, 0) if is_fundamental_discriminant(d)]:
1224
for s in xsrange(1, isqrt(maxD//disc)+1):
1225
## add (disc*s^2,t) as a hash key, for each t that divides s
1226
for t in s.divisors():
1227
maassc[(disc*s**2, t)] = sum([a**(k-1)*Cphi[disc*s**2/a**2] for a in t.divisors()])
1228
1229
## Compute the coefficients of the Siegel form $F$:
1230
from sage.rings.all import gcd
1231
siegelq = dict();
1232
if isinstance(prec, tuple):
1233
## Note: m>=n>=r, n>=1 implies m>=n>r^2/4n
1234
for r in xsrange(0, bmax):
1235
for n in xsrange(max(r, 1), amax):
1236
for m in xsrange(n, cmax):
1237
D=r**2 - 4*m*n
1238
g=gcd([n, r, m])
1239
siegelq[(n, r, m)] = maassc[(D, g)]
1240
bound = cmax
1241
else:
1242
bound = 0
1243
for n in xsrange(1, isqrt(Dtop//3)+1):
1244
for r in xsrange(n + 1):
1245
bound = max(bound, (Dtop + r*r)//(4*n) + 1)
1246
for m in xsrange(n, (Dtop + r*r)//(4*n) + 1):
1247
D=r**2 - 4*m*n
1248
g=gcd([n, r, m])
1249
siegelq[(n, r, m)] = maassc[(D, g)]
1250
1251
## Secondly, deal with the singular part.
1252
## Include the coeff corresponding to (0,0,0):
1253
## maassc = {(0,0): -bernoulli(k)/(2*k)*Cphi[0]}
1254
from sage.rings.all import bernoulli
1255
siegelq[(0, 0, 0)] = -bernoulli(k)/(2*k)*Cphi[0]
1256
1257
## Calculate the other discriminant-zero maass coefficients:
1258
from sage.rings.all import sigma
1259
for i in xsrange(1, bound):
1260
## maassc[(0,i)] = sigma(i, k-1) * Cphi[0]
1261
siegelq[(0, 0, i)] = sigma(i, k-1) * Cphi[0]
1262
1263
return _SiegelModularForm_from_dict(group='Sp(4,Z)', weight=k, coeffs=siegelq, prec=clean_prec, name=name)
1264
1265
1266
def _SiegelModularForm_from_file(loc):
1267
r"""
1268
Initialize an instance of SiegelModularForm_class from a file.
1269
1270
EXAMPLE::
1271
1272
sage: from sage.modular.siegel.siegel_modular_form import _SiegelModularForm_from_file
1273
sage: url = 'http://sage.math.washington.edu/home/nils/Siegel-Modular-Forms/data/upsilon-forms_20-32_1000/Upsilon_20.p' # optional -- internet
1274
sage: H = _SiegelModularForm_from_file(url); H # optional - internet
1275
Upsilon_20
1276
sage: H[(4, 4, 4)] # optional - internet
1277
248256200704
1278
"""
1279
if 'http://' == loc[:7]:
1280
f = urllib.urlopen(loc)
1281
else:
1282
f = open(loc, 'r')
1283
data = cPickle.load(f)
1284
f.close()
1285
fmt, wt, name, pol, prec, coeffs = data
1286
if len(pol) > 2:
1287
from sage.rings.all import PolynomialRing, NumberField
1288
R = PolynomialRing(ZZ, 'x')
1289
K = NumberField(R(pol), name='a')
1290
for k in coeffs.iterkeys():
1291
coeffs[k] = K(coeffs[k])
1292
return _SiegelModularForm_from_dict(group='Sp(4,Z)', weight=wt, coeffs=coeffs, prec=prec, name=name)
1293
1294
1295
def _SiegelModularForm_from_theta_characteristics(char_dict, prec=SMF_DEFAULT_PREC, name=None, hint=None):
1296
r"""
1297
Return the Siegel modular form
1298
`\sum_{l \in char_dict} \alpha[l] * \prod_i \theta_l[i](8Z)`,
1299
where `\theta_l[i]` denote the theta constant with characteristic `l`.
1300
1301
INPUT
1302
char_dict - a dictionary whose keys are *tuples* of theta characteristics
1303
and whose values are in some ring.
1304
prec - a precision for Siegel modular forms
1305
name - a string describing this modular form
1306
1307
EXAMPLES::
1308
1309
sage: theta_constants = {((1, 1, 0, 0), (0, 0, 1, 1), (1, 1, 0, 0), (0, 0, 1, 1)): 1}
1310
sage: from sage.modular.siegel.siegel_modular_form import _SiegelModularForm_from_theta_characteristics
1311
sage: _SiegelModularForm_from_theta_characteristics(theta_constants, prec=100)
1312
Siegel modular form on None of weight 2
1313
sage: theta_constants = {((1, 1, 0, 0), (0, 0, 1, 1), (1, 1, 0, 0), (0, 0, 1, 1)): 1}
1314
sage: S = _SiegelModularForm_from_theta_characteristics(theta_constants, prec=100)
1315
sage: S.coeffs()[(2, 0, 10)]
1316
32
1317
1318
TODO:
1319
Implement a parameter hint = "cusp_form" to prevent computing singular parts
1320
"""
1321
coeffs = dict()
1322
smf_prec = SiegelModularFormPrecision(prec)
1323
for f in smf_prec:
1324
if hint is 'cusp_form':
1325
a, b, c = f
1326
if 0 == a: continue
1327
from theta_constant import _compute_theta_char_poly
1328
val = _compute_theta_char_poly(char_dict, f)
1329
if val != 0: coeffs[f] = val
1330
wt = 0
1331
for l in char_dict: wt = max(wt, len(l)/2)
1332
return _SiegelModularForm_from_dict(group=None, weight=wt, coeffs=coeffs, prec=prec, name=name)
1333
1334
1335
def _SiegelModularForm_from_QuadraticForm(Q, prec, name):
1336
"""
1337
Return the theta series of degree 2 for the quadratic form Q.
1338
1339
INPUT:
1340
1341
- ``Q`` - a quadratic form.
1342
1343
- ``prec`` - an integer.
1344
1345
EXAMPLE::
1346
1347
sage: from sage.modular.siegel.siegel_modular_form import _SiegelModularForm_from_QuadraticForm
1348
sage: Q11 = QuadraticForm(ZZ, 4, [3,0,11,0, 3,0,11, 11,0, 11])
1349
sage: _SiegelModularForm_from_QuadraticForm(Q11, 100, None)
1350
Siegel modular form on Gamma0(11) of weight 2
1351
"""
1352
N = Q.level()
1353
k = Q.dim()/2
1354
coeffs = Q.theta_series_degree_2(prec)
1355
return _SiegelModularForm_from_dict(group='Gamma0(%d)'%N, weight=k, coeffs=coeffs, prec=prec, name=name)
1356
1357
1358
def _SiegelModularForm_borcherds_lift(f, prec=SMF_DEFAULT_PREC, name=None):
1359
r"""
1360
Returns Borcherds lift.
1361
1362
EXAMPLES::
1363
1364
sage: from sage.modular.siegel.siegel_modular_form import _SiegelModularForm_borcherds_lift
1365
sage: _SiegelModularForm_borcherds_lift(0)
1366
Traceback (most recent call last):
1367
...
1368
NotImplementedError: Borcherds lift not yet implemented
1369
"""
1370
raise NotImplementedError, "Borcherds lift not yet implemented"
1371
1372
1373
def _SiegelModularForm_yoshida_lift(f, g, prec=SMF_DEFAULT_PREC, name=None):
1374
r"""
1375
Returns the Yoshida lift.
1376
1377
EXAMPLES::
1378
1379
sage: from sage.modular.siegel.siegel_modular_form import _SiegelModularForm_yoshida_lift
1380
sage: _SiegelModularForm_yoshida_lift(0, 0)
1381
Traceback (most recent call last):
1382
...
1383
NotImplementedError: Yoshida lift not yet implemented
1384
"""
1385
raise NotImplementedError, 'Yoshida lift not yet implemented'
1386
1387
1388
def _SiegelModularForm_from_weil_representation(gram, prec=SMF_DEFAULT_PREC, name=None):
1389
r"""
1390
Returns a form associated to a Weil representation.
1391
1392
EXAMPLES::
1393
1394
sage: from sage.modular.siegel.siegel_modular_form import _SiegelModularForm_from_weil_representation
1395
sage: _SiegelModularForm_from_weil_representation(matrix([[2, 1], [1, 1]]))
1396
Traceback (most recent call last):
1397
...
1398
NotImplementedError: Weil representation argument not yet implemented
1399
"""
1400
raise NotImplementedError, 'Weil representation argument not yet implemented'
1401
1402
1403
def _SiegelModularForm_singular_weight(gram, prec=SMF_DEFAULT_PREC, name=None):
1404
r"""
1405
Returns a singular modular form from gram.
1406
1407
EXAMPLES::
1408
1409
sage: from sage.modular.siegel.siegel_modular_form import _SiegelModularForm_singular_weight
1410
sage: _SiegelModularForm_singular_weight(matrix([[2, 1], [1, 1]]))
1411
Traceback (most recent call last):
1412
...
1413
NotImplementedError: singular form argument not yet implemented
1414
"""
1415
raise NotImplementedError, 'singular form argument not yet implemented'
1416
1417
1418
def _SiegelModularForm_from_dict(group, weight, coeffs, prec, degree=2, parent=None, name=None):
1419
r"""
1420
Create an instance of SiegelModularForm_class(), where the parent
1421
is computed from the coeffs.
1422
1423
EXAMPLES::
1424
1425
sage: d = {(1, 1, 1): 1, (1, 0, 2): 2}
1426
sage: from sage.modular.siegel.siegel_modular_form import _SiegelModularForm_from_dict
1427
sage: S = _SiegelModularForm_from_dict('Sp(4,Z)', 2, d, 1); S
1428
Siegel modular form on Sp(4,Z) of weight 2
1429
sage: S.coeffs()
1430
{}
1431
sage: S = _SiegelModularForm_from_dict('Sp(4,Z)', 2, d, 4); S
1432
Siegel modular form on Sp(4,Z) of weight 2
1433
sage: S.coeffs()
1434
{(1, 1, 1): 1}
1435
sage: S = _SiegelModularForm_from_dict('Sp(4,Z)', 2, d, 9); S
1436
Siegel modular form on Sp(4,Z) of weight 2
1437
sage: S.coeffs()
1438
{(1, 1, 1): 1, (1, 0, 2): 2}
1439
"""
1440
if prec is None:
1441
prec = -min([b**2 - 4*a*c for (a, b, c) in coeffs]) + 1
1442
1443
smf_prec = SiegelModularFormPrecision(prec)
1444
coeffs_up_to_prec = {}
1445
for k in coeffs:
1446
if smf_prec.is_in_bound(k):
1447
coeffs_up_to_prec[k] = coeffs[k]
1448
if parent is None:
1449
from sage.structure.all import Sequence
1450
from siegel_modular_forms_algebra import SiegelModularFormsAlgebra
1451
s = Sequence(coeffs_up_to_prec.values())
1452
if weight % 2:
1453
weights = 'all'
1454
else:
1455
weights = 'even'
1456
if len(s) == 0:
1457
coeff_ring = ZZ
1458
else:
1459
coeff_ring = s.universe()
1460
parent = SiegelModularFormsAlgebra(coeff_ring=coeff_ring, group=group, weights=weights, degree=degree)
1461
1462
return parent.element_class(parent=parent, weight=weight, coeffs=coeffs_up_to_prec, prec=prec, name=name)
1463
1464
1465
1466
def _normalized_prec(prec):
1467
r"""
1468
Return a normalized prec for instance of class SiegelModularForm_class.
1469
1470
EXAMPLES::
1471
1472
sage: from sage.modular.siegel.siegel_modular_form import _normalized_prec
1473
sage: _normalized_prec((5, 4, 5))
1474
(5, 4, 5)
1475
sage: _normalized_prec(101)
1476
101
1477
sage: _normalized_prec(infinity)
1478
+Infinity
1479
1480
NOTE:
1481
$(a,b,c)$ is within the precison defined
1482
by prec, if $a,b,c < floor(a),floor(b),floor(c)%
1483
respectively $4ac-b^2 < floor(prec)$.
1484
"""
1485
from sage.rings.all import infinity
1486
if prec is infinity: return prec
1487
from sage.functions.all import floor
1488
if isinstance(prec, tuple):
1489
a, b, c = prec
1490
a = min(floor(a), floor(c))
1491
b = min(floor(b), a)
1492
if b <= 0:
1493
return (0, 0, 0)
1494
return a, b, c
1495
D = max(0, floor(prec))
1496
while 0 != D%4 and 1 != D%4:
1497
D -= 1
1498
return D
1499
1500
1501
def _is_bounded((a, b, c), prec):
1502
r"""
1503
Return True or False accordingly as (a, b, c) is in the
1504
region defined by prec (see. SiegelModularForm_class for what
1505
this means).
1506
1507
EXAMPLES::
1508
1509
sage: from sage.modular.siegel.siegel_modular_form import _is_bounded
1510
sage: _is_bounded((2, 0, 2), 15)
1511
False
1512
sage: _is_bounded((2, 0, 2), 16)
1513
False
1514
sage: _is_bounded((2, 0, 2), 17)
1515
True
1516
1517
NOTE
1518
It is assumed that prec is normalized accordingly to the output
1519
of _normalized_prec().
1520
"""
1521
if isinstance(prec, tuple):
1522
return (a, b, c) < prec
1523
else:
1524
D = 4*a*c - b*b
1525
return D < prec if D != 0 else c < (prec+1)/4
1526
1527
1528
1529
def _prec_min(prec1, prec2):
1530
r"""
1531
Returns the min of two precs.
1532
1533
EXAMPLES::
1534
1535
sage: from sage.modular.siegel.siegel_modular_form import _prec_min
1536
sage: _prec_min(100, 200)
1537
100
1538
sage: _prec_min((1, 0, 1), (2, 0, 1))
1539
(1, 0, 1)
1540
1541
NOTE
1542
It is assumed that the arguments are normalized according to the output
1543
of _normalized_prec().
1544
"""
1545
if type(prec1) != type(prec2):
1546
raise NotImplementedError, "addition for differing precs not yet implemented"
1547
return prec1 if prec1 <= prec2 else prec2
1548
1549
1550
1551