This repository has been archived by the owner on Jan 30, 2023. It is now read-only.
/
number_field_ideal.py
3342 lines (2700 loc) · 111 KB
/
number_field_ideal.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""
Number Field Ideals
AUTHORS:
- Steven Sivek (2005-05-16)
- William Stein (2007-09-06): vastly improved the doctesting
- William Stein and John Cremona (2007-01-28): new class
NumberFieldFractionalIdeal now used for all except the 0 ideal
- Radoslav Kirov and Alyson Deines (2010-06-22):
prime_to_S_part, is_S_unit, is_S_integral
We test that pickling works::
sage: K.<a> = NumberField(x^2 - 5)
sage: I = K.ideal(2/(5+a))
sage: I == loads(dumps(I))
True
"""
#*****************************************************************************
# Copyright (C) 2004 William Stein <wstein@gmail.com>
#
# Distributed under the terms of the GNU General Public License (GPL)
#
# This code is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# The full text of the GPL is available at:
#
# http://www.gnu.org/licenses/
#*****************************************************************************
SMALL_DISC = 1000000
import sage.libs.all
import sage.misc.latex as latex
import sage.rings.rational_field as rational_field
import sage.rings.integer_ring as integer_ring
import sage.rings.arith as arith
import sage.misc.misc as misc
from sage.rings.finite_rings.constructor import FiniteField
import number_field
from sage.rings.ideal import (Ideal_generic, Ideal_fractional)
from sage.misc.all import prod
from sage.misc.mrange import xmrange_iter
from sage.misc.cachefunc import cached_method
from sage.structure.element import generic_power
from sage.structure.factorization import Factorization
from sage.structure.sequence import Sequence
from sage.structure.proof.proof import get_flag
QQ = rational_field.RationalField()
ZZ = integer_ring.IntegerRing()
def convert_from_idealprimedec_form(field, ideal):
"""
Used internally in the number field ideal implementation for
converting from the form output by the PARI function ``idealprimedec``
to a Sage ideal.
INPUT:
- ``field`` - a number field
- ``ideal`` - a PARI prime ideal, as output by the
``idealprimedec`` or ``idealfactor`` functions
EXAMPLE::
sage: from sage.rings.number_field.number_field_ideal import convert_from_idealprimedec_form
sage: K.<a> = NumberField(x^2 + 3)
sage: K_bnf = gp(K.pari_bnf())
sage: ideal = K_bnf.idealprimedec(3)[1]
sage: convert_from_idealprimedec_form(K, ideal)
doctest:...: DeprecationWarning: convert_from_idealprimedec_form() is deprecated
See http://trac.sagemath.org/15767 for details.
Fractional ideal (-a)
sage: K.factor(3)
(Fractional ideal (-a))^2
"""
from sage.misc.superseded import deprecation
deprecation(15767, "convert_from_idealprimedec_form() is deprecated")
p = ZZ(ideal[1])
alpha = field(field.pari_zk() * ideal[2])
return field.ideal(p, alpha)
def convert_to_idealprimedec_form(field, ideal):
"""
Used internally in the number field ideal implementation for
converting to the form output by the pari function ``idealprimedec``
from a Sage ideal.
INPUT:
- ``field`` - a number field
- ``ideal`` - a prime ideal
NOTE:
The algorithm implemented right now is not optimal, but works. It should
eventually be replaced with something better.
EXAMPLE::
sage: from sage.rings.number_field.number_field_ideal import convert_to_idealprimedec_form
sage: K.<a> = NumberField(x^2 + 3)
sage: P = K.ideal(a/2-3/2)
sage: convert_to_idealprimedec_form(K, P)
doctest:...: DeprecationWarning: convert_to_idealprimedec_form() is deprecated, use ideal.pari_prime() instead
See http://trac.sagemath.org/15767 for details.
[3, [1, 2]~, 2, 1, [1, 1; -1, 2]]
"""
from sage.misc.superseded import deprecation
deprecation(15767, "convert_to_idealprimedec_form() is deprecated, use ideal.pari_prime() instead")
return field.ideal(ideal).pari_prime()
class NumberFieldIdeal(Ideal_generic):
"""
An ideal of a number field.
"""
def __init__(self, field, gens, coerce=True):
"""
INPUT:
- ``field`` - a number field
- ``x`` - a list of NumberFieldElements belonging to the field
EXAMPLES::
sage: K.<i> = NumberField(x^2 + 1)
sage: K.ideal(7)
Fractional ideal (7)
Initialization from PARI::
sage: K.ideal(pari(7))
Fractional ideal (7)
sage: K.ideal(pari(4), pari(4 + 2*i))
Fractional ideal (2)
sage: K.ideal(pari("i + 2"))
Fractional ideal (i + 2)
sage: K.ideal(pari("[3,0;0,3]"))
Fractional ideal (3)
sage: F = pari(K).idealprimedec(5)
sage: K.ideal(F[0])
Fractional ideal (2*i + 1)
TESTS:
Check that _pari_prime is set when initializing from a PARI
prime ideal::
sage: K.ideal(pari(K).idealprimedec(5)[0])._pari_prime
[5, [-2, 1]~, 1, 1, [2, -1; 1, 2]]
"""
if not isinstance(field, number_field.NumberField_generic):
raise TypeError("field (=%s) must be a number field."%field)
if len(gens) == 1 and isinstance(gens[0], (list, tuple)):
gens = gens[0]
from sage.libs.pari.all import pari_gen
if len(gens) == 1 and isinstance(gens[0], pari_gen):
# Init from PARI
gens = gens[0]
if gens.type() == "t_MAT":
# Assume columns are generators
gens = [field(_) for _ in field.pari_zk() * gens]
elif gens.type() == "t_VEC":
# Assume prime ideal form
self._pari_prime = gens
gens = [ZZ(gens.pr_get_p()), field(gens.pr_get_gen())]
else:
# Assume one element of the field
gens = [field(gens)]
if len(gens)==0:
raise ValueError("gens must have length at least 1 (zero ideal is not a fractional ideal)")
Ideal_generic.__init__(self, field, gens, coerce)
def __hash__(self):
"""
EXAMPLES::
sage: NumberField(x^2 + 1, 'a').ideal(7).__hash__()
848642427 # 32-bit
3643975048496365947 # 64-bit
"""
try:
return self._hash
except AttributeError:
# At some point in the future (e.g., for relative extensions),
# we'll likely have to consider other hashes.
self._hash = self.pari_hnf().__hash__()
return self._hash
def _latex_(self):
r"""
EXAMPLES::
sage: K.<a> = NumberField(x^2 + 23)
sage: K.ideal([2, 1/2*a - 1/2])._latex_()
'\\left(2, \\frac{1}{2} a - \\frac{1}{2}\\right)'
sage: latex(K.ideal([2, 1/2*a - 1/2]))
\left(2, \frac{1}{2} a - \frac{1}{2}\right)
The gens are reduced only if the norm of the discriminant of
the defining polynomial is at most
sage.rings.number_field.number_field_ideal.SMALL_DISC::
sage: K.<a> = NumberField(x^2 + 902384092834); K
Number Field in a with defining polynomial x^2 + 902384092834
sage: I = K.factor(19)[0][0]; I._latex_()
'\\left(19\\right)'
We can make the generators reduced by increasing SMALL_DISC.
We had better also set proof to False, or computing reduced
gens could take too long::
sage: proof.number_field(False)
sage: sage.rings.number_field.number_field_ideal.SMALL_DISC = 10^20
sage: K.<a> = NumberField(x^4 + 3*x^2 - 17)
sage: K.ideal([17*a,17,17,17*a])._latex_()
'\\left(17\\right)'
TESTS:
Reset SMALL_DISC for continued testing::
sage: sage.rings.number_field.number_field_ideal.SMALL_DISC = 1000000
"""
return '\\left(%s\\right)'%(", ".join(map(latex.latex, self._gens_repr())))
def __cmp__(self, other):
"""
Compare an ideal of a number field to something else.
REMARK:
By default, comparing ideals is the same as comparing
their generator list. But of course, different generators
can give rise to the same ideal. And this can easily
be detected using Hermite normal form.
Unfortunately, there is a difference between "cmp" and
"==": In the first case, this method is directly called.
In the second case, it is only called *after coercion*.
However, we ensure that "cmp(I,J)==0" and "I==J" will
always give the same answer for number field ideals.
EXAMPLES::
sage: K.<a> = NumberField(x^2 + 3); K
Number Field in a with defining polynomial x^2 + 3
sage: f = K.factor(15); f
(Fractional ideal (-a))^2 * (Fractional ideal (5))
sage: cmp(f[0][0], f[1][0])
-1
sage: cmp(f[0][0], f[0][0])
0
sage: cmp(f[1][0], f[0][0])
1
sage: f[1][0] == 5
True
sage: f[1][0] == GF(7)(5)
False
TESTS::
sage: L.<b> = NumberField(x^8-x^4+1)
sage: F_2 = L.fractional_ideal(b^2-1)
sage: F_4 = L.fractional_ideal(b^4-1)
sage: F_2 == F_4
True
"""
if not isinstance(other, NumberFieldIdeal):
# this can only occur with cmp(,)
return cmp(type(self), type(other))
if self.parent()!=other.parent():
# again, this can only occur if cmp(,) is called
if self==other:
return 0
return (cmp(self.pari_hnf(), other.pari_hnf()) or
cmp(self.parent(),other.parent()))
# We can now assume that both have the same parent,
# even if originally cmp(,) was called.
return cmp(self.pari_hnf(), other.pari_hnf())
def _mul_(self, other):
"""
Returns the product of self and other.
This is implemented by just calling pari to do the multiplication.
EXAMPLES::
sage: K.<I>=QQ[i]
sage: A = K.ideal([5, 2 + I])
sage: B = K.ideal([13, 5 + 12*I])
sage: A*B
Fractional ideal (4*I - 7)
sage: (K.ideal(3 + I) * K.ideal(7 + I)).gens()
(10*I + 20,)
TESTS:
Make sure that :trac:`13958` is fixed::
sage: I = QuadraticField(-5).ideal(2).factor()[0][0]
sage: I = I * I * I; I.ngens() == 2
True
sage: I = I^301; I.ngens() == 2
True
"""
if self.ngens() == 1 and other.ngens() == 1:
return self.ring().ideal(self.gen(0) * other.gen(0))
K=self.ring()
K_pari=K.pari_nf()
return K.ideal(K_pari.idealmul(self._pari_(), other._pari_()))
def coordinates(self, x):
r"""
Returns the coordinate vector of `x` with respect to this ideal.
INPUT:
``x`` -- an element of the number field (or ring of integers) of this ideal.
OUTPUT:
List giving the coordinates of `x` with respect to the integral basis
of the ideal. In general this will be a vector of
rationals; it will consist of integers if and only if `x`
is in the ideal.
AUTHOR: John Cremona 2008-10-31
ALGORITHM:
Uses linear algebra.
Provides simpler implementations for ``_contains_()``,
``is_integral()`` and ``smallest_integer()``.
EXAMPLES::
sage: K.<i> = QuadraticField(-1)
sage: I = K.ideal(7+3*i)
sage: Ibasis = I.integral_basis(); Ibasis
[58, i + 41]
sage: a = 23-14*i
sage: acoords = I.coordinates(a); acoords
(597/58, -14)
sage: sum([Ibasis[j]*acoords[j] for j in range(2)]) == a
True
sage: b = 123+456*i
sage: bcoords = I.coordinates(b); bcoords
(-18573/58, 456)
sage: sum([Ibasis[j]*bcoords[j] for j in range(2)]) == b
True
sage: J = K.ideal(0)
sage: J.coordinates(0)
()
sage: J.coordinates(1)
Traceback (most recent call last):
...
TypeError: vector is not in free module
"""
K = self.number_field()
V, from_V, to_V = K.absolute_vector_space()
try:
return self.free_module().coordinate_vector(to_V(K(x)))
except ArithmeticError as e:
raise TypeError(e)
def _contains_(self, x):
"""
Return True if x is an element of this ideal.
This function is called (indirectly) when the ``in`` operator is used.
EXAMPLES::
sage: K.<a> = NumberField(x^2 + 23); K
Number Field in a with defining polynomial x^2 + 23
sage: I = K.factor(13)[0][0]; I
Fractional ideal (13, 1/2*a + 9/2)
sage: I._contains_(a)
False
sage: a in I
False
sage: 13 in I
True
sage: 13/2 in I
False
sage: a + 9 in I
True
sage: J = K.ideal(0)
sage: 0 in J
True
sage: 1 in J
False
sage: K.<a> = NumberField(x^4 + 3); K
Number Field in a with defining polynomial x^4 + 3
sage: I = K.factor(13)[0][0]
sage: I # random sign in output
Fractional ideal (-2*a^2 - 1)
sage: 2/3 in I
False
sage: 1 in I
False
sage: 13 in I
True
sage: 1 in I*I^(-1)
True
sage: I # random sign in output
Fractional ideal (-2*a^2 - 1)
sage: K.<y>=NumberField(x^2-3)
sage: L.<z>=K.extension(x^2-5)
sage: 0 in L.ideal(0)
True
sage: 1 in L.ideal(0)
False
"""
return self.coordinates(x).denominator() == 1
def __elements_from_hnf(self, hnf):
"""
Convert a PARI Hermite normal form matrix to a list of
NumberFieldElements.
EXAMPLES::
sage: K.<a> = NumberField(x^3 + 389); K
Number Field in a with defining polynomial x^3 + 389
sage: I = K.factor(17)[0][0]
sage: I # random sign in generator
Fractional ideal (-100*a^2 + 730*a - 5329)
sage: hnf = I.pari_hnf(); hnf
[17, 0, 13; 0, 17, 8; 0, 0, 1]
sage: I._NumberFieldIdeal__elements_from_hnf(hnf)
[17, 17*a, a^2 + 8*a + 13]
sage: I._NumberFieldIdeal__elements_from_hnf(hnf^(-1))
[1/17, 1/17*a, a^2 - 8/17*a - 13/17]
"""
K = self.number_field()
return [K(_) for _ in K.pari_zk() * hnf]
def __repr__(self):
"""
Return the string representation of this number field ideal.
.. note::
Only the zero ideal actually has type NumberFieldIdeal; all
others have type NumberFieldFractionalIdeal. So this function
will only ever be called on the zero ideal.
EXAMPLES::
sage: K.<a> = NumberField(x^3-2)
sage: I = K.ideal(0); I
Ideal (0) of Number Field in a with defining polynomial x^3 - 2
sage: type(I)
<class 'sage.rings.number_field.number_field_ideal.NumberFieldIdeal'>
sage: I = K.ideal(1); I
Fractional ideal (1)
sage: type(I)
<class 'sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal'>
sage: I = K.ideal(a); I
Fractional ideal (a)
sage: type(I)
<class 'sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal'>
sage: I = K.ideal(1/a); I
Fractional ideal (1/2*a^2)
sage: type(I)
<class 'sage.rings.number_field.number_field_ideal.NumberFieldFractionalIdeal'>
"""
return "Ideal %s of %s"%(self._repr_short(), self.number_field())
def _repr_short(self):
"""
Compact string representation of this ideal. When the norm of
the discriminant of the defining polynomial of the number field
is less than
sage.rings.number_field.number_field_ideal.SMALL_DISC
then display reduced generators. Otherwise display two
generators.
EXAMPLES::
sage: K.<a> = NumberField(x^4 + 389); K
Number Field in a with defining polynomial x^4 + 389
sage: I = K.factor(17)[0][0]; I
Fractional ideal (17, a^2 + 6)
sage: I._repr_short()
'(17, a^2 + 6)'
We use reduced gens, because the discriminant is small::
sage: K.<a> = NumberField(x^2 + 17); K
Number Field in a with defining polynomial x^2 + 17
sage: I = K.factor(17)[0][0]; I
Fractional ideal (a)
Here the discriminant is 'large', so the gens aren't reduced::
sage: sage.rings.number_field.number_field_ideal.SMALL_DISC
1000000
sage: K.<a> = NumberField(x^2 + 902384094); K
Number Field in a with defining polynomial x^2 + 902384094
sage: I = K.factor(19)[0][0]; I
Fractional ideal (19, a + 5)
sage: I.gens_reduced()
(19, a + 5)
"""
return '(%s)'%(', '.join(map(str, self._gens_repr())))
def _gens_repr(self):
"""
Returns tuple of generators to be used for printing this number
field ideal. The gens are reduced only if the absolute value of
the norm of the discriminant of the defining polynomial is at
most sage.rings.number_field.number_field_ideal.SMALL_DISC.
EXAMPLES::
sage: sage.rings.number_field.number_field_ideal.SMALL_DISC
1000000
sage: K.<a> = NumberField(x^4 + 3*x^2 - 17)
sage: K.discriminant() # too big
-1612688
sage: I = K.ideal([17*a*(2*a-2),17*a*(2*a-3)]); I._gens_repr()
(289, 17*a)
sage: I.gens_reduced()
(17*a,)
"""
# If the discriminant is small, it is easy to find nice gens.
# Otherwise it is potentially very hard.
try:
if abs(self.number_field().defining_polynomial().discriminant().norm()) <= SMALL_DISC:
return self.gens_reduced()
except TypeError:
# In some cases with relative extensions, computing the
# discriminant of the defining polynomial is not
# supported.
pass
# Return two generators unless the second one is zero
two_gens = self.gens_two()
if two_gens[1]:
return two_gens
else:
return (two_gens[0],)
def _pari_(self):
"""
Returns PARI Hermite Normal Form representations of this
ideal.
EXAMPLES::
sage: K.<w> = NumberField(x^2 + 23)
sage: I = K.class_group().0.ideal(); I
Fractional ideal (2, 1/2*w - 1/2)
sage: I._pari_()
[2, 0; 0, 1]
"""
return self.pari_hnf()
def _pari_init_(self):
"""
Returns self in PARI Hermite Normal Form as a string
EXAMPLES::
sage: K.<w> = NumberField(x^2 + 23)
sage: I = K.class_group().0.ideal()
sage: I._pari_init_()
'[2, 0; 0, 1]'
"""
return str(self._pari_())
def pari_hnf(self):
"""
Return PARI's representation of this ideal in Hermite normal form.
EXAMPLES::
sage: R.<x> = PolynomialRing(QQ)
sage: K.<a> = NumberField(x^3 - 2)
sage: I = K.ideal(2/(5+a))
sage: I.pari_hnf()
[2, 0, 50/127; 0, 2, 244/127; 0, 0, 2/127]
"""
try:
return self.__pari_hnf
except AttributeError:
nf = self.number_field().pari_nf()
self.__pari_hnf = nf.idealhnf(0)
hnflist = [ nf.idealhnf(x) for x in self.gens() ]
for ideal in hnflist:
self.__pari_hnf = nf.idealadd(self.__pari_hnf, ideal)
return self.__pari_hnf
@cached_method
def basis(self):
r"""
Return an immutable sequence of elements of this ideal (note:
their parent is the number field) that form a basis for this
ideal viewed as a `\ZZ` -module.
OUTPUT:
basis -- an immutable sequence.
EXAMPLES::
sage: K.<z> = CyclotomicField(7)
sage: I = K.factor(11)[0][0]
sage: I.basis() # warning -- choice of basis can be somewhat random
[11, 11*z, 11*z^2, z^3 + 5*z^2 + 4*z + 10, z^4 + z^2 + z + 5, z^5 + z^4 + z^3 + 2*z^2 + 6*z + 5]
An example of a non-integral ideal.::
sage: J = 1/I
sage: J # warning -- choice of generators can be somewhat random
Fractional ideal (2/11*z^5 + 2/11*z^4 + 3/11*z^3 + 2/11)
sage: J.basis() # warning -- choice of basis can be somewhat random
[1, z, z^2, 1/11*z^3 + 7/11*z^2 + 6/11*z + 10/11, 1/11*z^4 + 1/11*z^2 + 1/11*z + 7/11, 1/11*z^5 + 1/11*z^4 + 1/11*z^3 + 2/11*z^2 + 8/11*z + 7/11]
"""
hnf = self.pari_hnf()
v = self.__elements_from_hnf(hnf)
O = self.number_field().maximal_order()
return Sequence(v, immutable=True)
@cached_method
def free_module(self):
r"""
Return the free `\ZZ`-module contained in the vector space
associated to the ambient number field, that corresponds
to this ideal.
EXAMPLES::
sage: K.<z> = CyclotomicField(7)
sage: I = K.factor(11)[0][0]; I
Fractional ideal (-2*z^4 - 2*z^2 - 2*z + 1)
sage: A = I.free_module()
sage: A # warning -- choice of basis can be somewhat random
Free module of degree 6 and rank 6 over Integer Ring
User basis matrix:
[11 0 0 0 0 0]
[ 0 11 0 0 0 0]
[ 0 0 11 0 0 0]
[10 4 5 1 0 0]
[ 5 1 1 0 1 0]
[ 5 6 2 1 1 1]
However, the actual `\ZZ`-module is not at all random::
sage: A.basis_matrix().change_ring(ZZ).echelon_form()
[ 1 0 0 5 1 1]
[ 0 1 0 1 1 7]
[ 0 0 1 7 6 10]
[ 0 0 0 11 0 0]
[ 0 0 0 0 11 0]
[ 0 0 0 0 0 11]
The ideal doesn't have to be integral::
sage: J = I^(-1)
sage: B = J.free_module()
sage: B.echelonized_basis_matrix()
[ 1/11 0 0 7/11 1/11 1/11]
[ 0 1/11 0 1/11 1/11 5/11]
[ 0 0 1/11 5/11 4/11 10/11]
[ 0 0 0 1 0 0]
[ 0 0 0 0 1 0]
[ 0 0 0 0 0 1]
This also works for relative extensions::
sage: K.<a,b> = NumberField([x^2 + 1, x^2 + 2])
sage: I = K.fractional_ideal(4)
sage: I.free_module()
Free module of degree 4 and rank 4 over Integer Ring
User basis matrix:
[ 4 0 0 0]
[ -3 7 -1 1]
[ 3 7 1 1]
[ 0 -10 0 -2]
sage: J = I^(-1); J.free_module()
Free module of degree 4 and rank 4 over Integer Ring
User basis matrix:
[ 1/4 0 0 0]
[-3/16 7/16 -1/16 1/16]
[ 3/16 7/16 1/16 1/16]
[ 0 -5/8 0 -1/8]
An example of intersecting ideals by intersecting free modules.::
sage: K.<a> = NumberField(x^3 + x^2 - 2*x + 8)
sage: I = K.factor(2)
sage: p1 = I[0][0]; p2 = I[1][0]
sage: N = p1.free_module().intersection(p2.free_module()); N
Free module of degree 3 and rank 3 over Integer Ring
Echelon basis matrix:
[ 1 1/2 1/2]
[ 0 1 1]
[ 0 0 2]
sage: N.index_in(p1.free_module()).abs()
2
TESTS:
Sage can find the free module associated to quite large ideals
quickly (see trac #4627)::
sage: y = polygen(ZZ)
sage: M.<a> = NumberField(y^20 - 2*y^19 + 10*y^17 - 15*y^16 + 40*y^14 - 64*y^13 + 46*y^12 + 8*y^11 - 32*y^10 + 8*y^9 + 46*y^8 - 64*y^7 + 40*y^6 - 15*y^4 + 10*y^3 - 2*y + 1)
sage: M.ideal(prod(prime_range(6000, 6200))).free_module()
Free module of degree 20 and rank 20 over Integer Ring
User basis matrix:
20 x 20 dense matrix over Rational Field
"""
return basis_to_module(self.basis(), self.number_field())
def reduce_equiv(self):
"""
Return a small ideal that is equivalent to self in the group
of fractional ideals modulo principal ideals. Very often (but
not always) if self is principal then this function returns
the unit ideal.
ALGORITHM: Calls pari's idealred function.
EXAMPLES::
sage: K.<w> = NumberField(x^2 + 23)
sage: I = ideal(w*23^5); I
Fractional ideal (6436343*w)
sage: I.reduce_equiv()
Fractional ideal (1)
sage: I = K.class_group().0.ideal()^10; I
Fractional ideal (1024, 1/2*w + 979/2)
sage: I.reduce_equiv()
Fractional ideal (2, 1/2*w - 1/2)
"""
K = self.number_field()
P = K.pari_nf()
hnf = P.idealred(self.pari_hnf())
gens = self.__elements_from_hnf(hnf)
return K.ideal(gens)
def gens_reduced(self, proof=None):
r"""
Express this ideal in terms of at most two generators, and one
if possible.
This function indirectly uses ``bnfisprincipal``, so set
``proof=True`` if you want to prove correctness (which *is* the
default).
EXAMPLES::
sage: R.<x> = PolynomialRing(QQ)
sage: K.<a> = NumberField(x^2 + 5)
sage: K.ideal(0).gens_reduced()
(0,)
sage: J = K.ideal([a+2, 9])
sage: J.gens()
(a + 2, 9)
sage: J.gens_reduced() # random sign
(a + 2,)
sage: K.ideal([a+2, 3]).gens_reduced()
(3, a + 2)
TESTS::
sage: len(J.gens_reduced()) == 1
True
sage: all(j.parent() is K for j in J.gens())
True
sage: all(j.parent() is K for j in J.gens_reduced())
True
sage: K.<a> = NumberField(x^4 + 10*x^2 + 20)
sage: J = K.prime_above(5)
sage: J.is_principal()
False
sage: J.gens_reduced()
(5, a)
sage: all(j.parent() is K for j in J.gens())
True
sage: all(j.parent() is K for j in J.gens_reduced())
True
Make sure this works with large ideals (#11836)::
sage: R.<x> = QQ['x']
sage: L.<b> = NumberField(x^10 - 10*x^8 - 20*x^7 + 165*x^6 - 12*x^5 - 760*x^3 + 2220*x^2 + 5280*x + 7744)
sage: z_x = -96698852571685/2145672615243325696*b^9 + 2472249905907/195061146840302336*b^8 + 916693155514421/2145672615243325696*b^7 + 1348520950997779/2145672615243325696*b^6 - 82344497086595/12191321677518896*b^5 + 2627122040194919/536418153810831424*b^4 - 452199105143745/48765286710075584*b^3 + 4317002771457621/536418153810831424*b^2 + 2050725777454935/67052269226353928*b + 3711967683469209/3047830419379724
sage: P = EllipticCurve(L, '57a1').lift_x(z_x) * 3
sage: ideal = L.fractional_ideal(P[0], P[1])
sage: ideal.is_principal(proof=False)
*** Warning: precision too low for generators, not given.
True
sage: len(ideal.gens_reduced(proof=False))
1
"""
if len(self.gens()) <= 1:
self._is_principal = True
self._reduced_generators = self.gens()
return self._reduced_generators
self._cache_bnfisprincipal(proof=proof, gens_needed=True)
return self._reduced_generators
def gens_two(self):
r"""
Express this ideal using exactly two generators, the first of
which is a generator for the intersection of the ideal with `Q`.
ALGORITHM: uses PARI's ``idealtwoelt`` function, which runs in
randomized polynomial time and is very fast in practice.
EXAMPLES::
sage: R.<x> = PolynomialRing(QQ)
sage: K.<a> = NumberField(x^2 + 5)
sage: J = K.ideal([a+2, 9])
sage: J.gens()
(a + 2, 9)
sage: J.gens_two()
(9, a + 2)
sage: K.ideal([a+5, a+8]).gens_two()
(3, a + 2)
sage: K.ideal(0).gens_two()
(0, 0)
The second generator is zero if and only if the ideal is
generated by a rational, in contrast to the PARI function
``idealtwoelt()``::
sage: I = K.ideal(12)
sage: pari(K).idealtwoelt(I) # Note that second element is not zero
[12, [0, 12]~]
sage: I.gens_two()
(12, 0)
"""
try:
return self.__two_generators
except AttributeError:
if self.is_zero():
self.__two_generators = (0,0)
return self.__two_generators
K = self.number_field()
HNF = self.pari_hnf()
# Check whether the ideal is generated by an integer, i.e.
# whether HNF is a multiple of the identity matrix
if HNF.gequal(HNF[0,0]):
a = HNF[0,0]; alpha = 0
else:
a, alpha = K.pari_nf().idealtwoelt(HNF)
self.__two_generators = (K(a), K(alpha))
return self.__two_generators
def integral_basis(self):
r"""
Return a list of generators for this ideal as a `\ZZ`-module.
EXAMPLES::
sage: R.<x> = PolynomialRing(QQ)
sage: K.<i> = NumberField(x^2 + 1)
sage: J = K.ideal(i+1)
sage: J.integral_basis()
[2, i + 1]
"""
hnf = self.pari_hnf()
return self.__elements_from_hnf(hnf)
def integral_split(self):
r"""
Return a tuple `(I, d)`, where `I` is an integral ideal, and `d` is the
smallest positive integer such that this ideal is equal to `I/d`.
EXAMPLES::
sage: R.<x> = PolynomialRing(QQ)
sage: K.<a> = NumberField(x^2-5)
sage: I = K.ideal(2/(5+a))
sage: I.is_integral()
False
sage: J,d = I.integral_split()
sage: J
Fractional ideal (-1/2*a + 5/2)
sage: J.is_integral()
True
sage: d
5
sage: I == J/d
True
"""
try:
return self.__integral_split
except AttributeError:
if self.is_integral():
self.__integral_split = (self, ZZ(1))
else:
factors = self.factor()
denom_list = [p_e for p_e in factors if p_e[1] < 0]
denominator = prod([ p.smallest_integer()**(-e)
for (p,e) in denom_list ])
## Get a list of the primes dividing the denominator
plist = [ p.smallest_integer() for (p,e) in denom_list ]
for p in plist:
while denominator % p == 0 and (self*(denominator/p)).is_integral():
denominator //= p
self.__integral_split = (self*denominator, denominator)
return self.__integral_split
def intersection(self, other):
r"""
Return the intersection of self and other.
EXAMPLE::
sage: K.<a> = QuadraticField(-11)
sage: p = K.ideal((a + 1)/2); q = K.ideal((a + 3)/2)
sage: p.intersection(q) == q.intersection(p) == K.ideal(a-2)
True
An example with non-principal ideals::
sage: L.<a> = NumberField(x^3 - 7)
sage: p = L.ideal(a^2 + a + 1, 2)
sage: q = L.ideal(a+1)
sage: p.intersection(q) == L.ideal(8, 2*a + 2)
True
A relative example::
sage: L.<a,b> = NumberField([x^2 + 11, x^2 - 5])
sage: A = L.ideal([15, (-3/2*b + 7/2)*a - 8])
sage: B = L.ideal([6, (-1/2*b + 1)*a - b - 5/2])
sage: A.intersection(B) == L.ideal(-1/2*a - 3/2*b - 1)
True
TESTS:
Test that this works with non-integral ideals (#10767)::
sage: K = QuadraticField(-2)
sage: I = K.ideal(1/2)
sage: I.intersection(I)
Fractional ideal (1/2)
"""
L = self.number_field()
other = L.ideal(other)
nf = L.pari_nf()
hnf = nf.idealintersection(self.pari_hnf(), other.pari_hnf())
I = L.ideal(self._NumberFieldIdeal__elements_from_hnf(hnf))
I.__pari_hnf = hnf
return I
def is_integral(self):
"""
Return True if this ideal is integral.
EXAMPLES::
sage: R.<x> = PolynomialRing(QQ)
sage: K.<a> = NumberField(x^5-x+1)
sage: K.ideal(a).is_integral()
True
sage: (K.ideal(1) / (3*a+1)).is_integral()
False
"""
try:
return self.__is_integral
except AttributeError:
one = self.number_field().ideal(1)