Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
"""
2
Low level functions for coefficients of Siegel modular forms
3
"""
4
5
6
# coeffs_dict* are dictionaries of the form (a,b,c) -> Integer, where
7
# (a,b,c) is GL(2,Z)-reduced, i.e. |b| <= a <= c, and b^2-4ac <= 0,
8
# and where the keys consist either of all reduced triples in a box of the form
9
# (0,A)x(0,B)x(0,C) or else of all reduced triples (a,b,c) with 4ac-b^2 below
10
# a given bound (and c <= if 4ac-b^2=0).
11
12
include 'gmp.pxi'
13
14
from sage.structure.element cimport Element
15
import operator
16
include 'sage/structure/coerce.pxi'
17
from sage.rings.integer_ring import ZZ
18
from sage.rings.integer cimport Integer
19
20
cdef struct int_triple:
21
int a
22
int b
23
int c
24
25
cdef struct long_triple:
26
long a
27
long b
28
long c
29
30
cdef struct int_septuple:
31
int a
32
int b
33
int c
34
int O
35
int o
36
int U
37
int u
38
39
40
cdef struct int_quadruple:
41
int a
42
int b
43
int c
44
int s
45
46
47
cpdef mult_coeff_int(int a, int b, int c, coeffs_dict1, coeffs_dict2):
48
"""
49
Returns the value at (a,b,c) of the coefficient dict of the product
50
of the two forms with dict coeffs_dict1 and coeffs_dict2.
51
It is assumed that (a,b,c) is a key in coeffs_dict1 and coeffs_dict2.
52
53
EXAMPLES::
54
55
sage: from sage.modular.siegel.fastmult import mult_coeff_int
56
sage: A, B, C, D = SiegelModularFormsAlgebra().gens()
57
sage: A[(0,0,0)]
58
1
59
sage: mult_coeff_int(0, 0, 0, A.coeffs(), A.coeffs())
60
1
61
sage: mult_coeff_int(2, 2, 2, C.coeffs(), D.coeffs())
62
1
63
sage: mult_coeff_int(2, 1, 2, C.coeffs(), D.coeffs())
64
8
65
"""
66
cdef int a1, a2
67
cdef int b1, b2
68
cdef int c1, c2
69
cdef int B1, B2
70
71
cdef Integer result
72
73
cdef mpz_t tmp
74
cdef mpz_t left, right
75
cdef mpz_t mult_coeff
76
77
cdef mpz_t mpz_zero
78
79
cdef long_triple tmp_triple
80
81
result = PY_NEW(Integer)
82
83
mpz_init(tmp)
84
mpz_init(left)
85
mpz_init(right)
86
mpz_init(mult_coeff)
87
mpz_init(mpz_zero)
88
89
## We assume that (a,b,c) is semipositive definite! (Havoc otherwise.)
90
## Reduce the form first so that our search space is smaller
91
tmp_triple = _reduce_GL(a, b, c)
92
93
_sig_on
94
95
mpz_set_si( mpz_zero, 0)
96
a = tmp_triple.a
97
b = tmp_triple.b
98
c = tmp_triple.c
99
for a1 from 0 <= a1 < a+1:
100
a2 = a - a1
101
for c1 from 0 <= c1 < c+1:
102
c2 = c - c1
103
mpz_set_si(tmp, 4*a1*c1)
104
mpz_sqrt(tmp, tmp)
105
B1 = mpz_get_si(tmp)
106
107
mpz_set_si(tmp, 4*a2*c2)
108
mpz_sqrt(tmp, tmp)
109
B2 = mpz_get_si(tmp)
110
111
for b1 from max(-B1, b - B2) <= b1 < min(B1 + 1, b + B2 + 1) :
112
## Guarantees that both (a1,b1,c1) and (a2,b2,c2) are
113
## positive semidefinite
114
b2 = b - b1
115
116
set_coeff(left, a1, b1, c1, coeffs_dict1)
117
if 0 == mpz_cmp( left, mpz_zero): continue
118
119
set_coeff(right, a2, b2, c2, coeffs_dict2)
120
if 0 == mpz_cmp( right, mpz_zero): continue
121
122
mpz_mul(tmp, left, right)
123
mpz_add(mult_coeff, mult_coeff, tmp)
124
125
_sig_off
126
127
mpz_set(result.value, mult_coeff)
128
mpz_clear(tmp)
129
mpz_clear(left)
130
mpz_clear(right)
131
mpz_clear(mult_coeff)
132
mpz_clear(mpz_zero)
133
134
return result
135
136
137
cdef inline void set_coeff(mpz_t dest, int a, int b, int c, coeffs_dict):
138
"""
139
Return the value of coeffs_dict at the triple obtained from
140
reducing (a,b,c).
141
It is assumed that the latter is a valid key
142
and that (a,b,c) is positive semidefinite.
143
144
"""
145
cdef long_triple tmp_triple
146
147
mpz_set_si(dest, 0)
148
149
tmp_triple = _reduce_GL(a, b, c)
150
triple = (tmp_triple.a, tmp_triple.b, tmp_triple.c)
151
try:
152
mpz_set(dest, (<Integer>(coeffs_dict[triple])).value)
153
except KeyError:
154
pass
155
return
156
157
158
cpdef mult_coeff_generic(int a, int b, int c, coeffs_dict1, coeffs_dict2, Ring R):
159
"""
160
Returns the value at (a,b,c) of the coefficient dict of the product
161
of the two forms with dict coeffs_dict1 and coeffs_dict2.
162
It is assumed that (a,b,c) is a key in coeffs_dict1 and coeffs_dict2.
163
164
EXAMPLES::
165
166
sage: from sage.modular.siegel.fastmult import mult_coeff_generic
167
sage: A, B, C, D = SiegelModularFormsAlgebra().gens()
168
sage: AB = A.satoh_bracket(B)
169
sage: CD = C.satoh_bracket(D)
170
sage: R = CD.base_ring()
171
sage: mult_coeff_generic(3, 2, 7, AB.coeffs(), CD.coeffs(), R)
172
-7993474656/5*x^4 - 18273219840*x^3*y - 134223332976/5*x^2*y^2 - 120763645536/5*x*y^3 - 17770278912/5*y^4
173
"""
174
cdef int a1, a2
175
cdef int b1, b2
176
cdef int c1, c2
177
cdef int B1, B2
178
cdef Integer nt = PY_NEW(Integer)
179
nmc = R(0)
180
cdef long_triple tmp_triple
181
182
cdef mpz_t tmp
183
184
mpz_init(tmp)
185
186
## We assume that (a,b,c) is semipositive definite! (Havoc otherwise.)
187
## Reduce the form first so that our search space is smaller
188
tmp_triple = _reduce_GL(a, b, c)
189
190
_sig_on
191
192
a = tmp_triple.a
193
b = tmp_triple.b
194
c = tmp_triple.c
195
for a1 from 0 <= a1 < a+1:
196
a2 = a - a1
197
for c1 from 0 <= c1 < c+1:
198
c2 = c - c1
199
mpz_set_si(tmp, 4*a1*c1)
200
mpz_sqrt(tmp, tmp)
201
B1 = mpz_get_si(tmp)
202
203
mpz_set_si(tmp, 4*a2*c2)
204
mpz_sqrt(tmp, tmp)
205
B2 = mpz_get_si(tmp)
206
207
for b1 from max(-B1, b - B2) <= b1 < min(B1 + 1, b + B2 + 1) :
208
## Guarantees that both (a1,b1,c1) and (a2,b2,c2) are
209
## positive semidefinite
210
b2 = b - b1
211
212
nl = get_coeff(a1, b1, c1, coeffs_dict1)
213
if nl is None or nl.is_zero() : continue
214
215
nr = get_coeff(a2, b2, c2, coeffs_dict2)
216
if nr is None or nr.is_zero() : continue
217
218
nmc += nl*nr
219
220
_sig_off
221
222
mpz_clear(tmp)
223
224
return nmc
225
226
227
cdef get_coeff(int a, int b, int c, coeffs_dict):
228
"""
229
Return the value of coeffs_dict at the triple obtained from
230
reducing (a,b,c).
231
It is assumed that the latter is a valid key
232
and that (a,b,c) is positive semidefinite.
233
234
235
"""
236
cdef long_triple tmp_triple
237
238
tmp_triple = _reduce_GL(a, b, c)
239
triple = (tmp_triple.a, tmp_triple.b, tmp_triple.c)
240
try:
241
return coeffs_dict[triple]
242
except KeyError:
243
return None
244
245
246
cpdef mult_coeff_generic_with_action(int a, int b, int c, coeffs_dict1, coeffs_dict2, Ring R):
247
"""
248
Returns the value at (a,b,c) of the coefficient dict of the product
249
of the two forms with dict coeffs_dict1 and coeffs_dict2.
250
It is assumed that (a,b,c) is a key in coeffs_dict1 and coeffs_dict2.
251
252
TO DO:
253
254
I'm not sure what this does and it's not working
255
256
"""
257
cdef int a1, a2
258
cdef int b1, b2
259
cdef int c1, c2
260
cdef int B1, B2
261
cdef Integer nt = PY_NEW(Integer)
262
nmc = R(0)
263
cdef long_triple tmp_triple
264
265
cdef mpz_t tmp
266
267
mpz_init(tmp)
268
269
## We assume that (a,b,c) is semipositive definite! (Havoc otherwise.)
270
## Reduce the form first so that our search space is smaller
271
tmp_triple = _reduce_GL(a, b, c)
272
273
_sig_on
274
275
a = tmp_triple.a
276
b = tmp_triple.b
277
c = tmp_triple.c
278
for a1 from 0 <= a1 < a+1:
279
a2 = a - a1
280
for c1 from 0 <= c1 < c+1:
281
c2 = c - c1
282
mpz_set_si(tmp, 4*a1*c1)
283
mpz_sqrt(tmp, tmp)
284
B1 = mpz_get_si(tmp)
285
286
mpz_set_si(tmp, 4*a2*c2)
287
mpz_sqrt(tmp, tmp)
288
B2 = mpz_get_si(tmp)
289
290
for b1 from max(-B1, b - B2) <= b1 < min(B1 + 1, b + B2 + 1) :
291
## Guarantees that both (a1,b1,c1) and (a2,b2,c2) are
292
## positive semidefinite
293
b2 = b - b1
294
295
nl = get_coeff_with_action(a1, b1, c1, coeffs_dict1, R)
296
if nl is None or nl.is_zero() : continue
297
298
nr = get_coeff_with_action(a2, b2, c2, coeffs_dict2, R)
299
if nr is None or nr.is_zero() : continue
300
301
nmc += nl*nr
302
303
_sig_off
304
305
mpz_clear(tmp)
306
307
return nmc
308
309
310
311
cdef get_coeff_with_action(int a0, int b0, int c0, coeffs_dict, R):
312
"""
313
Return the value of coeffs_dict at the triple obtained from
314
reducing (a,b,c).
315
It is assumed that the latter is a valid key
316
and that (a,b,c) is positive semidefinite.
317
"""
318
cdef int_septuple tmp_septuple
319
cdef int a,b,c,d
320
321
tmp_septuple = _xreduce_GL(a0, b0, c0)
322
triple = (tmp_septuple.a, tmp_septuple.b, tmp_septuple.c)
323
a = tmp_septuple.O
324
b = tmp_septuple.o
325
c = tmp_septuple.U
326
d = tmp_septuple.u
327
328
try:
329
v = coeffs_dict[triple]
330
except KeyError:
331
return None
332
333
from sage.algebras.all import GroupAlgebra
334
if isinstance( R, GroupAlgebra):
335
B = R.base_ring()
336
else:
337
B = R
338
339
from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
340
if is_PolynomialRing( B):
341
x = B.gen(0)
342
y = B.gen(1)
343
xp = x*a + y*c
344
yp = x*b + y*d
345
346
if is_PolynomialRing( R):
347
v = v( xp, yp)
348
return v
349
350
res = R(0)
351
for p,chi in v._fs:
352
if is_PolynomialRing( B): p = p(xp,yp)
353
G = B.group()
354
det = G.gen(0)
355
sig = G.gen(1)
356
if chi == G.identity(): e = 1
357
elif chi == det: e = a*d-b*c
358
elif chi == sig: e = _sig(a,b,c,d)
359
else: e = (a*d-b*c) * _sig(a,b,c,d)
360
res += p*e*R(chi)
361
return res
362
363
364
cdef _sig( int a, int b, int c, int d):
365
a = a%2
366
b = b%2
367
c = c%2
368
d = d%2
369
if 0 == b and 0 == c: return 1
370
if 1 == a+d: return 1
371
return -1
372
373
374
def reduce_GL(a, b, c):
375
"""
376
Return the GL2(ZZ)-reduced form equivalent to (positive semidefinite)
377
quadratic form ax^2+bxy+cy^2.
378
379
EXAMPLES::
380
381
sage: from sage.modular.siegel.fastmult import reduce_GL
382
sage: reduce_GL(2,2,4)
383
(2, 2, 4)
384
sage: reduce_GL(3,5,3)
385
(1, 1, 3)
386
sage: reduce_GL(1,2,1)
387
(0, 0, 1)
388
"""
389
cdef long_triple res
390
391
# We want to check that (a,b,c) is semipositive definite
392
# since otherwise we might end up in an infinite loop.
393
# TODO: the discriminant can become to big
394
if b*b-4*a*c > 0 or a < 0 or c < 0:
395
raise NotImplementedError, "only implemented for nonpositive discriminant"
396
397
res = _reduce_GL(a, b, c)
398
return (res.a, res.b, res.c)
399
400
401
cdef long_triple _reduce_GL(long a, long b, long c):
402
"""
403
Return the GL2(ZZ)-reduced form equivalent to (positive semidefinite)
404
quadratic form ax^2+bxy+cy^2.
405
(Following algorithm 5.4.2 found in Cohen's Computational Algebraic Number Theory.)
406
"""
407
cdef long_triple res
408
cdef long twoa, q, r
409
cdef long tmp
410
411
if b < 0:
412
b = -b
413
414
while not (b<=a and a<=c): ## while not GL-reduced
415
twoa = 2 * a
416
#if b not in range(-a+1,a+1):
417
if b > a:
418
## apply Euclidean step (translation)
419
q = b / twoa #(2*a)
420
r = b % twoa #(2*a)
421
if r > a:
422
## want (quotient and) remainder such that -a<r<=a
423
r = r - twoa # 2*a;
424
q = q + 1
425
c = c-b*q+a*q*q
426
b = r
427
428
## apply symmetric step (reflection) if necessary
429
if a > c:
430
#(a,c) = (c,a)
431
tmp = c
432
c = a
433
a = tmp
434
435
#b=abs(b)
436
if b < 0:
437
b = -b
438
## iterate
439
## We're finished! Return the GL2(ZZ)-reduced form (a,b,c):
440
441
res.a = a
442
res.b = b
443
res.c = c
444
445
return res
446
447
448
def xreduce_GL(a, b, c):
449
"""
450
Return the GL2(ZZ)-reduced form equivalent to (positive semidefinite)
451
quadratic form ax^2+bxy+cy^2.
452
453
EXAMPLES::
454
455
sage: from sage.modular.siegel.fastmult import xreduce_GL
456
sage: xreduce_GL(3,1,1)
457
((1, 1, 3), (0, 1, 1, 0))
458
sage: xreduce_GL(1,2,1)
459
((0, 0, 1), (0, 1, 1, 1))
460
sage: xreduce_GL(3,8,2)
461
Traceback (most recent call last):
462
NotImplementedError: only implemented for nonpositive discriminant
463
sage: xreduce_GL(1,1,1)
464
((1, 1, 1), (1, 0, 0, 1))
465
sage: xreduce_GL(3,2,9)
466
((3, 2, 9), (1, 0, 0, 1))
467
sage: xreduce_GL(3,7,9)
468
((3, 1, 5), (1, 0, 1, 1))
469
470
471
"""
472
cdef int_septuple res
473
474
# We want to check that (a,b,c) is semipositive definite
475
# since otherwise we might end up in an infinite loop.
476
if b*b-4*a*c > 0 or a < 0 or c < 0:
477
raise NotImplementedError, "only implemented for nonpositive discriminant"
478
479
res = _xreduce_GL(a, b, c)
480
return ((res.a, res.b, res.c), (res.O, res.o, res.U, res.u))
481
482
483
cdef int_septuple _xreduce_GL(int a, int b, int c):
484
"""
485
Return the GL2(ZZ)-reduced form f and a matrix M such that
486
ax^2+bxy+cy^2 = f((x,y)*M).
487
488
TODO
489
_xreduce_GL is a factor 20 slower than xreduce_GL.
490
How can we improve this factor ?
491
492
"""
493
cdef int_septuple res
494
cdef int twoa, q, r
495
cdef int tmp
496
cdef int O,o,U,u
497
498
# If [A,B,C] is the form to be reduced, then after each reduction
499
# step we have [A,B,C] =[a,b,c]( (x,y)*matrix(2,2,[O,o, U,u]) )
500
O = u = 1
501
o = U = 0
502
503
if b < 0:
504
b = -b
505
O = -1
506
507
while not (b<=a and a<=c): ## while not GL-reduced
508
twoa = 2 * a
509
#if b not in range(-a+1,a+1):
510
if b > a:
511
## apply Euclidean step (translation)
512
q = b / twoa #(2*a)
513
r = b % twoa #(2*a)
514
if r > a:
515
## want (quotient and) remainder such that -a<r<=a
516
r = r - twoa # 2*a;
517
q = q + 1
518
c = c-b*q+a*q*q
519
b = r
520
O += q*o
521
U += q*u
522
523
## apply symmetric step (reflection) if necessary
524
if a > c:
525
#(a,c) = (c,a)
526
tmp = c; c = a; a = tmp
527
tmp = O; O = o; o = tmp
528
tmp = U; U = u; u = tmp
529
530
#b=abs(b)
531
if b < 0:
532
b = -b
533
O = -O
534
U = -U
535
536
## iterate
537
## We're finished! Return the GL2(ZZ)-reduced form (a,b,c) and the O,o,U,u-matrix:
538
539
res.a = a
540
res.b = b
541
res.c = c
542
res.O = O
543
res.o = o
544
res.U = U
545
res.u = u
546
547
return res
548
549
550
551
552
553
cdef inline int poly(int e, int f, int g, int h,
554
int i, int j, int k, int l,
555
int m, int n, int o, int p) :
556
## reverse the linebreaks; this won't work
557
return ( 4*(f*(k*p - l*o) - g*(j*p - l*n) + h*(j*o - k*n))
558
- 6*(e*(k*p - l*o) - g*(i*p - l*m) + h*(i*o - k*m))
559
+ 10*(e*(j*p - l*n) - f*(i*p - l*m) + h*(i*n - j*m))
560
- 12*(e*(j*o - k*n) - f*(i*o - k*m) + g*(i*n - j*m)) )
561
562
563
def chi35(disc, A,B,C,D) :
564
r"""
565
Returns the odd weight generator the ring of Siegel modular forms of degree 2
566
as in Igusa. Uses a formula from Ibukiyama [I].
567
568
EXAMPLES::
569
570
sage: A, B, C, D = SiegelModularFormsAlgebra().gens()
571
sage: from sage.modular.siegel.fastmult import chi35
572
sage: chi = chi35(51,A,B,C,D)
573
sage: chi[(0,0,0)]
574
Traceback (most recent call last):
575
KeyError: (0, 0, 0)
576
sage: chi[(2,1,3)]
577
1
578
sage: chi[(3,1,4)]
579
-129421
580
581
"""
582
cdef dict Acoeffs, Bcoeffs, Ccoeffs, Dcoeffs
583
cdef int a1, a2, a3, a4
584
cdef int c1, c2, c3, c4
585
cdef int b1, b2, b3, b4
586
cdef int a, b, c
587
cdef int B1, B1r, B2, B2r, B3, B4
588
589
cdef mpz_t coeff, acc, tmp
590
591
cdef mpz_t mpz_zero
592
593
mpz_init(coeff)
594
mpz_init(acc)
595
mpz_init(tmp)
596
mpz_init(mpz_zero)
597
598
599
_sig_on
600
601
mpz_set_si( mpz_zero, 0)
602
coeffs = PY_NEW( dict )
603
604
prec = min([ disc, A.prec(), B.prec(), C.prec(), D.prec()])
605
606
if prec != disc:
607
raise ValueError, "Insufficient precision of Igusa forms"
608
from siegel_modular_form_prec import SiegelModularFormPrecision
609
prec_class = SiegelModularFormPrecision( prec)
610
611
Acoeffs = A.coeffs()
612
Bcoeffs = B.coeffs()
613
Ccoeffs = C.coeffs()
614
Dcoeffs = D.coeffs()
615
616
for trip in prec_class.positive_forms():
617
(a, b, c) = trip
618
mpz_set_si(coeff, 0)
619
for c1 from 0 <= c1 < c-1 :
620
for c2 from 0 <= c2 < c-1-c1 :
621
for c3 from 1 <= c3 < c-c1-c2 :
622
c1r = c - c1
623
c2r = c1r - c2
624
c4 = c2r - c3
625
for a1 from 0 <= a1 < a-1 :
626
for a2 from 0<= a2 < a-1-a1 :
627
for a3 from 1 <= a3 < a-a1-a2 :
628
a1r = a - a1
629
a2r = a1r - a2
630
a4 = a2r - a3
631
632
mpz_set_si(tmp, 4*a1*c1)
633
mpz_sqrt(tmp, tmp)
634
B1 = mpz_get_si(tmp)
635
636
mpz_set_si(tmp, 4*a1r*c1r)
637
mpz_sqrt(tmp, tmp)
638
B1r = mpz_get_si(tmp)
639
640
mpz_set_si(tmp, 4*a2*c2)
641
mpz_sqrt(tmp, tmp)
642
B2 = mpz_get_si(tmp)
643
644
mpz_set_si(tmp, 4*a2r*c2r)
645
mpz_sqrt(tmp, tmp)
646
B2r = mpz_get_si(tmp)
647
648
mpz_set_si(tmp, 4*a3*c3)
649
mpz_sqrt(tmp, tmp)
650
B3 = mpz_get_si(tmp)
651
652
mpz_set_si(tmp, 4*a4*c4)
653
mpz_sqrt(tmp, tmp)
654
B4 = mpz_get_si(tmp)
655
656
for b1 from max(-B1, b - B1r) <= b1 < min(B1 + 1, b + B1r + 1) :
657
for b2 from max(-B2, b - b1 - B2r) <= b2 < min(B2 + 1, b - b1 + B2r + 1) :
658
for b3 from max(-B3, b - b1 - b2 - B4) <= b3 < min(B3 + 1, b - b1 - b2 + B4 + 1) :
659
b4 = b-(b1+b2+b3)
660
661
set_coeff(acc, a1, b1, c1, Acoeffs)
662
set_coeff(tmp, a2, b2, c2, Bcoeffs)
663
mpz_mul(acc, acc, tmp)
664
set_coeff(tmp, a3, b3, c3, Ccoeffs)
665
mpz_mul(acc, acc, tmp)
666
set_coeff(tmp, a4, b4, c4, Dcoeffs)
667
mpz_mul(acc, acc, tmp)
668
669
mpz_set_si(tmp, poly(a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4))
670
mpz_mul(acc, acc, tmp)
671
672
mpz_add(coeff, coeff, acc)
673
if mpz_cmp( coeff, mpz_zero) != 0:
674
coeffs[trip] = PY_NEW( Integer)
675
mpz_set((<Integer>coeffs[trip]).value, coeff)
676
677
for t in coeffs:
678
coeffs[t] = Integer(coeffs[t]/41472)
679
680
_sig_off
681
682
mpz_clear(coeff)
683
mpz_clear(acc)
684
mpz_clear(tmp)
685
mpz_clear(mpz_zero)
686
687
return coeffs
688
689
690