Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/modsym/p1list.pyx
4069 views
1
r"""
2
Lists of Manin symbols (elements of `\mathbb{P}^1(\ZZ/N\ZZ)`) over `\QQ`
3
"""
4
5
from sage.misc.search import search
6
7
cimport sage.rings.fast_arith
8
import sage.rings.fast_arith
9
cdef sage.rings.fast_arith.arith_int arith_int
10
cdef sage.rings.fast_arith.arith_llong arith_llong
11
arith_int = sage.rings.fast_arith.arith_int()
12
arith_llong = sage.rings.fast_arith.arith_llong()
13
14
ctypedef long long llong
15
16
include '../../ext/interrupt.pxi'
17
include '../../ext/stdsage.pxi'
18
19
###############################################################
20
#
21
# Int p1_normalize and p1list; a non-int version is below,
22
# which should be used for N > 46340
23
#
24
################################################################
25
26
cdef int c_p1_normalize_int(int N, int u, int v,
27
int* uu, int* vv, int* ss,
28
int compute_s) except -1:
29
"""
30
Computes the canonical representative of
31
`\mathbb{P}^1(\ZZ/N\ZZ)` equivalent to
32
`(u,v)` along with a transforming scalar.
33
34
INPUT:
35
36
37
- ``N`` - an integer
38
39
- ``u`` - an integer
40
41
- ``v`` - an integer
42
43
44
OUTPUT: If gcd(u,v,N) = 1, then returns
45
46
47
- ``uu`` - an integer
48
49
- ``vv`` - an integer
50
51
- ``ss`` - an integer such that `(ss*uu, ss*vv)` is congruent to
52
`(u,v)` (mod `N`);
53
54
if `\gcd(u,v,N) \not= 1`, returns 0, 0, 0.
55
56
If ``compute_s`` is 0, ``s`` is not computed.
57
"""
58
cdef int d, k, g, s, t, min_v, min_t, Ng, vNg
59
if N == 1:
60
uu[0] = 0
61
vv[0] = 0
62
ss[0] = 1
63
return 0
64
65
if N<=0 or N > 46340:
66
raise OverflowError, "Modulus is too large (must be < 46340)"
67
return -1
68
69
u = u % N
70
v = v % N
71
if u<0: u = u + N
72
if v<0: v = v + N
73
if u == 0:
74
uu[0] = 0
75
if arith_int.c_gcd_int(v,N) == 1:
76
vv[0] = 1
77
else:
78
vv[0] = 0
79
ss[0] = v
80
return 0
81
82
g = arith_int.c_xgcd_int(u, N, &s, &t)
83
s = s % N
84
if s<0: s = s + N
85
if arith_int.c_gcd_int(g, v) != 1:
86
uu[0] = 0
87
vv[0] = 0
88
ss[0] = 0
89
return 0
90
91
# Now g = s*u + t*N, so s is a "pseudo-inverse" of u mod N
92
# Adjust s modulo N/g so it is coprime to N.
93
if g!=1:
94
d = N/g
95
while arith_int.c_gcd_int(s,N) != 1:
96
s = (s+d) % N
97
98
# Multiply [u,v] by s; then [s*u,s*v] = [g,s*v] (mod N)
99
u = g
100
v = (s*v) % N
101
102
min_v = v; min_t = 1
103
if g!=1:
104
Ng = N/g
105
vNg = (v*Ng) % N
106
t = 1
107
for k from 2 <= k <= g:
108
v = (v + vNg) % N
109
t = (t + Ng) % N
110
if v<min_v and arith_int.c_gcd_int(t,N)==1:
111
min_v = v; min_t = t
112
v = min_v
113
if u<0: u = u+N
114
if v<0: v = v+N
115
uu[0] = u
116
vv[0] = v
117
if compute_s:
118
ss[0] = arith_int.c_inverse_mod_int(s*min_t, N);
119
return 0
120
121
def p1_normalize_int(N, u, v):
122
r"""
123
Computes the canonical representative of
124
`\mathbb{P}^1(\ZZ/N\ZZ)` equivalent to
125
`(u,v)` along with a transforming scalar.
126
127
INPUT:
128
129
130
- ``N`` - an integer
131
132
- ``u`` - an integer
133
134
- ``v`` - an integer
135
136
137
OUTPUT: If gcd(u,v,N) = 1, then returns
138
139
140
- ``uu`` - an integer
141
142
- ``vv`` - an integer
143
144
- ``ss`` - an integer such that `(ss*uu, ss*vv)` is congruent to `(u,v)` (mod `N`);
145
146
if `\gcd(u,v,N) \not= 1`, returns 0, 0, 0.
147
148
EXAMPLES::
149
150
sage: from sage.modular.modsym.p1list import p1_normalize_int
151
sage: p1_normalize_int(90,7,77)
152
(1, 11, 7)
153
sage: p1_normalize_int(90,7,78)
154
(1, 24, 7)
155
sage: (7*24-78*1) % 90
156
0
157
sage: (7*24) % 90
158
78
159
"""
160
cdef int uu, vv, ss
161
c_p1_normalize_int(N, u%N, v%N, &uu, &vv, &ss, 1)
162
return (uu,vv,ss)
163
164
def p1list_int(int N):
165
r"""
166
Returns a list of the normalized elements of
167
`\mathbb{P}^1(\ZZ/N\ZZ)`.
168
169
INPUT:
170
171
172
- ``N`` - integer (the level or modulus).
173
174
EXAMPLES::
175
176
sage: from sage.modular.modsym.p1list import p1list_int
177
sage: p1list_int(6)
178
[(0, 1),
179
(1, 0),
180
(1, 1),
181
(1, 2),
182
(1, 3),
183
(1, 4),
184
(1, 5),
185
(2, 1),
186
(2, 3),
187
(2, 5),
188
(3, 1),
189
(3, 2)]
190
191
::
192
193
sage: p1list_int(120)
194
[(0, 1),
195
(1, 0),
196
(1, 1),
197
(1, 2),
198
(1, 3),
199
...
200
(30, 7),
201
(40, 1),
202
(40, 3),
203
(40, 11),
204
(60, 1)]
205
"""
206
cdef int g, u, v, s, c, d, h, d1, cmax
207
cdef object lst
208
209
if N==1: return [(0,0)]
210
211
sig_on()
212
lst = [(0,1)]
213
c = 1
214
for d from 0 <= d < N:
215
lst.append((c,d))
216
217
cmax = N/2
218
if N%2: # N odd, max divisor is <= N/3
219
if N%3: # N not a multiple of 3 either, max is N/5
220
cmax = N/5
221
else:
222
cmax = N/3
223
224
for c from 2 <= c <= cmax:
225
if N%c == 0: # c is a proper divisor
226
h = N/c
227
g = arith_int.c_gcd_int(c,h)
228
for d from 1 <= d <= h:
229
if arith_int.c_gcd_int(d,g)==1:
230
d1 = d
231
while arith_int.c_gcd_int(d1,c)!=1:
232
d1 += h
233
c_p1_normalize_int(N, c, d1, &u, &v, &s, 0)
234
lst.append((u,v))
235
sig_off()
236
lst.sort()
237
return lst
238
239
240
###############################################################
241
#
242
# The following is a version of the three functions
243
#
244
# c_p1_normalize_int, p1_normalize_int, and p1list_int
245
#
246
# but the gcd's are done using GMP, so there are no overflow
247
# worries. Also, the one multiplication is done using double
248
# precision.
249
#
250
################################################################
251
252
cdef int c_p1_normalize_llong(int N, int u, int v,
253
int* uu, int* vv, int* ss,
254
int compute_s) except -1:
255
r"""
256
c_p1_normalize_llong(N, u, v):
257
258
Computes the canonical representative of
259
`\mathbb{P}^1(\ZZ/N\ZZ)` equivalent to `(u,v)` along
260
with a transforming scalar 's' (if compute_s is 1).
261
262
INPUT:
263
264
265
- ``N`` - an integer (the modulus or level)
266
267
- ``u`` - an integer (the first coordinate of (u:v))
268
269
- ``v`` - an integer (the second coordinate of (u:v))
270
271
- ``compute_s`` - a boolean (int)
272
273
274
OUTPUT: If gcd(u,v,N) = 1, then returns
275
276
277
- ``uu`` - an integer
278
279
- ``vv`` - an integer
280
281
- ``ss`` - an integer such that `(ss*uu, ss*vv)` is equivalent to `(u,v)` mod `N`;
282
283
if `\gcd(u,v,N) \not= 1`, returns 0, 0, 0.
284
285
EXAMPLES::
286
287
sage: from sage.modular.modsym.p1list import p1_normalize_int
288
sage: p1_normalize_int(90,7,77)
289
(1, 11, 7)
290
sage: p1_normalize_int(90,7,78)
291
(1, 24, 7)
292
sage: (7*24-78*1) % 90
293
0
294
sage: (7*24) % 90
295
78
296
"""
297
cdef int d, k, g, s, t, min_v, min_t, Ng, vNg
298
cdef llong ll_s, ll_t, ll_N
299
if N == 1:
300
uu[0] = 0
301
vv[0] = 0
302
ss[0] = 1
303
return 0
304
305
ll_N = <long> N
306
307
#if N<=0 or N >= 2**31:
308
# raise OverflowError, "Modulus is too large (must be < 46340)"
309
# return -1
310
311
u = u % N
312
v = v % N
313
if u<0: u = u + N
314
if v<0: v = v + N
315
if u == 0:
316
uu[0] = 0
317
if arith_int.c_gcd_int(v,N) == 1:
318
vv[0] = 1
319
else:
320
vv[0] = 0
321
ss[0] = v
322
return 0
323
324
#g = xgcd_int_llong(u, N, &s, &t)
325
g = <int> arith_llong.c_xgcd_longlong(u, N, &ll_s, &ll_t)
326
s = <int>(ll_s % ll_N)
327
t = <int>(ll_t % ll_N)
328
s = s % N
329
if s<0: s = s + N
330
if arith_int.c_gcd_int(g, v) != 1:
331
uu[0] = 0
332
vv[0] = 0
333
ss[0] = 0
334
return 0
335
336
# Now g = s*u + t*N, so s is a "pseudo-inverse" of u mod N
337
# Adjust s modulo N/g so it is coprime to N.
338
if g!=1:
339
d = N/g
340
while arith_int.c_gcd_int(s,N) != 1:
341
s = (s+d) % N
342
343
# Multiply [u,v] by s; then [s*u,s*v] = [g,s*v] (mod N)
344
u = g
345
# v = (s*v) % N
346
v = <int> ( ((<llong>s) * (<llong>v)) % ll_N )
347
348
min_v = v; min_t = 1
349
if g!=1:
350
Ng = N/g
351
vNg = <int> ((<llong>v * <llong> Ng) % ll_N)
352
t = 1
353
for k from 2 <= k <= g:
354
v = (v + vNg) % N
355
t = (t + Ng) % N
356
if v<min_v and arith_int.c_gcd_int(t,N)==1:
357
min_v = v; min_t = t
358
v = min_v
359
if u<0: u = u+N
360
if v<0: v = v+N
361
uu[0] = u
362
vv[0] = v
363
if compute_s:
364
ss[0] = <int> (arith_llong.c_inverse_mod_longlong(s*min_t, N) % ll_N)
365
return 0
366
367
def p1_normalize_llong(N, u, v):
368
r"""
369
Computes the canonical representative of
370
`\mathbb{P}^1(\ZZ/N\ZZ)` equivalent to
371
`(u,v)` along with a transforming scalar.
372
373
INPUT:
374
375
376
- ``N`` - an integer
377
378
- ``u`` - an integer
379
380
- ``v`` - an integer
381
382
383
OUTPUT: If gcd(u,v,N) = 1, then returns
384
385
386
- ``uu`` - an integer
387
388
- ``vv`` - an integer
389
390
- ``ss`` - an integer such that `(ss*uu, ss*vv)` is equivalent to `(u,v)` mod `N`;
391
392
if `\gcd(u,v,N) \not= 1`, returns 0, 0, 0.
393
394
EXAMPLES::
395
396
sage: from sage.modular.modsym.p1list import p1_normalize_llong
397
sage: p1_normalize_llong(90000,7,77)
398
(1, 11, 7)
399
sage: p1_normalize_llong(90000,7,78)
400
(1, 77154, 7)
401
sage: (7*77154-78*1) % 90000
402
0
403
sage: (7*77154) % 90000
404
78
405
"""
406
cdef int uu, vv, ss
407
c_p1_normalize_llong(N, u%N, v%N, &uu, &vv, &ss, 1)
408
return (uu,vv,ss)
409
410
def p1list_llong(int N):
411
r"""
412
Returns a list of the normalized elements of
413
`\mathbb{P}^1(\ZZ/N\ZZ)`, as a plain list of
414
2-tuples.
415
416
INPUT:
417
418
419
- ``N`` - integer (the level or modulus).
420
421
EXAMPLES::
422
423
sage: from sage.modular.modsym.p1list import p1list_llong
424
sage: N = 50000
425
sage: L = p1list_llong(50000)
426
sage: len(L) == N*prod([1+1/p for p,e in N.factor()])
427
True
428
sage: L[0]
429
(0, 1)
430
sage: L[len(L)-1]
431
(25000, 1)
432
"""
433
cdef int g, u, v, s, c, d, h, d1, cmax
434
if N==1: return [(0,0)]
435
436
lst = [(0,1)]
437
sig_on()
438
c = 1
439
for d from 0 <= d < N:
440
lst.append((c,d))
441
442
cmax = N/2
443
if N%2: # N odd, max divisor is <= N/3
444
if N%5: # N not a multiple of 3 either, max is N/5
445
cmax = N/5
446
else:
447
cmax = N/3
448
449
for c from 2 <= c <= cmax:
450
if N%c == 0: # c is a proper divisor
451
h = N/c
452
g = arith_int.c_gcd_int(c,h)
453
for d from 1 <= d <= h:
454
if arith_int.c_gcd_int(d,g)==1:
455
d1 = d
456
while arith_int.c_gcd_int(d1,c)!=1:
457
d1 += h
458
c_p1_normalize_llong(N, c, d1, &u, &v, &s, 0)
459
lst.append((u,v))
460
sig_off()
461
lst.sort()
462
return lst
463
464
def p1list(N):
465
"""
466
Returns the elements of the projective line modulo `N`,
467
`\mathbb{P}^1(\ZZ/N\ZZ)`, as a plain list of 2-tuples.
468
469
INPUT:
470
471
- N (integer) - a positive integer (less than 2^31).
472
473
OUTPUT:
474
475
A list of the elements of the projective line
476
`\mathbb{P}^1(\ZZ/N\ZZ)`, as plain 2-tuples.
477
478
EXAMPLES::
479
480
sage: from sage.modular.modsym.p1list import p1list
481
sage: list(p1list(7))
482
[(0, 1), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6)]
483
sage: N=23456
484
sage: len(p1list(N)) == N*prod([1+1/p for p,e in N.factor()])
485
True
486
487
"""
488
if N <= 0:
489
raise ValueError, "N must be a positive integer"
490
if N <= 46340:
491
return p1list_int(N)
492
if N <= 2147483647:
493
return p1list_llong(N)
494
else:
495
raise OverflowError, "p1list not defined for such large N."
496
497
def p1_normalize(int N, int u, int v):
498
r"""
499
Computes the canonical representative of
500
`\mathbb{P}^1(\ZZ/N\ZZ)` equivalent to
501
`(u,v)` along with a transforming scalar.
502
503
INPUT:
504
505
506
- ``N`` - an integer
507
508
- ``u`` - an integer
509
510
- ``v`` - an integer
511
512
513
OUTPUT: If gcd(u,v,N) = 1, then returns
514
515
516
- ``uu`` - an integer
517
518
- ``vv`` - an integer
519
520
- ``ss`` - an integer such that `(ss*uu, ss*vv)` is equivalent to `(u,v)` mod `N`;
521
522
if `\gcd(u,v,N) \not= 1`, returns 0, 0, 0.
523
524
EXAMPLES::
525
526
sage: from sage.modular.modsym.p1list import p1_normalize
527
sage: p1_normalize(90,7,77)
528
(1, 11, 7)
529
sage: p1_normalize(90,7,78)
530
(1, 24, 7)
531
sage: (7*24-78*1) % 90
532
0
533
sage: (7*24) % 90
534
78
535
536
::
537
538
sage: from sage.modular.modsym.p1list import p1_normalize
539
sage: p1_normalize(50001,12345,54322)
540
(3, 4667, 4115)
541
sage: (12345*4667-54321*3) % 50001
542
3
543
sage: 4115*3 % 50001
544
12345
545
sage: 4115*4667 % 50001 == 54322 % 50001
546
True
547
"""
548
if N <= 46340:
549
return p1_normalize_int(N, u, v)
550
if N <= 2147483647:
551
return p1_normalize_llong(N, u, v)
552
else:
553
raise OverflowError
554
555
cdef int p1_normalize_xgcdtable(int N, int u, int v,
556
int compute_s,
557
int *t_g, int *t_a, int *t_b,
558
int* uu, int* vv, int* ss) except -1:
559
"""
560
INPUT:
561
562
563
- ``N, u, v`` - integers
564
565
- ``compute_s`` - do not compute s if compute_s == 0.
566
567
- ``t_g, t_a, t_b`` - int arrays of
568
569
570
OUTPUT:
571
572
- ``uu, vv, ss`` - reduced representative and normalizing scalar.
573
"""
574
cdef int d, k, g, s, t, min_v, min_t, Ng, vNg
575
if N == 1:
576
uu[0] = 0
577
vv[0] = 0
578
ss[0] = 1
579
return 0
580
581
if N<=0 or N > 46340:
582
raise OverflowError, "Modulus is too large (must be < 46340)"
583
return -1
584
585
u = u % N
586
v = v % N
587
if u<0: u = u + N
588
if v<0: v = v + N
589
if u == 0:
590
uu[0] = 0
591
if t_g[v] == 1: # "if arith_int.c_gcd_int(v,N) == 1"
592
vv[0] = 1
593
else:
594
vv[0] = 0
595
ss[0] = v
596
return 0
597
598
# WAS: "g = arith_int.c_xgcd_int(u, N, &s, &t)"
599
g = t_g[u]
600
s = t_a[u]
601
t = t_b[u]
602
s = s % N
603
if s<0: s = s + N
604
if g != 1 and arith_int.c_gcd_int(g, v) != 1:
605
uu[0] = 0
606
vv[0] = 0
607
ss[0] = 0
608
return 0
609
610
# Now g = s*u + t*N, so s is a "pseudo-inverse" of u mod N
611
# Adjust s modulo N/g so it is coprime to N.
612
if g!=1:
613
d = N/g
614
while t_g[s] != 1: # while arith_int.c_gcd_int(s,N) != 1:
615
s = (s+d) % N
616
617
# Multiply [u,v] by s; then [s*u,s*v] = [g,s*v] (mod N)
618
u = g
619
v = (s*v) % N
620
621
min_v = v; min_t = 1
622
if g!=1:
623
Ng = N/g
624
vNg = (v*Ng) % N
625
t = 1
626
for k from 2 <= k <= g:
627
v = (v + vNg) % N
628
t = (t + Ng) % N
629
if v<min_v and t_g[t] == 1: #arith_int.c_gcd_int(t,N)==1:
630
min_v = v; min_t = t
631
v = min_v
632
if u<0: u = u+N
633
if v<0: v = v+N
634
uu[0] = u
635
vv[0] = v
636
if compute_s:
637
#ss[0] = arith_int.c_inverse_mod_int(s*min_t, N);
638
ss[0] = t_a[(s*min_t)%N]
639
return 0
640
641
cdef class P1List:
642
"""
643
The class for `\mathbb{P}^1(\ZZ/N\ZZ)`, the projective line modulo `N`.
644
645
EXAMPLES::
646
647
sage: P = P1List(12); P
648
The projective line over the integers modulo 12
649
sage: list(P)
650
[(0, 1), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (1, 11), (2, 1), (2, 3), (2, 5), (3, 1), (3, 2), (3, 4), (3, 7), (4, 1), (4, 3), (4, 5), (6, 1)]
651
652
Saving and loading works.
653
654
::
655
656
sage: loads(dumps(P)) == P
657
True
658
"""
659
def __init__(self, int N):
660
"""
661
The constructor for the class P1List.
662
663
INPUT:
664
665
666
- ``N`` - positive integer (the modulus or level).
667
668
669
OUTPUT:
670
671
A P1List object representing `\mathbb{P}^1(\ZZ/N\ZZ)`.
672
673
EXAMPLES::
674
675
sage: L = P1List(120) # indirect doctest
676
sage: L
677
The projective line over the integers modulo 120
678
"""
679
cdef int i
680
681
self.__N = N
682
if N <= 46340:
683
self.__list = p1list_int(N)
684
self.__normalize = c_p1_normalize_int
685
elif N <= 2147483647:
686
self.__list = p1list_llong(N)
687
self.__normalize = c_p1_normalize_llong
688
else:
689
raise OverflowError, "p1list not defined for such large N."
690
self.__list.sort()
691
self.__end_hash = dict([(x,i) for i, x in enumerate(self.__list[N+1:])])
692
693
# Allocate memory for xgcd table.
694
self.g = NULL; self.s = NULL; self.t = NULL
695
self.g = <int*> sage_malloc(sizeof(int)*N)
696
if not self.g: raise MemoryError
697
self.s = <int*> sage_malloc(sizeof(int)*N)
698
if not self.s: raise MemoryError
699
self.t = <int*> sage_malloc(sizeof(int)*N)
700
if not self.t: raise MemoryError
701
702
# Initialize xgcd table
703
cdef llong ll_s, ll_t, ll_N = N
704
705
if N <= 46340:
706
for i from 0 <= i < N:
707
self.g[i] = arith_int.c_xgcd_int(i, N, &self.s[i], &self.t[i])
708
else:
709
for i from 0 <= i < N:
710
self.g[i] = arith_llong.c_xgcd_longlong(i, N, &ll_s, &ll_t)
711
self.s[i] = <int>(ll_s % ll_N)
712
self.t[i] = <int>(ll_t % ll_N)
713
714
def __dealloc__(self):
715
"""
716
Deallocates memory for an object of the class P1List.
717
"""
718
if self.g: sage_free(self.g)
719
if self.s: sage_free(self.s)
720
if self.t: sage_free(self.t)
721
722
723
def __cmp__(self, other):
724
"""
725
Comparison function for objects of the class P1List.
726
727
The order is the same as for the underlying modulus.
728
729
EXAMPLES::
730
731
sage: P1List(10) < P1List(11)
732
True
733
sage: P1List(12) > P1List(11)
734
True
735
sage: P1List(11) == P1List(11)
736
True
737
738
sage: t = [P1List(N) for N in [100,23,45]]
739
sage: [L.N() for L in t]
740
[100, 23, 45]
741
sage: t.sort()
742
sage: [L.N() for L in t]
743
[23, 45, 100]
744
"""
745
if not isinstance(other, P1List):
746
return -1
747
cdef P1List O
748
O = other
749
if self.__N < O.__N:
750
return -1
751
elif self.__N > O.__N:
752
return 1
753
return 0
754
755
def __reduce__(self):
756
"""
757
Helper function used in pickling.
758
759
EXAMPLES::
760
761
sage: L = P1List(8)
762
sage: L.__reduce__()
763
(<built-in function _make_p1list>, (8,))
764
"""
765
import sage.modular.modsym.p1list
766
return sage.modular.modsym.p1list._make_p1list, (self.__N, )
767
768
def __getitem__(self, n):
769
"""
770
Standard indexing/slicing function for the class P1List.
771
772
EXAMPLES::
773
774
sage: L = P1List(8)
775
sage: list(L) # indirect doctest
776
[(0, 1),
777
(1, 0),
778
...
779
(2, 3),
780
(4, 1)]
781
sage: L[4:8] # indirect doctest
782
[(1, 3), (1, 4), (1, 5), (1, 6)]
783
"""
784
if isinstance(n, slice):
785
start, stop, step = n.indices(len(self))
786
return self.__list[start:stop:step]
787
else:
788
return self.__list[n]
789
790
def __len__(self):
791
"""
792
Returns the length of this P1List.
793
794
EXAMPLES::
795
796
sage: L = P1List(8)
797
sage: len(L) # indirect doctest
798
12
799
"""
800
return len(self.__list)
801
802
def __repr__(self):
803
"""
804
Returns the string representation of this P1List.
805
806
EXAMPLES::
807
808
sage: L = P1List(8)
809
sage: str(L) # indirect doctest
810
'The projective line over the integers modulo 8'
811
812
"""
813
return "The projective line over the integers modulo %s"%self.__N
814
815
def lift_to_sl2z(self, int i):
816
"""
817
Lift the `i`'th element of this P1list to an element of
818
`SL(2,\ZZ)`.
819
820
If the `i`'th element is `(c,d)`, this function computes and
821
returns a list `[a,b, c',d']` that defines a 2x2 matrix
822
with determinant 1 and integer entries, such that `c=c'` (mod
823
`N`) and `d=d'` (mod `N`).
824
825
INPUT:
826
827
828
- ``i`` - integer (the index of the element to lift).
829
830
EXAMPLES::
831
832
sage: p = P1List(11)
833
sage: p.list()[3]
834
(1, 2)
835
836
sage: p.lift_to_sl2z(3)
837
[0, -1, 1, 2]
838
839
AUTHORS:
840
841
- Justin Walker
842
"""
843
cdef int c, d, N
844
845
if self.__N == 1:
846
return [1,0,0,1]
847
848
c, d = self.__list[i]
849
N = self.__N
850
# No overflow: This was adjudicated during init...
851
if N <= 46340:
852
return lift_to_sl2z_int(c, d, self.__N)
853
elif N <= 2147483647:
854
return lift_to_sl2z_llong(c, d, self.__N)
855
else:
856
raise OverflowError, "N too large"
857
858
def apply_I(self, int i):
859
r"""
860
Return the index of the result of applying the matrix
861
`I=[-1,0;0,1]` to the `i`'th element of this P1List.
862
863
INPUT:
864
865
866
- ``i`` - integer (the index of the element to act on).
867
868
869
EXAMPLES::
870
871
sage: L = P1List(120)
872
sage: L[10]
873
(1, 9)
874
sage: L.apply_I(10)
875
112
876
sage: L[112]
877
(1, 111)
878
sage: L.normalize(-1,9)
879
(1, 111)
880
881
::
882
883
This operation is an involution:
884
885
sage: all([L.apply_I(L.apply_I(i))==i for i in xrange(len(L))])
886
True
887
888
"""
889
cdef int u, v, uu, vv, ss
890
u,v = self.__list[i]
891
self.__normalize(self.__N, -u, v, &uu, &vv, &ss, 0)
892
_, j = search(self.__list, (uu,vv))
893
return j
894
895
def apply_S(self, int i):
896
r"""
897
Return the index of the result of applying the matrix
898
`S=[0,-1;1,0]` to the `i`'th element of this P1List.
899
900
INPUT:
901
902
903
- ``i`` - integer (the index of the element to act on).
904
905
EXAMPLES::
906
907
sage: L = P1List(120)
908
sage: L[10]
909
(1, 9)
910
sage: L.apply_S(10)
911
159
912
sage: L[159]
913
(3, 13)
914
sage: L.normalize(-9,1)
915
(3, 13)
916
917
::
918
919
This operation is an involution:
920
921
sage: all([L.apply_S(L.apply_S(i))==i for i in xrange(len(L))])
922
True
923
924
"""
925
cdef int u, v, uu, vv, ss
926
u,v = self.__list[i]
927
self.__normalize(self.__N, -v, u, &uu, &vv, &ss, 0)
928
_, j = search(self.__list, (uu,vv))
929
return j
930
931
def apply_T(self, int i):
932
r"""
933
Return the index of the result of applying the matrix
934
`T=[0,1;-1,-1]` to the `i`'th element of this P1List.
935
936
INPUT:
937
938
939
- ``i`` - integer (the index of the element to act on).
940
941
EXAMPLES::
942
943
sage: L = P1List(120)
944
sage: L[10]
945
(1, 9)
946
sage: L.apply_T(10)
947
157
948
sage: L[157]
949
(3, 10)
950
sage: L.normalize(9,-10)
951
(3, 10)
952
953
::
954
955
This operation has order three:
956
957
sage: all([L.apply_T(L.apply_T(L.apply_T(i)))==i for i in xrange(len(L))])
958
True
959
960
"""
961
cdef int u, v, uu, vv, ss
962
u,v = self.__list[i]
963
self.__normalize(self.__N, v, -u-v, &uu, &vv, &ss, 0)
964
_, j = search(self.__list, (uu,vv))
965
return j
966
967
cpdef index(self, int u, int v):
968
r"""
969
Returns the index of the class of `(u,v)` in the fixed list
970
of representatives of
971
`\mathbb{P}^1(\ZZ/N\ZZ)`.
972
973
INPUT:
974
975
976
- ``u, v`` - integers, with `\gcd(u,v,N)=1`.
977
978
979
OUTPUT:
980
981
982
- ``i`` - the index of `u`, `v`, in the P1list.
983
984
EXAMPLES::
985
986
sage: L = P1List(120)
987
sage: L[100]
988
(1, 99)
989
sage: L.index(1,99)
990
100
991
sage: all([L.index(L[i][0],L[i][1])==i for i in range(len(L))])
992
True
993
"""
994
if self.__N == 1:
995
# there is exactly 1 class [(0,0)].
996
return 0
997
cdef int uu, vv, ss
998
p1_normalize_xgcdtable(self.__N, u, v, 0, self.g, self.s, self.t, &uu, &vv, &ss)
999
if uu == 1:
1000
return vv + 1
1001
elif uu == 0:
1002
if vv == 0:
1003
return -1
1004
return 0
1005
try:
1006
return self.__end_hash[(uu,vv)] + self.__N + 1
1007
except KeyError:
1008
return -1
1009
1010
cdef index_and_scalar(self, int u, int v, int* i, int* s):
1011
r"""
1012
Compute the index of the class of `(u,v)` in the fixed list
1013
of representatives of `\mathbb{P}^1(\ZZ/N\ZZ)` and scalar s
1014
such that (s*a,s*b) = (u,v), with (a,b) the normalized
1015
representative.
1016
1017
INPUT:
1018
1019
1020
- ``u, v`` - integers, with `\gcd(u,v,N)=1`.
1021
1022
1023
OUTPUT:
1024
1025
1026
- ``i`` - the index of `u`, `v`, in the P1list.
1027
1028
- ``s`` - normalizing scalar.
1029
"""
1030
if self.__N == 1:
1031
# there is exactly 1 class [(0,0)].
1032
i[0] = 0
1033
s[0] = 1
1034
return
1035
1036
cdef int uu, vv, ss
1037
p1_normalize_xgcdtable(self.__N, u, v, 1, self.g, self.s, self.t, &uu, &vv, s)
1038
if uu == 1:
1039
i[0] = vv + 1
1040
return
1041
elif uu == 0:
1042
if vv == 0:
1043
i[0] = -1
1044
return
1045
i[0] = 0
1046
return
1047
try:
1048
i[0] = self.__end_hash[(uu,vv)] + self.__N + 1
1049
return
1050
except KeyError:
1051
i[0] = -1
1052
return
1053
1054
def index_of_normalized_pair(self, int u, int v):
1055
r"""
1056
Returns the index of the class of `(u,v)` in the fixed list
1057
of representatives of
1058
`\mathbb{P}^1(\ZZ/N\ZZ)`.
1059
1060
INPUT:
1061
1062
1063
- ``u, v`` - integers, with `\gcd(u,v,N)=1`, normalized so they lie in the list.
1064
1065
1066
OUTPUT:
1067
1068
1069
- ``i`` - the index of `(u:v)`, in the P1list.
1070
1071
EXAMPLES::
1072
1073
sage: L = P1List(120)
1074
sage: L[100]
1075
(1, 99)
1076
sage: L.index_of_normalized_pair(1,99)
1077
100
1078
sage: all([L.index_of_normalized_pair(L[i][0],L[i][1])==i for i in range(len(L))])
1079
True
1080
"""
1081
t, i = search(self.__list, (u,v))
1082
if t: return i
1083
return -1
1084
1085
1086
def list(self):
1087
r"""
1088
Returns the underlying list of this P1List object.
1089
1090
EXAMPLES::
1091
1092
sage: L = P1List(8)
1093
sage: type(L)
1094
<type 'sage.modular.modsym.p1list.P1List'>
1095
sage: type(L.list())
1096
<type 'list'>
1097
"""
1098
return self.__list
1099
1100
def normalize(self, int u, int v):
1101
r"""
1102
Returns a normalised element of `\mathbb{P}^1(\ZZ/N\ZZ)`.
1103
1104
INPUT:
1105
1106
1107
- ``u, v`` - integers, with `\gcd(u,v,N)=1`.
1108
1109
1110
OUTPUT:
1111
1112
- a 2-tuple ``(uu,vv)`` where `(uu:vv)` is a *normalized*
1113
representative of `(u:v)`.
1114
1115
NOTE: See also normalize_with_scalar() which also returns the
1116
normalizing scalar.
1117
1118
EXAMPLES::
1119
1120
sage: L = P1List(120)
1121
sage: (u,v) = (555555555,7777)
1122
sage: uu,vv = L.normalize(555555555,7777)
1123
sage: (uu,vv)
1124
(15, 13)
1125
sage: (uu*v-vv*u) % L.N() == 0
1126
True
1127
"""
1128
cdef int uu, vv, ss
1129
self.__normalize(self.__N, u, v, &uu, &vv, &ss, 0)
1130
return (uu,vv)
1131
1132
def normalize_with_scalar(self, int u, int v):
1133
r"""
1134
Returns a normalised element of `\mathbb{P}^1(\ZZ/N\ZZ)`, together with
1135
the normalizing scalar.
1136
1137
INPUT:
1138
1139
1140
- ``u, v`` - integers, with `\gcd(u,v,N)=1`.
1141
1142
1143
OUTPUT:
1144
1145
- a 3-tuple ``(uu,vv,ss)`` where `(uu:vv)` is a *normalized*
1146
representative of `(u:v)`, and `ss` is a scalar such that
1147
`(ss*uu, ss*vv) = (u,v)` (mod `N`).
1148
1149
EXAMPLES::
1150
1151
sage: L = P1List(120)
1152
sage: (u,v) = (555555555,7777)
1153
sage: uu,vv,ss = L.normalize_with_scalar(555555555,7777)
1154
sage: (uu,vv)
1155
(15, 13)
1156
sage: ((ss*uu-u)%L.N(), (ss*vv-v)%L.N())
1157
(0, 0)
1158
sage: (uu*v-vv*u) % L.N() == 0
1159
True
1160
"""
1161
cdef int uu, vv, ss
1162
self.__normalize(self.__N, u, v, &uu, &vv, &ss, 1)
1163
return (uu,vv,ss)
1164
1165
def N(self):
1166
"""
1167
Returns the level or modulus of this P1List.
1168
1169
EXAMPLES::
1170
1171
sage: L = P1List(120)
1172
sage: L.N()
1173
120
1174
"""
1175
return self.__N
1176
1177
1178
cdef class export:
1179
cdef int c_p1_normalize_int(self, int N, int u, int v,
1180
int* uu, int* vv, int* ss,
1181
int compute_s) except -1:
1182
return c_p1_normalize_int(N, u, v, uu, vv, ss, compute_s)
1183
1184
cdef int c_p1_normalize_llong(self, int N, int u, int v,
1185
int* uu, int* vv, int* ss,
1186
int compute_s) except -1:
1187
return c_p1_normalize_llong(N, u, v, uu, vv, ss, compute_s)
1188
1189
def lift_to_sl2z_int(int c, int d, int N):
1190
"""
1191
Lift a pair `(c, d)` to an element of `SL(2, \ZZ)`.
1192
1193
`(c,d)` is assumed to be an element of
1194
`\mathbb{P}^1(\ZZ/N\ZZ)`. This function computes
1195
and returns a list `[a, b, c', d']` that defines a 2x2
1196
matrix, with determinant 1 and integer entries, such that
1197
`c=c'` (mod `N`) and `d=d'` (mod `N`).
1198
1199
INPUT:
1200
1201
- ``c,d,N`` - integers such that `\gcd(c,d,N)=1`.
1202
1203
EXAMPLES::
1204
1205
sage: from sage.modular.modsym.p1list import lift_to_sl2z_int
1206
sage: lift_to_sl2z_int(2,6,11)
1207
[1, 8, 2, 17]
1208
sage: m=Matrix(Integers(),2,2,lift_to_sl2z_int(2,6,11))
1209
sage: m
1210
[ 1 8]
1211
[ 2 17]
1212
1213
AUTHOR:
1214
1215
- Justin Walker
1216
"""
1217
cdef int z1, z2, g, m
1218
1219
if c == 0 and d == 0:
1220
raise AttributeError, "Element (%s, %s) not in P1." % (c,d)
1221
g = arith_int.c_xgcd_int(c, d, &z1, &z2)
1222
1223
# We're lucky: z1*c + z2*d = 1.
1224
if g==1:
1225
return [z2, -z1, c, d]
1226
1227
# Have to try harder.
1228
if c == 0:
1229
c = c + N;
1230
if d == 0:
1231
d = d + N;
1232
m = c;
1233
1234
# compute prime-to-d part of m.
1235
while True:
1236
g = arith_int.c_gcd_int(m,d)
1237
if g == 1:
1238
break
1239
m = m / g
1240
1241
# compute prime-to-N part of m.
1242
while True:
1243
g = arith_int.c_gcd_int(m,N)
1244
if g == 1:
1245
break
1246
m = m / g
1247
d = d + N*m
1248
g = arith_int.c_xgcd_int(c, d, &z1, &z2)
1249
1250
if g != 1:
1251
raise ValueError, "input must have gcd 1"
1252
1253
return [z2, -z1, c, d]
1254
1255
def lift_to_sl2z_llong(llong c, llong d, int N):
1256
r"""
1257
Lift a pair `(c, d)` (modulo `N`) to an element of `SL(2, \ZZ)`.
1258
1259
`(c,d)` is assumed to be an element of
1260
`\mathbb{P}^1(\ZZ/N\ZZ)`. This function computes and
1261
returns a list `[a, b, c', d']` that defines a 2x2 matrix,
1262
with determinant 1 and integer entries, such that `c=c'` (mod `N`)
1263
and `d=d'` (mod `N`).
1264
1265
INPUT:
1266
1267
- ``c,d,N`` - integers such that `\gcd(c,d,N)=1`.
1268
1269
EXAMPLES::
1270
1271
sage: from sage.modular.modsym.p1list import lift_to_sl2z_llong
1272
sage: lift_to_sl2z_llong(2,6,11)
1273
[1L, 8L, 2L, 17L]
1274
sage: m=Matrix(Integers(),2,2,lift_to_sl2z_llong(2,6,11))
1275
sage: m
1276
[ 1 8]
1277
[ 2 17]
1278
1279
AUTHOR:
1280
1281
- Justin Walker
1282
"""
1283
cdef llong z1, z2, g, m
1284
1285
if c == 0 and d == 0:
1286
raise AttributeError, "Element (%s, %s) not in P1." % (c,d)
1287
g = arith_llong.c_xgcd_longlong(c, d, &z1, &z2)
1288
1289
# We're lucky: z1*c + z2*d = 1.
1290
if g==1:
1291
return [z2, -z1, c, d]
1292
1293
# Have to try harder.
1294
if c == 0:
1295
c = c + N;
1296
if d == 0:
1297
d = d + N;
1298
m = c;
1299
1300
# compute prime-to-d part of m.
1301
while True:
1302
g = arith_llong.c_gcd_longlong(m,d)
1303
if g == 1:
1304
break
1305
m = m / g
1306
1307
# compute prime-to-N part of m.
1308
while True:
1309
g = arith_llong.c_gcd_longlong(m,N)
1310
if g == 1:
1311
break
1312
m = m / g
1313
d = d + N*m
1314
g = arith_llong.c_xgcd_longlong(c, d, &z1, &z2)
1315
1316
if g != 1:
1317
raise ValueError, "input must have gcd 1"
1318
1319
return [z2, -z1, c, d]
1320
1321
def lift_to_sl2z(c, d, N):
1322
r"""
1323
Return a list of Python ints `[a,b,c',d']` that are the entries of a
1324
2x2 matrix with determinant 1 and lower two entries congruent to
1325
`c,d` modulo `N`.
1326
1327
INPUT:
1328
1329
- ``c,d,N`` - Python ints or longs such that `\gcd(c,d,N)=1`.
1330
1331
EXAMPLES::
1332
1333
sage: lift_to_sl2z(2,3,6)
1334
[1, 1, 2, 3]
1335
sage: lift_to_sl2z(2,3,6000000)
1336
[1L, 1L, 2L, 3L]
1337
1338
You will get a ValueError exception if the input is invalid. Note
1339
that here gcd(15,6,24)=3::
1340
1341
sage: lift_to_sl2z(15,6,24)
1342
Traceback (most recent call last):
1343
...
1344
ValueError: input must have gcd 1
1345
1346
This function is not implemented except for N at most 2**31::
1347
1348
sage: lift_to_sl2z(1,1,2^32)
1349
Traceback (most recent call last):
1350
...
1351
NotImplementedError: N too large
1352
"""
1353
if N <= 46340:
1354
return lift_to_sl2z_int(c,d,N)
1355
elif N <= 2147483647:
1356
return lift_to_sl2z_llong(c,d,N)
1357
else:
1358
raise NotImplementedError, "N too large"
1359
1360
1361
def _make_p1list(n):
1362
"""
1363
Helper function used in pickling.
1364
1365
Not intended for end-users.
1366
1367
EXAMPLES::
1368
1369
sage: from sage.modular.modsym.p1list import _make_p1list
1370
sage: _make_p1list(3)
1371
The projective line over the integers modulo 3
1372
1373
"""
1374
return P1List(n)
1375
1376