Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/modular/cusps_nf.py
4045 views
1
r"""
2
The set `\mathbb{P}^1(K)` of cusps of a number field K
3
4
AUTHORS:
5
6
- Maite Aranes (2009): Initial version
7
8
EXAMPLES:
9
10
The space of cusps over a number field k:
11
12
::
13
14
sage: k.<a> = NumberField(x^2 + 5)
15
sage: kCusps = NFCusps(k); kCusps
16
Set of all cusps of Number Field in a with defining polynomial x^2 + 5
17
sage: kCusps is NFCusps(k)
18
True
19
20
Define a cusp over a number field:
21
22
::
23
24
sage: NFCusp(k, a, 2/(a+1))
25
Cusp [a - 5: 2] of Number Field in a with defining polynomial x^2 + 5
26
sage: kCusps((a,2))
27
Cusp [a: 2] of Number Field in a with defining polynomial x^2 + 5
28
sage: NFCusp(k,oo)
29
Cusp Infinity of Number Field in a with defining polynomial x^2 + 5
30
31
Different operations with cusps over a number field:
32
33
::
34
35
sage: alpha = NFCusp(k, 3, 1/a + 2); alpha
36
Cusp [a + 10: 7] of Number Field in a with defining polynomial x^2 + 5
37
sage: alpha.numerator()
38
a + 10
39
sage: alpha.denominator()
40
7
41
sage: alpha.ideal()
42
Fractional ideal (7, a + 3)
43
sage: alpha.ABmatrix()
44
[a + 10, 3*a - 1, 7, 2*a]
45
sage: alpha.apply([0, 1, -1,0])
46
Cusp [7: -a - 10] of Number Field in a with defining polynomial x^2 + 5
47
48
Check Gamma0(N)-equivalence of cusps:
49
50
::
51
52
sage: N = k.ideal(3)
53
sage: alpha = NFCusp(k, 3, a + 1)
54
sage: beta = kCusps((2, a - 3))
55
sage: alpha.is_Gamma0_equivalent(beta, N)
56
True
57
58
Obtain transformation matrix for equivalent cusps:
59
60
::
61
62
sage: t, M = alpha.is_Gamma0_equivalent(beta, N, Transformation=True)
63
sage: M[2] in N
64
True
65
sage: M[0]*M[3] - M[1]*M[2] == 1
66
True
67
sage: alpha.apply(M) == beta
68
True
69
70
List representatives for Gamma_0(N) - equivalence classes of cusps:
71
72
::
73
74
sage: Gamma0_NFCusps(N)
75
[Cusp [0: 1] of Number Field in a with defining polynomial x^2 + 5,
76
Cusp [1: 3] of Number Field in a with defining polynomial x^2 + 5,
77
...]
78
"""
79
#*****************************************************************************
80
# Copyright (C) 2009, Maite Aranes <[email protected]>
81
#
82
# Distributed under the terms of the GNU General Public License (GPL)
83
# http://www.gnu.org/licenses/
84
#*****************************************************************************
85
86
from sage.structure.parent_base import ParentWithBase
87
from sage.structure.element import Element, is_InfinityElement
88
from sage.misc.cachefunc import cached_method
89
90
_nfcusps_cache = {}
91
92
_list_reprs_cache = {}
93
94
def NFCusps_clear_list_reprs_cache():
95
"""
96
Clear the global cache of lists of representatives for ideal classes.
97
98
EXAMPLES::
99
100
sage: sage.modular.cusps_nf.NFCusps_clear_list_reprs_cache()
101
sage: k.<a> = NumberField(x^3 + 11)
102
sage: N = k.ideal(a+1)
103
sage: sage.modular.cusps_nf.list_of_representatives(N)
104
(Fractional ideal (1), Fractional ideal (17, a - 5))
105
sage: sage.modular.cusps_nf._list_reprs_cache.keys()
106
[Fractional ideal (a + 1)]
107
sage: sage.modular.cusps_nf.NFCusps_clear_list_reprs_cache()
108
sage: sage.modular.cusps_nf._list_reprs_cache.keys()
109
[]
110
"""
111
global _list_reprs_cache
112
_list_reprs_cache = {}
113
114
def list_of_representatives(N):
115
"""
116
Returns a list of ideals, coprime to the ideal ``N``, representatives of
117
the ideal classes of the corresponding number field.
118
119
Note: This list, used every time we check `\\Gamma_0(N)` - equivalence of
120
cusps, is cached.
121
122
INPUT:
123
124
- ``N`` -- an ideal of a number field.
125
126
OUTPUT:
127
128
A list of ideals coprime to the ideal ``N``, such that they are
129
representatives of all the ideal classes of the number field.
130
131
EXAMPLES::
132
133
sage: sage.modular.cusps_nf.NFCusps_clear_list_reprs_cache()
134
sage: sage.modular.cusps_nf._list_reprs_cache.keys()
135
[]
136
137
::
138
139
sage: from sage.modular.cusps_nf import list_of_representatives
140
sage: k.<a> = NumberField(x^4 + 13*x^3 - 11)
141
sage: N = k.ideal(713, a + 208)
142
sage: L = list_of_representatives(N); L
143
(Fractional ideal (1),
144
Fractional ideal (37, a + 12),
145
Fractional ideal (47, a - 9))
146
147
The output of ``list_of_representatives`` has been cached:
148
149
::
150
151
sage: sage.modular.cusps_nf._list_reprs_cache.keys()
152
[Fractional ideal (713, a + 208)]
153
sage: sage.modular.cusps_nf._list_reprs_cache[N]
154
(Fractional ideal (1),
155
Fractional ideal (37, a + 12),
156
Fractional ideal (47, a - 9))
157
"""
158
if _list_reprs_cache.has_key(N):
159
lreps = _list_reprs_cache[N]
160
if not (lreps is None): return lreps
161
lreps = NFCusps_ideal_reps_for_levelN(N)[0]
162
_list_reprs_cache[N] = lreps
163
return lreps
164
165
def NFCusps_clear_cache():
166
"""
167
Clear the global cache of sets of cusps over number fields.
168
169
EXAMPLES::
170
171
sage: sage.modular.cusps_nf.NFCusps_clear_cache()
172
sage: k.<a> = NumberField(x^3 + 51)
173
sage: kCusps = NFCusps(k); kCusps
174
Set of all cusps of Number Field in a with defining polynomial x^3 + 51
175
sage: sage.modular.cusps_nf._nfcusps_cache.keys()
176
[Number Field in a with defining polynomial x^3 + 51]
177
sage: NFCusps_clear_cache()
178
sage: sage.modular.cusps_nf._nfcusps_cache.keys()
179
[]
180
"""
181
global _nfcusps_cache
182
_nfcusps_cache = {}
183
184
def NFCusps(number_field, use_cache=True):
185
r"""
186
The set of cusps of a number field `K`, i.e. `\mathbb{P}^1(K)`.
187
188
INPUT:
189
190
- ``number_field`` -- a number field
191
192
- ``use_cache`` -- bool (default=True) - to set a cache of number fields
193
and their associated sets of cusps
194
195
OUTPUT:
196
197
The set of cusps over the given number field.
198
199
EXAMPLES::
200
201
sage: k.<a> = NumberField(x^2 + 5)
202
sage: kCusps = NFCusps(k); kCusps
203
Set of all cusps of Number Field in a with defining polynomial x^2 + 5
204
sage: kCusps is NFCusps(k)
205
True
206
207
Saving and loading works:
208
209
::
210
211
sage: loads(kCusps.dumps()) == kCusps
212
True
213
214
We test use_cache:
215
216
::
217
218
sage: NFCusps_clear_cache()
219
sage: k.<a> = NumberField(x^2 + 11)
220
sage: kCusps = NFCusps(k, use_cache=False)
221
sage: sage.modular.cusps_nf._nfcusps_cache
222
{}
223
sage: kCusps = NFCusps(k, use_cache=True)
224
sage: sage.modular.cusps_nf._nfcusps_cache
225
{Number Field in a with defining polynomial x^2 + 11: ...}
226
sage: kCusps is NFCusps(k, use_cache=False)
227
False
228
sage: kCusps is NFCusps(k, use_cache=True)
229
True
230
"""
231
if use_cache:
232
key = number_field
233
if _nfcusps_cache.has_key(key):
234
C = _nfcusps_cache[key]
235
if not (C is None): return C
236
237
C = NFCuspsSpace(number_field)
238
if use_cache:
239
_nfcusps_cache[key] = C
240
return C
241
242
#**************************************************************************
243
#* NFCuspsSpace class *
244
#**************************************************************************
245
class NFCuspsSpace(ParentWithBase):
246
"""
247
The set of cusps of a number field. See ``NFCusps`` for full documentation.
248
249
EXAMPLES::
250
251
sage: k.<a> = NumberField(x^2 + 5)
252
sage: kCusps = NFCusps(k); kCusps
253
Set of all cusps of Number Field in a with defining polynomial x^2 + 5
254
"""
255
256
def __init__(self, number_field):
257
"""
258
See ``NFCusps`` for full documentation.
259
260
EXAMPLES::
261
262
sage: k.<a> = NumberField(x^3 + x^2 + 13)
263
sage: kCusps = NFCusps(k); kCusps
264
Set of all cusps of Number Field in a with defining polynomial x^3 + x^2 + 13
265
"""
266
self.__number_field = number_field
267
ParentWithBase.__init__(self, self)
268
269
def __cmp__(self, right):
270
"""
271
Return equality only if right is the set of cusps for the same field.
272
273
Comparing sets of cusps for two different fields gives the same
274
result as comparing the two fields.
275
276
EXAMPLES::
277
278
sage: k.<a> = NumberField(x^2 + 5)
279
sage: L.<a> = NumberField(x^2 + 23)
280
sage: kCusps = NFCusps(k); kCusps
281
Set of all cusps of Number Field in a with defining polynomial x^2 + 5
282
sage: LCusps = NFCusps(L); LCusps
283
Set of all cusps of Number Field in a with defining polynomial x^2 + 23
284
sage: kCusps == NFCusps(k)
285
True
286
sage: LCusps == NFCusps(L)
287
True
288
sage: LCusps == kCusps
289
False
290
291
"""
292
t = cmp(type(self), type(right))
293
if t:
294
return t
295
else:
296
return cmp(self.number_field(), right.number_field())
297
298
def _repr_(self):
299
"""
300
String representation of the set of cusps of a number field.
301
302
EXAMPLES::
303
304
sage: k.<a> = NumberField(x^2 + 2)
305
sage: kCusps = NFCusps(k)
306
sage: kCusps
307
Set of all cusps of Number Field in a with defining polynomial x^2 + 2
308
sage: kCusps._repr_()
309
'Set of all cusps of Number Field in a with defining polynomial x^2 + 2'
310
sage: kCusps.rename('Number Field Cusps'); kCusps
311
Number Field Cusps
312
sage: kCusps.rename(); kCusps
313
Set of all cusps of Number Field in a with defining polynomial x^2 + 2
314
315
"""
316
return "Set of all cusps of %s" %(self.number_field())
317
318
def _latex_(self):
319
"""
320
Return latex representation of self.
321
322
EXAMPLES::
323
324
sage: k.<a> = NumberField(x^2 + 5)
325
sage: kCusps = NFCusps(k)
326
sage: latex(kCusps) # indirect doctest
327
\mathbf{P}^1(\Bold{Q}[a]/(a^{2} + 5))
328
"""
329
return "\\mathbf{P}^1(%s)" %(self.number_field()._latex_())
330
331
def __call__(self, x):
332
"""
333
Convert x into the set of cusps of a number field.
334
335
EXAMPLES::
336
337
sage: k.<a> = NumberField(x^2 + 5)
338
sage: kCusps = NFCusps(k)
339
sage: c = kCusps(a,2)
340
Traceback (most recent call last):
341
...
342
TypeError: __call__() takes exactly 2 arguments (3 given)
343
344
::
345
346
sage: c = kCusps((a,2)); c
347
Cusp [a: 2] of Number Field in a with defining polynomial x^2 + 5
348
sage: kCusps(2/a)
349
Cusp [-2*a: 5] of Number Field in a with defining polynomial x^2 + 5
350
sage: kCusps(oo)
351
Cusp Infinity of Number Field in a with defining polynomial x^2 + 5
352
"""
353
return NFCusp(self.number_field(), x, parent=self)
354
355
@cached_method
356
def zero_element(self):
357
"""
358
Return the zero cusp.
359
360
NOTE:
361
362
This method just exists to make some general algorithms work.
363
It is not intended that the returned cusp is an additive
364
neutral element.
365
366
EXAMPLE::
367
368
sage: k.<a> = NumberField(x^2 + 5)
369
sage: kCusps = NFCusps(k)
370
sage: kCusps.zero_element()
371
Cusp [0: 1] of Number Field in a with defining polynomial x^2 + 5
372
373
"""
374
return self(0)
375
376
def number_field(self):
377
"""
378
Return the number field that this set of cusps is attached to.
379
380
EXAMPLES::
381
382
sage: k.<a> = NumberField(x^2 + 1)
383
sage: kCusps = NFCusps(k)
384
sage: kCusps.number_field()
385
Number Field in a with defining polynomial x^2 + 1
386
"""
387
return self.__number_field
388
389
#**************************************************************************
390
#* NFCusp class *
391
#**************************************************************************
392
393
class NFCusp(Element):
394
r"""
395
Creates a number field cusp, i.e., an element of `\mathbb{P}^1(k)`.
396
397
A cusp on a number field is either an element of the field or infinity,
398
i.e., an element of the projective line over the number field. It is
399
stored as a pair (a,b), where a, b are integral elements of the number
400
field.
401
402
INPUT:
403
404
- ``number_field`` -- the number field over which the cusp is defined.
405
406
- ``a`` -- it can be a number field element (integral or not), or
407
a number field cusp.
408
409
- ``b`` -- (optional) when present, it must be either Infinity or
410
coercible to an element of the number field.
411
412
- ``lreps`` -- (optional) a list of chosen representatives for all the
413
ideal classes of the field. When given, the representative of the cusp
414
will be changed so its associated ideal is one of the ideals in the list.
415
416
OUTPUT:
417
418
``[a: b]`` -- a number field cusp.
419
420
EXAMPLES::
421
422
sage: k.<a> = NumberField(x^2 + 5)
423
sage: NFCusp(k, a, 2)
424
Cusp [a: 2] of Number Field in a with defining polynomial x^2 + 5
425
sage: NFCusp(k, (a,2))
426
Cusp [a: 2] of Number Field in a with defining polynomial x^2 + 5
427
sage: NFCusp(k, a, 2/(a+1))
428
Cusp [a - 5: 2] of Number Field in a with defining polynomial x^2 + 5
429
430
Cusp Infinity:
431
432
::
433
434
sage: NFCusp(k, 0)
435
Cusp [0: 1] of Number Field in a with defining polynomial x^2 + 5
436
sage: NFCusp(k, oo)
437
Cusp Infinity of Number Field in a with defining polynomial x^2 + 5
438
sage: NFCusp(k, 3*a, oo)
439
Cusp [0: 1] of Number Field in a with defining polynomial x^2 + 5
440
sage: NFCusp(k, a + 5, 0)
441
Cusp Infinity of Number Field in a with defining polynomial x^2 + 5
442
443
Saving and loading works:
444
445
::
446
447
sage: alpha = NFCusp(k, a, 2/(a+1))
448
sage: loads(dumps(alpha))==alpha
449
True
450
451
Some tests:
452
453
::
454
455
sage: I*I
456
-1
457
sage: NFCusp(k, I)
458
Traceback (most recent call last):
459
...
460
TypeError: Unable to convert I to a cusp of the number field
461
462
::
463
464
sage: NFCusp(k, oo, oo)
465
Traceback (most recent call last):
466
...
467
TypeError: Unable to convert (+Infinity, +Infinity) to a cusp of the number field
468
469
::
470
471
sage: NFCusp(k, 0, 0)
472
Traceback (most recent call last):
473
...
474
TypeError: Unable to convert (0, 0) to a cusp of the number field
475
476
::
477
478
sage: NFCusp(k, "a + 2", a)
479
Cusp [-2*a + 5: 5] of Number Field in a with defining polynomial x^2 + 5
480
481
::
482
483
sage: NFCusp(k, NFCusp(k, oo))
484
Cusp Infinity of Number Field in a with defining polynomial x^2 + 5
485
sage: c = NFCusp(k, 3, 2*a)
486
sage: NFCusp(k, c, a + 1)
487
Cusp [-a - 5: 20] of Number Field in a with defining polynomial x^2 + 5
488
sage: L.<b> = NumberField(x^2 + 2)
489
sage: NFCusp(L, c)
490
Traceback (most recent call last):
491
...
492
ValueError: Cannot coerce cusps from one field to another
493
"""
494
def __init__(self, number_field, a, b=None, parent=None, lreps=None):
495
"""
496
Constructor of number field cusps. See ``NFCusp`` for full
497
documentation.
498
499
EXAMPLES::
500
501
sage: k.<a> = NumberField(x^2 + 1)
502
sage: c = NFCusp(k, 3, a+1); c
503
Cusp [3: a + 1] of Number Field in a with defining polynomial x^2 + 1
504
sage: c.parent()
505
Set of all cusps of Number Field in a with defining polynomial x^2 + 1
506
sage: kCusps = NFCusps(k)
507
sage: c.parent() is kCusps
508
True
509
"""
510
if parent is None:
511
parent = NFCusps(number_field)
512
Element.__init__(self, parent)
513
R = number_field.maximal_order()
514
if b is None:
515
if not a:#that is cusp "0"
516
self.__a = R(0)
517
self.__b = R(1)
518
return
519
if isinstance(a, NFCusp):
520
if a.parent() == parent:
521
self.__a = R(a.__a)
522
self.__b = R(a.__b)
523
else:
524
raise ValueError, "Cannot coerce cusps from one field to another"
525
elif a in R:
526
self.__a = R(a)
527
self.__b = R(1)
528
elif a in number_field:
529
self.__b = R(a.denominator())
530
self.__a = R(a * self.__b)
531
elif is_InfinityElement(a):
532
self.__a = R(1)
533
self.__b = R(0)
534
elif isinstance(a, (int, long)):
535
self.__a = R(a)
536
self.__b = R(1)
537
elif isinstance(a, (tuple, list)):
538
if len(a) != 2:
539
raise TypeError, "Unable to convert %s to a cusp \
540
of the number field"%a
541
if a[1].is_zero():
542
self.__a = R(1)
543
self.__b = R(0)
544
elif a[0] in R and a[1] in R:
545
self.__a = R(a[0])
546
self.__b = R(a[1])
547
elif isinstance(a[0], NFCusp):#we know that a[1] is not zero
548
if a[1] == 1:
549
self.__a = a[0].__a
550
self.__b = a[0].__b
551
else:
552
r = a[0].__a / (a[0].__b * a[1])
553
self.__b = R(r.denominator())
554
self.__a = R(r*self.__b)
555
else:
556
try:
557
r = number_field(a[0]/a[1])
558
self.__b = R(r.denominator())
559
self.__a = R(r * self.__b)
560
except (ValueError, TypeError):
561
raise TypeError, "Unable to convert %s to a cusp \
562
of the number field"%a
563
else:
564
try:
565
r = number_field(a)
566
self.__b = R(r.denominator())
567
self.__a = R(r * self.__b)
568
except (ValueError, TypeError):
569
raise TypeError, "Unable to convert %s to a cusp \
570
of the number field"%a
571
else:#'b' is given
572
if is_InfinityElement(b):
573
if is_InfinityElement(a) or (isinstance(a, NFCusp) and a.is_infinity()):
574
raise TypeError, "Unable to convert (%s, %s) \
575
to a cusp of the number field"%(a, b)
576
self.__a = R(0)
577
self.__b = R(1)
578
return
579
elif not b:
580
if not a:
581
raise TypeError, "Unable to convert (%s, %s) \
582
to a cusp of the number field"%(a, b)
583
self.__a = R(1)
584
self.__b = R(0)
585
return
586
if not a:
587
self.__a = R(0)
588
self.__b = R(1)
589
return
590
if (b in R or isinstance(b, (int, long))) and (a in R or isinstance(a, (int, long))):
591
self.__a = R(a)
592
self.__b = R(b)
593
else:
594
if a in R or a in number_field:
595
r = a / b
596
elif is_InfinityElement(a):
597
self.__a = R(1)
598
self.__b = R(0)
599
return
600
elif isinstance(a, NFCusp):
601
if a.is_infinity():
602
self.__a = R(1)
603
self.__b = R(0)
604
return
605
r = a.__a / (a.__b * b)
606
elif isinstance(a, (int, long)):
607
r = R(a) / b
608
elif isinstance(a, (tuple, list)):
609
if len(a) != 2:
610
raise TypeError, "Unable to convert (%s, %s) \
611
to a cusp of the number field"%(a, b)
612
r = R(a[0]) / (R(a[1]) * b)
613
else:
614
try:
615
r = number_field(a) / b
616
except (ValueError, TypeError):
617
raise TypeError, "Unable to convert (%s, %s) \
618
to a cusp of the number field"%(a, b)
619
self.__b = R(r.denominator())
620
self.__a = R(r * self.__b)
621
if not lreps is None:
622
# Changes the representative of the cusp so the ideal associated
623
# to the cusp is one of the ideals of the given list lreps.
624
# Note: the trivial class is always represented by (1).
625
I = self.ideal()
626
for J in lreps:
627
if (J/I).is_principal():
628
newI = J
629
l = (newI/I).gens_reduced()[0]
630
self.__a = R(l * self.__a)
631
self.__b = R(l * self.__b)
632
633
def _repr_(self):
634
"""
635
String representation of this cusp.
636
637
EXAMPLES::
638
sage: k.<a> = NumberField(x^2 + 1)
639
sage: c = NFCusp(k, a, 2); c
640
Cusp [a: 2] of Number Field in a with defining polynomial x^2 + 1
641
sage: c._repr_()
642
'Cusp [a: 2] of Number Field in a with defining polynomial x^2 + 1'
643
sage: c.rename('[a:2](cusp of a number field)');c
644
[a:2](cusp of a number field)
645
sage: c.rename();c
646
Cusp [a: 2] of Number Field in a with defining polynomial x^2 + 1
647
"""
648
if self.__b.is_zero():
649
return "Cusp Infinity of %s"%self.parent().number_field()
650
else:
651
return "Cusp [%s: %s] of %s"%(self.__a, self.__b, \
652
self.parent().number_field())
653
654
655
def number_field(self):
656
"""
657
Returns the number field of definition of the cusp ``self``
658
659
EXAMPLES::
660
661
sage: k.<a> = NumberField(x^2 + 2)
662
sage: alpha = NFCusp(k, 1, a + 1)
663
sage: alpha.number_field()
664
Number Field in a with defining polynomial x^2 + 2
665
"""
666
return self.parent().number_field()
667
668
def is_infinity(self):
669
"""
670
Returns ``True`` if this is the cusp infinity.
671
672
EXAMPLES::
673
674
sage: k.<a> = NumberField(x^2 + 1)
675
sage: NFCusp(k, a, 2).is_infinity()
676
False
677
sage: NFCusp(k, 2, 0).is_infinity()
678
True
679
sage: NFCusp(k, oo).is_infinity()
680
True
681
"""
682
return self.__b == 0
683
684
def numerator(self):
685
"""
686
Return the numerator of the cusp ``self``.
687
688
EXAMPLES::
689
690
sage: k.<a> = NumberField(x^2 + 1)
691
sage: c = NFCusp(k, a, 2)
692
sage: c.numerator()
693
a
694
sage: d = NFCusp(k, 1, a)
695
sage: d.numerator()
696
1
697
sage: NFCusp(k, oo).numerator()
698
1
699
"""
700
return self.__a
701
702
703
def denominator(self):
704
"""
705
Return the denominator of the cusp ``self``.
706
707
EXAMPLES::
708
709
sage: k.<a> = NumberField(x^2 + 1)
710
sage: c = NFCusp(k, a, 2)
711
sage: c.denominator()
712
2
713
sage: d = NFCusp(k, 1, a + 1);d
714
Cusp [1: a + 1] of Number Field in a with defining polynomial x^2 + 1
715
sage: d.denominator()
716
a + 1
717
sage: NFCusp(k, oo).denominator()
718
0
719
"""
720
return self.__b
721
722
def _number_field_element_(self):
723
"""
724
Coerce to an element of the number field.
725
726
EXAMPLES::
727
728
sage: k.<a> = NumberField(x^2 + 2)
729
sage: NFCusp(k, a, 2)._number_field_element_()
730
1/2*a
731
sage: NFCusp(k, 1, a + 1)._number_field_element_()
732
-1/3*a + 1/3
733
"""
734
if self.__b.is_zero():
735
raise TypeError, "%s is not an element of %s"%(self, \
736
self.number_field())
737
k = self.number_field()
738
return k(self.__a / self.__b)
739
740
741
def _ring_of_integers_element_(self):
742
"""
743
Coerce to an element of the ring of integers of the number field.
744
745
EXAMPLES::
746
747
sage: k.<a> = NumberField(x^2 + 2)
748
sage: NFCusp(k, a+1)._ring_of_integers_element_()
749
a + 1
750
sage: NFCusp(k, 1, a + 1)._ring_of_integers_element_()
751
Traceback (most recent call last):
752
...
753
TypeError: Cusp [1: a + 1] of Number Field in a with defining polynomial x^2 + 2 is not an integral element
754
"""
755
if self.__b.is_one():
756
return self.__a
757
if self.__b.is_zero():
758
raise TypeError, "%s is not an element of %s"%(self, \
759
self.number_field.ring_of_integers())
760
R = self.number_field().ring_of_integers()
761
try:
762
return R(self.__a/self.__b)
763
except (ValueError, TypeError):
764
raise TypeError, "%s is not an integral element"%self
765
766
def _latex_(self):
767
r"""
768
Latex representation of this cusp.
769
770
EXAMPLES::
771
772
sage: k.<a> = NumberField(x^2 + 11)
773
sage: latex(NFCusp(k, 3*a, a + 1)) # indirect doctest
774
\[3 a: a + 1\]
775
sage: latex(NFCusp(k, 3*a, a + 1)) == NFCusp(k, 3*a, a + 1)._latex_()
776
True
777
sage: latex(NFCusp(k, oo))
778
\infty
779
"""
780
if self.__b.is_zero():
781
return "\\infty"
782
else:
783
return "\\[%s: %s\\]"%(self.__a._latex_(), \
784
self.__b._latex_())
785
786
def __cmp__(self, right):
787
"""
788
Compare the cusps self and right. Comparison is as for elements in
789
the number field, except with the cusp oo which is greater than
790
everything but itself.
791
792
The ordering in comparison is only really meaningful for infinity.
793
794
EXAMPLES::
795
796
sage: k.<a> = NumberField(x^3 + x + 1)
797
sage: kCusps = NFCusps(k)
798
799
Comparing with infinity:
800
801
::
802
sage: c = kCusps((a,2))
803
sage: d = kCusps(oo)
804
sage: c < d
805
True
806
sage: kCusps(oo) < d
807
False
808
809
Comparison as elements of the number field:
810
811
::
812
813
sage: kCusps(2/3) < kCusps(5/2)
814
False
815
sage: k(2/3) < k(5/2)
816
False
817
"""
818
if self.__b.is_zero():
819
# self is oo, which is bigger than everything but oo.
820
if right.__b.is_zero():
821
return 0
822
else:
823
return 1
824
elif right.__b.is_zero():
825
if self.__b.is_zero():
826
return 0
827
else:
828
return -1
829
return cmp(self._number_field_element_(), right._number_field_element_())
830
831
def __neg__(self):
832
"""
833
The negative of this cusp.
834
835
EXAMPLES::
836
837
sage: k.<a> = NumberField(x^2 + 23)
838
sage: c = NFCusp(k, a, a+1); c
839
Cusp [a: a + 1] of Number Field in a with defining polynomial x^2 + 23
840
sage: -c
841
Cusp [-a: a + 1] of Number Field in a with defining polynomial x^2 + 23
842
"""
843
return NFCusp(self.parent().number_field(), -self.__a, self.__b)
844
845
def apply(self, g):
846
"""
847
Return g(``self``), where ``g`` is a 2x2 matrix, which we view as a
848
linear fractional transformation.
849
850
INPUT:
851
852
- ``g`` -- a list of integral elements [a, b, c, d] that are the
853
entries of a 2x2 matrix.
854
855
OUTPUT:
856
857
A number field cusp, obtained by the action of ``g`` on the cusp
858
``self``.
859
860
EXAMPLES:
861
862
::
863
864
sage: k.<a> = NumberField(x^2 + 23)
865
sage: beta = NFCusp(k, 0, 1)
866
sage: beta.apply([0, -1, 1, 0])
867
Cusp Infinity of Number Field in a with defining polynomial x^2 + 23
868
sage: beta.apply([1, a, 0, 1])
869
Cusp [a: 1] of Number Field in a with defining polynomial x^2 + 23
870
"""
871
k = self.number_field()
872
return NFCusp(k, g[0]*self.__a + g[1]*self.__b, \
873
g[2]*self.__a + g[3]*self.__b)
874
875
def ideal(self):
876
"""
877
Returns the ideal associated to the cusp ``self``.
878
879
EXAMPLES::
880
881
sage: k.<a> = NumberField(x^2 + 23)
882
sage: alpha = NFCusp(k, 3, a-1)
883
sage: alpha.ideal()
884
Fractional ideal (3, 1/2*a - 1/2)
885
sage: NFCusp(k, oo).ideal()
886
Fractional ideal (1)
887
"""
888
k = self.number_field()
889
return k.ideal(self.__a, self.__b)
890
891
def ABmatrix(self):
892
"""
893
Returns AB-matrix associated to the cusp ``self``.
894
895
Given R a Dedekind domain and A, B ideals of R in inverse classes, an
896
AB-matrix is a matrix realizing the isomorphism between R+R and A+B.
897
An AB-matrix associated to a cusp [a1: a2] is an AB-matrix with A the
898
ideal associated to the cusp (A=<a1, a2>) and first column given by
899
the coefficients of the cusp.
900
901
EXAMPLES:
902
903
::
904
905
sage: k.<a> = NumberField(x^3 + 11)
906
sage: alpha = NFCusp(k, oo)
907
sage: alpha.ABmatrix()
908
[1, 0, 0, 1]
909
910
::
911
912
sage: alpha = NFCusp(k, 0)
913
sage: alpha.ABmatrix()
914
[0, -1, 1, 0]
915
916
Note that the AB-matrix associated to a cusp is not unique, and the
917
output of the ``ABmatrix`` function may change.
918
919
::
920
921
sage: alpha = NFCusp(k, 3/2, a-1)
922
sage: M = alpha.ABmatrix()
923
sage: M # random
924
[-a^2 - a - 1, -3*a - 7, 8, -2*a^2 - 3*a + 4]
925
sage: M[0] == alpha.numerator() and M[2]==alpha.denominator()
926
True
927
928
929
An AB-matrix associated to a cusp alpha will send Infinity to alpha:
930
931
::
932
933
sage: alpha = NFCusp(k, 3, a-1)
934
sage: M = alpha.ABmatrix()
935
sage: (k.ideal(M[1], M[3])*alpha.ideal()).is_principal()
936
True
937
sage: M[0] == alpha.numerator() and M[2]==alpha.denominator()
938
True
939
sage: NFCusp(k, oo).apply(M) == alpha
940
True
941
"""
942
k = self.number_field()
943
A = self.ideal()
944
945
if self.is_infinity():
946
return [1, 0, 0, 1]
947
if not self:
948
return [0, -1, 1, 0]
949
950
if A.is_principal():
951
B = k.ideal(1)
952
else:
953
B = k.ideal(A.gens_reduced()[1])/A
954
assert (A*B).is_principal()
955
956
a1 = self.__a
957
a2 = self.__b
958
959
g = (A*B).gens_reduced()[0]
960
Ainv = A**(-1)
961
A1 = a1*Ainv
962
A2 = a2*Ainv
963
r = A1.element_1_mod(A2)
964
b1 = -(1-r)/a2*g
965
b2 = (r/a1)*g
966
ABM = [a1, b1, a2, b2]
967
968
return ABM
969
970
def is_Gamma0_equivalent(self, other, N, Transformation=False):
971
r"""
972
Checks if cusps ``self`` and ``other`` are `\Gamma_0(N)`- equivalent.
973
974
INPUT:
975
976
- ``other`` -- a number field cusp or a list of two number field
977
elements which define a cusp.
978
979
- ``N`` -- an ideal of the number field (level)
980
981
OUTPUT:
982
983
- bool -- ``True`` if the cusps are equivalent.
984
985
- a transformation matrix -- (if ``Transformation=True``) a list of
986
integral elements [a, b, c, d] which are the entries of a 2x2 matrix
987
M in `\Gamma_0(N)` such that M * ``self`` = ``other`` if ``other``
988
and ``self`` are `\Gamma_0(N)`- equivalent. If ``self`` and ``other``
989
are not equivalent it returns zero.
990
991
EXAMPLES:
992
993
::
994
995
sage: K.<a> = NumberField(x^3-10)
996
sage: N = K.ideal(a-1)
997
sage: alpha = NFCusp(K, 0)
998
sage: beta = NFCusp(K, oo)
999
sage: alpha.is_Gamma0_equivalent(beta, N)
1000
False
1001
sage: alpha.is_Gamma0_equivalent(beta, K.ideal(1))
1002
True
1003
sage: b, M = alpha.is_Gamma0_equivalent(beta, K.ideal(1),Transformation=True)
1004
sage: alpha.apply(M)
1005
Cusp Infinity of Number Field in a with defining polynomial x^3 - 10
1006
1007
::
1008
1009
sage: k.<a> = NumberField(x^2+23)
1010
sage: N = k.ideal(3)
1011
sage: alpha1 = NFCusp(k, a+1, 4)
1012
sage: alpha2 = NFCusp(k, a-8, 29)
1013
sage: alpha1.is_Gamma0_equivalent(alpha2, N)
1014
True
1015
sage: b, M = alpha1.is_Gamma0_equivalent(alpha2, N, Transformation=True)
1016
sage: alpha1.apply(M) == alpha2
1017
True
1018
sage: M[2] in N
1019
True
1020
"""
1021
k = self.number_field()
1022
other = NFCusp(k, other)
1023
if not (self.ideal()/other.ideal()).is_principal():
1024
if not Transformation:
1025
return False
1026
else:
1027
return False, 0
1028
1029
reps = list_of_representatives(N)
1030
alpha1 = NFCusp(k, self, lreps=reps)
1031
alpha2 = NFCusp(k, other, lreps=reps)
1032
1033
delta = k.ideal(alpha1.__b) + N
1034
if (k.ideal(alpha2.__b) + N)!= delta:
1035
if not Transformation:
1036
return False
1037
else:
1038
return False, 0
1039
1040
M1 = alpha1.ABmatrix()
1041
M2 = alpha2.ABmatrix()
1042
1043
A = alpha1.ideal()
1044
B = k.ideal(M1[1], M1[3])
1045
1046
ABdelta = A*B*delta*delta
1047
1048
units = units_mod_ideal(ABdelta)
1049
for u in units:
1050
if (M2[2]*M1[3] - u*M1[2]*M2[3]) in ABdelta:
1051
if not Transformation:
1052
return True
1053
else:
1054
AuxCoeff = [1, 0, 0, 1]
1055
Aux = M2[2]*M1[3] - u*M1[2]*M2[3]
1056
if Aux in A*B*N:
1057
if not u==1:
1058
AuxCoeff[3] = u
1059
else:
1060
A1 = (A*B*N)/ABdelta
1061
A2 = B*k.ideal(M1[2]*M2[2])/(A*ABdelta)
1062
f = A1.element_1_mod(A2)
1063
w = ((1 - f)*Aux)/(M1[2]*M2[2])
1064
AuxCoeff[3] = u
1065
AuxCoeff[1] = w
1066
from sage.matrix.all import Matrix
1067
Maux = Matrix(k, 2, AuxCoeff)
1068
M1inv = Matrix(k, 2, M1).inverse()
1069
Mtrans = Matrix(k, 2, M2)*Maux*M1inv
1070
assert Mtrans[1][0] in N
1071
return True, Mtrans.list()
1072
if not Transformation:
1073
return False
1074
else:
1075
return False, 0
1076
1077
#**************************************************************************
1078
# Global functions:
1079
# - Gamma0_NFCusps --compute list of inequivalent cusps
1080
# Internal use only:
1081
# - number_of_Gamma0_NFCusps -- useful to test Gamma0_NFCusps
1082
# - NFCusps_ideal_reps_for_levelN -- lists of reps for ideal classes
1083
# - units_mod_ideal -- needed to check Gamma0(N)-equiv of cusps
1084
#**************************************************************************
1085
1086
def Gamma0_NFCusps(N):
1087
r"""
1088
Returns a list of inequivalent cusps for `\Gamma_0(N)`, i.e., a set of
1089
representatives for the orbits of ``self`` on `\mathbb{P}^1(k)`.
1090
1091
INPUT:
1092
1093
- ``N`` -- an integral ideal of the number field k (the level).
1094
1095
OUTPUT:
1096
1097
A list of inequivalent number field cusps.
1098
1099
EXAMPLES:
1100
1101
::
1102
1103
sage: k.<a> = NumberField(x^2 + 5)
1104
sage: N = k.ideal(3)
1105
sage: L = Gamma0_NFCusps(N)
1106
1107
The cusps in the list are inequivalent:
1108
1109
::
1110
1111
sage: all([not L[i].is_Gamma0_equivalent(L[j], N) for i, j in \
1112
mrange([len(L), len(L)]) if i<j])
1113
True
1114
1115
We test that we obtain the right number of orbits:
1116
1117
::
1118
1119
sage: from sage.modular.cusps_nf import number_of_Gamma0_NFCusps
1120
sage: len(L) == number_of_Gamma0_NFCusps(N)
1121
True
1122
1123
Another example:
1124
1125
::
1126
1127
sage: k.<a> = NumberField(x^4 - x^3 -21*x^2 + 17*x + 133)
1128
sage: N = k.ideal(5)
1129
sage: from sage.modular.cusps_nf import number_of_Gamma0_NFCusps
1130
sage: len(Gamma0_NFCusps(N)) == number_of_Gamma0_NFCusps(N) # long time (over 1 sec)
1131
True
1132
"""
1133
# We create L a list of three lists, which are different and each a list of
1134
# prime ideals, coprime to N, representing the ideal classes of k
1135
L = NFCusps_ideal_reps_for_levelN(N, nlists=3)
1136
Laux = L[1]+L[2]
1137
Lreps = list_of_representatives(N)
1138
Lcusps = []
1139
1140
k = N.number_field()
1141
1142
for A in L[0]:
1143
#find B in inverse class:
1144
if A.is_trivial():
1145
B = k.ideal(1)
1146
#B = k.unit_ideal() produces an error because we need fract ideal
1147
g = 1
1148
else:
1149
Lbs = [P for P in Laux if (P*A).is_principal()]
1150
B = Lbs[0]
1151
g = (A*B).gens_reduced()[0]
1152
1153
#for every divisor of N we have to find cusps
1154
from sage.rings.arith import divisors
1155
for d in divisors(N):
1156
#find delta prime coprime to B in inverse class of d*A
1157
#by searching in our list of auxiliary prime ideals
1158
Lds = [P for P in Laux if (P*d*A).is_principal() and P.is_coprime(B)]
1159
deltap = Lds[0]
1160
a = (deltap*d*A).gens_reduced()[0]
1161
I = d + N/d
1162
#especial case: A=B=d=<1>:
1163
if a.is_one() and I.is_trivial():
1164
Lcusps.append(NFCusp(k, 0, 1, lreps=Lreps))
1165
else:
1166
u = k.unit_group().gens()
1167
for b in I.invertible_residues_mod(u):
1168
#Note: if I trivial, invertible_residues_mod returns [1]
1169
#lift b to (R/a)star
1170
#we need the part of d which is coprime to I, call it M
1171
M = d.prime_to_idealM_part(I)
1172
deltAM = deltap*A*M
1173
u = (B*deltAM).element_1_mod(I)
1174
v = (I*B).element_1_mod(deltAM)
1175
newb = u*b + v
1176
#build AB-matrix:
1177
#----> extended gcd for k.ideal(a), k.ideal(newb)
1178
Y = k.ideal(newb).element_1_mod(k.ideal(a))
1179
# if xa + yb = 1, cusp = y*g /a
1180
Lcusps.append(NFCusp(k, Y*g, a, lreps=Lreps))
1181
return Lcusps
1182
1183
def number_of_Gamma0_NFCusps(N):
1184
"""
1185
Returns the total number of orbits of cusps under the action of the
1186
congruence subgroup `\\Gamma_0(N)`.
1187
1188
INPUT:
1189
1190
- ``N`` -- a number field ideal.
1191
1192
OUTPUT:
1193
1194
ingeter -- the number of orbits of cusps under Gamma0(N)-action.
1195
1196
EXAMPLES::
1197
1198
sage: k.<a> = NumberField(x^3 + 11)
1199
sage: N = k.ideal(2, a+1)
1200
sage: from sage.modular.cusps_nf import number_of_Gamma0_NFCusps
1201
sage: number_of_Gamma0_NFCusps(N)
1202
4
1203
sage: L = Gamma0_NFCusps(N)
1204
sage: len(L) == number_of_Gamma0_NFCusps(N)
1205
True
1206
"""
1207
k = N.number_field()
1208
# The number of Gamma0(N)-sub-orbits for each Gamma-orbit:
1209
from sage.rings.arith import divisors
1210
s = sum([len(list((d+N/d).invertible_residues_mod(k.unit_group().gens()))) \
1211
for d in divisors(N)])
1212
# There are h Gamma-orbits, with h class number of underlying number field.
1213
return s*k.class_number()
1214
1215
def NFCusps_ideal_reps_for_levelN(N, nlists=1):
1216
"""
1217
Returns a list of lists (``nlists`` different lists) of prime ideals,
1218
coprime to ``N``, representing every ideal class of the number field.
1219
1220
INPUT:
1221
1222
- ``N`` -- number field ideal.
1223
1224
- ``nlists`` -- optional (default 1). The number of lists of prime ideals
1225
we want.
1226
1227
OUTPUT:
1228
1229
A list of lists of ideals representatives of the ideal classes, all coprime
1230
to ``N``, representing every ideal.
1231
1232
EXAMPLES::
1233
1234
sage: k.<a> = NumberField(x^3 + 11)
1235
sage: N = k.ideal(5, a + 1)
1236
sage: from sage.modular.cusps_nf import NFCusps_ideal_reps_for_levelN
1237
sage: NFCusps_ideal_reps_for_levelN(N)
1238
[(Fractional ideal (1), Fractional ideal (2, a + 1))]
1239
sage: L = NFCusps_ideal_reps_for_levelN(N, 3)
1240
sage: all([len(L[i])==k.class_number() for i in range(len(L))])
1241
True
1242
1243
::
1244
1245
sage: k.<a> = NumberField(x^4 - x^3 -21*x^2 + 17*x + 133)
1246
sage: N = k.ideal(6)
1247
sage: from sage.modular.cusps_nf import NFCusps_ideal_reps_for_levelN
1248
sage: NFCusps_ideal_reps_for_levelN(N)
1249
[(Fractional ideal (1),
1250
Fractional ideal (13, a - 2),
1251
Fractional ideal (43, a - 1),
1252
Fractional ideal (67, a + 17))]
1253
sage: L = NFCusps_ideal_reps_for_levelN(N, 5)
1254
sage: all([len(L[i])==k.class_number() for i in range(len(L))])
1255
True
1256
"""
1257
k = N.number_field()
1258
G = k.class_group()
1259
L = []
1260
for i in range(nlists):
1261
L.append([k.ideal(1)])
1262
it = k.primes_of_degree_one_iter()
1263
for I in G.list():
1264
check = 0
1265
if not I.is_principal():
1266
Iinv = (I.ideal())**(-1)
1267
while check<nlists:
1268
J = it.next()
1269
if (J*Iinv).is_principal() and J.is_coprime(N):
1270
L[check].append(J)
1271
check = check + 1
1272
return [tuple(l) for l in L]
1273
1274
def units_mod_ideal(I):
1275
"""
1276
Returns integral elements of the number field representing the images of
1277
the global units modulo the ideal ``I``.
1278
1279
INPUT:
1280
1281
- ``I`` -- number field ideal.
1282
1283
OUTPUT:
1284
1285
A list of integral elements of the number field representing the images of
1286
the global units modulo the ideal ``I``. Elements of the list might be
1287
equivalent to each other mod ``I``.
1288
1289
EXAMPLES::
1290
1291
sage: from sage.modular.cusps_nf import units_mod_ideal
1292
sage: k.<a> = NumberField(x^2 + 1)
1293
sage: I = k.ideal(a + 1)
1294
sage: units_mod_ideal(I)
1295
[1]
1296
sage: I = k.ideal(3)
1297
sage: units_mod_ideal(I)
1298
[1, -a, -1, a]
1299
1300
::
1301
1302
sage: from sage.modular.cusps_nf import units_mod_ideal
1303
sage: k.<a> = NumberField(x^3 + 11)
1304
sage: k.unit_group()
1305
Unit group with structure C2 x Z of Number Field in a with defining polynomial x^3 + 11
1306
sage: I = k.ideal(5, a + 1)
1307
sage: units_mod_ideal(I)
1308
[1,
1309
2*a^2 + 4*a - 1,
1310
...]
1311
1312
::
1313
1314
sage: from sage.modular.cusps_nf import units_mod_ideal
1315
sage: k.<a> = NumberField(x^4 - x^3 -21*x^2 + 17*x + 133)
1316
sage: k.unit_group()
1317
Unit group with structure C6 x Z of Number Field in a with defining polynomial x^4 - x^3 - 21*x^2 + 17*x + 133
1318
sage: I = k.ideal(3)
1319
sage: U = units_mod_ideal(I)
1320
sage: all([U[j].is_unit() and not (U[j] in I) for j in range(len(U))])
1321
True
1322
"""
1323
k = I.number_field()
1324
Uk = k.unit_group()
1325
Istar = I.idealstar(2)
1326
ulist = Uk.gens()
1327
elist = [Istar(I.ideallog(u)).order() for u in ulist]
1328
1329
from sage.misc.mrange import xmrange
1330
from sage.misc.misc import prod
1331
1332
return [prod([u**e for u,e in zip(ulist,ei)],k(1)) for ei in xmrange(elist)]
1333
1334