Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/rings/finite_rings/finite_field_ext_pari.py
4128 views
1
"""
2
Finite Extension Fields implemented via PARI.
3
4
AUTHORS:
5
6
- William Stein: initial version
7
8
- Jeroen Demeyer (2010-12-16): fix formatting of docstrings (#10487)
9
"""
10
#*****************************************************************************
11
# Copyright (C) 2005,2007 William Stein <[email protected]>
12
# Copyright (C) 2010 Jeroen Demeyer <[email protected]>
13
#
14
# Distributed under the terms of the GNU General Public License (GPL)
15
# as published by the Free Software Foundation; either version 2 of
16
# the License, or (at your option) any later version.
17
# http://www.gnu.org/licenses/
18
#*****************************************************************************
19
20
21
import sage.rings.polynomial.polynomial_element as polynomial_element
22
import sage.rings.polynomial.multi_polynomial_element as multi_polynomial_element
23
24
import sage.rings.integer as integer
25
import sage.rings.rational as rational
26
27
import sage.libs.pari.all as pari
28
29
import element_ext_pari
30
31
from sage.rings.finite_rings.finite_field_base import FiniteField as FiniteField_generic
32
33
34
import sage.interfaces.gap
35
36
class FiniteField_ext_pari(FiniteField_generic):
37
r"""
38
Finite Field of order `q`, where `q` is a prime power (not a prime),
39
implemented using PARI ``POLMOD``s. This implementation is the default
40
implementation for `q \geq 2^{16}`.
41
42
INPUT:
43
44
- ``q`` -- int, prime power, order of the finite field
45
- ``name`` -- string (default: 'a'), string for printing the generator
46
47
OUTPUT:
48
49
- FiniteField_ext_pari -- finite field of order `q`.
50
51
EXAMPLES::
52
53
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
54
sage: k = FiniteField_ext_pari(9, 'a')
55
sage: k
56
Finite Field in a of size 3^2
57
sage: k.is_field()
58
True
59
sage: k.characteristic()
60
3
61
sage: a = k.gen()
62
sage: a
63
a
64
sage: a.parent()
65
Finite Field in a of size 3^2
66
sage: a.charpoly('x')
67
x^2 + 2*x + 2
68
sage: [a^i for i in range(8)]
69
[1, a, a + 1, 2*a + 1, 2, 2*a, 2*a + 2, a + 2]
70
71
Fields can be coerced into sets or list and iterated over::
72
73
sage: list(k)
74
[0, 1, 2, a, a + 1, a + 2, 2*a, 2*a + 1, 2*a + 2]
75
76
The following is a native Python set::
77
78
sage: set(k)
79
set([0, 1, 2, a, a + 1, a + 2, 2*a, 2*a + 1, 2*a + 2])
80
81
And the following is a Sage set::
82
83
sage: Set(k)
84
{0, 1, 2, a, a + 1, a + 2, 2*a, 2*a + 1, 2*a + 2}
85
86
We can also make a list via comprehension:
87
sage: [x for x in k]
88
[0, 1, 2, a, a + 1, a + 2, 2*a, 2*a + 1, 2*a + 2]
89
90
Next we compute with the finite field of order 16, where
91
the name is named b::
92
93
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
94
sage: k16 = FiniteField_ext_pari(16, "b")
95
sage: z = k16.gen()
96
sage: z
97
b
98
sage: z.charpoly('x')
99
x^4 + x + 1
100
sage: k16.is_field()
101
True
102
sage: k16.characteristic()
103
2
104
sage: z.multiplicative_order()
105
15
106
107
Of course one can also make prime finite fields::
108
109
sage: k = FiniteField(7)
110
111
Note that the generator is 1::
112
113
sage: k.gen()
114
1
115
sage: k.gen().multiplicative_order()
116
1
117
118
Prime finite fields are implemented elsewhere, they cannot be
119
constructed using ``FiniteField_ext_pari``::
120
121
sage: k = FiniteField_ext_pari(7, 'a')
122
Traceback (most recent call last):
123
...
124
ValueError: The size of the finite field must not be prime.
125
126
Illustration of dumping and loading::
127
128
sage: K = FiniteField(7)
129
sage: loads(K.dumps()) == K
130
True
131
sage: K = FiniteField(7^10, 'b')
132
sage: loads(K.dumps()) == K
133
True
134
sage: K = FiniteField(7^10, 'a')
135
sage: loads(K.dumps()) == K
136
True
137
138
In this example `K` is large enough that Conway polynomials are not
139
used. Note that when the field is dumped the defining polynomial `f`
140
is also dumped. Since `f` is determined by a random algorithm, it's
141
important that `f` is dumped as part of `K`. If you quit Sage and
142
restart and remake a finite field of the same order (and the order is
143
large enough so that there is no Conway polynomial), then defining
144
polynomial is probably different. However, if you load a previously
145
saved field, that will have the same defining polynomial. ::
146
147
sage: K = GF(10007^10, 'a')
148
sage: loads(K.dumps()) == K
149
True
150
151
.. NOTE::
152
153
We do NOT yet define natural consistent inclusion maps
154
between different finite fields.
155
"""
156
def __init__(self, q, name, modulus=None):
157
"""
158
Create finite field of order q with variable printed as name.
159
160
INPUT:
161
162
- ``q`` -- integer, size of the finite field, not prime
163
- ``name`` -- variable used for printing element of the finite
164
field. Also, two finite fields are considered
165
equal if they have the same variable name, and not
166
otherwise.
167
- ``modulus`` -- you may provide a polynomial to use for reduction or
168
a string:
169
'conway': force the use of a Conway polynomial, will
170
raise a RuntimeError if none is found in the database;
171
'random': use a random irreducible polynomial.
172
'default': a Conway polynomial is used if found. Otherwise
173
a random polynomial is used.
174
175
OUTPUT:
176
177
- FiniteField_ext_pari -- a finite field of order q with given variable name.
178
179
EXAMPLES::
180
181
sage: FiniteField(65537)
182
Finite Field of size 65537
183
sage: FiniteField(2^20, 'c')
184
Finite Field in c of size 2^20
185
sage: FiniteField(3^11, "b")
186
Finite Field in b of size 3^11
187
sage: FiniteField(3^11, "b").gen()
188
b
189
190
You can also create a finite field using GF, which is a synonym
191
for FiniteField. ::
192
193
sage: GF(19^5, 'a')
194
Finite Field in a of size 19^5
195
"""
196
if element_ext_pari.dynamic_FiniteField_ext_pariElement is None: element_ext_pari._late_import()
197
from constructor import FiniteField as GF
198
q = integer.Integer(q)
199
if q < 2:
200
raise ArithmeticError, "q must be a prime power"
201
from sage.structure.proof.all import arithmetic
202
proof = arithmetic()
203
if proof:
204
F = q.factor()
205
else:
206
from sage.rings.arith import is_pseudoprime_small_power
207
F = is_pseudoprime_small_power(q, get_data=True)
208
if len(F) != 1:
209
raise ArithmeticError, "q must be a prime power"
210
211
if F[0][1] > 1:
212
base_ring = GF(F[0][0])
213
else:
214
raise ValueError, "The size of the finite field must not be prime."
215
#base_ring = self
216
217
FiniteField_generic.__init__(self, base_ring, name, normalize=True)
218
219
self._kwargs = {}
220
self.__char = F[0][0]
221
self.__pari_one = pari.pari(1).Mod(self.__char)
222
self.__degree = integer.Integer(F[0][1])
223
self.__order = q
224
self.__is_field = True
225
226
if modulus is None or modulus == "default":
227
from constructor import exists_conway_polynomial
228
if exists_conway_polynomial(self.__char, self.__degree):
229
modulus = "conway"
230
else:
231
modulus = "random"
232
233
if isinstance(modulus,str):
234
if modulus == "conway":
235
from constructor import conway_polynomial
236
modulus = conway_polynomial(self.__char, self.__degree)
237
elif modulus == "random":
238
# The following is fast/deterministic, but has serious problems since
239
# it crashes on 64-bit machines, and I can't figure out why:
240
# self.__pari_modulus = pari.pari.finitefield_init(self.__char, self.__degree, self.variable_name())
241
# So instead we iterate through random polys until we find an irreducible one.
242
243
R = GF(self.__char)['x']
244
while True:
245
modulus = R.random_element(self.__degree)
246
modulus = modulus.monic()
247
if modulus.degree() == self.__degree and modulus.is_irreducible():
248
break
249
else:
250
raise ValueError("Modulus parameter not understood")
251
252
elif isinstance(modulus, (list, tuple)):
253
modulus = GF(self.__char)['x'](modulus)
254
elif sage.rings.polynomial.polynomial_element.is_Polynomial(modulus):
255
if modulus.parent() is not base_ring:
256
modulus = modulus.change_ring(base_ring)
257
else:
258
raise ValueError("Modulus parameter not understood")
259
260
self.__modulus = modulus
261
f = pari.pari(str(modulus))
262
self.__pari_modulus = f.subst(modulus.parent().variable_name(), 'a') * self.__pari_one
263
self.__gen = element_ext_pari.FiniteField_ext_pariElement(self, pari.pari('a'))
264
265
self._zero_element = self._element_constructor_(0)
266
self._one_element = self._element_constructor_(1)
267
268
def __reduce__(self):
269
"""
270
EXAMPLES::
271
272
sage: k.<b> = GF(5^20); type(k)
273
<class 'sage.rings.finite_rings.finite_field_ext_pari.FiniteField_ext_pari_with_category'>
274
sage: k is loads(dumps(k))
275
True
276
"""
277
return self._factory_data[0].reduce_data(self)
278
279
def __cmp__(self, other):
280
"""
281
EXAMPLES::
282
283
sage: k = GF(7^20,'a')
284
sage: k == loads(dumps(k))
285
True
286
"""
287
if not isinstance(other, FiniteField_ext_pari):
288
return cmp(type(self), type(other))
289
return cmp((self.__order, self.variable_name(), self.__modulus), (other.__order, other.variable_name(), other.__modulus))
290
291
def __richcmp__(left, right, op):
292
r"""
293
Compare ``left`` with ``right``.
294
295
EXAMPLE::
296
297
sage: k.<a> = GF(next_prime(2^17))
298
sage: j.<b> = GF(next_prime(2^18))
299
sage: k == j
300
False
301
302
sage: GF(next_prime(2^17),'a') == copy(GF(next_prime(2^17),'a'))
303
True
304
"""
305
return left._richcmp_helper(right, op)
306
307
def _pari_one(self):
308
r"""
309
The PARI object Mod(1,p). This is implementation specific
310
and should be ignored by users.
311
312
EXAMPLES::
313
314
sage: k = GF(7^20,'a')
315
sage: k._pari_one()
316
Mod(1, 7)
317
"""
318
return self.__pari_one
319
320
def _pari_modulus(self):
321
"""
322
The polynomial mod p that defines the finite field, as a PARI
323
object. This is implementation specific, and some finite fields
324
might not be implemented using PARI, so you should avoid using
325
this function.
326
327
OUTPUT:
328
329
- ``gen`` -- a PARI polynomial gen
330
331
EXAMPLES::
332
333
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
334
sage: FiniteField_ext_pari(19^2, 'a')._pari_modulus()
335
Mod(1, 19)*a^2 + Mod(18, 19)*a + Mod(2, 19)
336
337
sage: FiniteField_ext_pari(13^3, 'a')._pari_modulus()
338
Mod(1, 13)*a^3 + Mod(2, 13)*a + Mod(11, 13)
339
340
Note that the PARI modulus is always in terms of a, even if
341
the field variable isn't. This is because the specific choice
342
of variable name has meaning in PARI, i.e., it can't be
343
arbitrary. ::
344
345
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
346
sage: FiniteField_ext_pari(2^4, "b")._pari_modulus()
347
Mod(1, 2)*a^4 + Mod(1, 2)*a + Mod(1, 2)
348
"""
349
return self.__pari_modulus
350
351
def gen(self, n=0):
352
"""
353
Return a generator of the finite field. This generator
354
is a root of the defining polynomial of the finite field, and
355
might differ between different runs or different
356
architectures.
357
358
.. WARNING::
359
360
This generator is not guaranteed to be a generator
361
for the multiplicative group. To obtain the latter, use
362
multiplicative_generator().
363
364
INPUT:
365
366
- ``n`` -- ignored
367
368
OUTPUT:
369
370
- FiniteField_ext_pariElement -- field generator of finite field
371
372
EXAMPLES::
373
374
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
375
sage: FiniteField_ext_pari(2^4, "b").gen()
376
b
377
sage: k = FiniteField_ext_pari(3^4, "alpha")
378
sage: a = k.gen()
379
sage: a
380
alpha
381
sage: a^4
382
alpha^3 + 1
383
384
"""
385
return self.__gen
386
387
def characteristic(self):
388
"""
389
Returns the characteristic of the finite field, which is a
390
prime number.
391
392
EXAMPLES::
393
394
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
395
sage: k = FiniteField_ext_pari(3^4, 'a')
396
sage: k.characteristic()
397
3
398
"""
399
return self.__char
400
401
def modulus(self):
402
r"""
403
Return the minimal polynomial of the generator of self in
404
``self.polynomial_ring('x')``.
405
406
EXAMPLES::
407
408
sage: F.<a> = GF(7^20, 'a')
409
sage: f = F.modulus(); f
410
x^20 + x^12 + 6*x^11 + 2*x^10 + 5*x^9 + 2*x^8 + 3*x^7 + x^6 + 3*x^5 + 3*x^3 + x + 3
411
412
sage: f(a)
413
0
414
"""
415
return self.__modulus
416
417
def degree(self):
418
"""
419
Returns the degree of the finite field, which is a positive
420
integer.
421
422
EXAMPLES::
423
424
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
425
sage: FiniteField_ext_pari(3^20, 'a').degree()
426
20
427
"""
428
return self.__degree
429
430
def _element_constructor_(self, x):
431
r"""
432
Coerce x into the finite field.
433
434
INPUT:
435
436
- ``x`` -- object
437
438
OUTPUT:
439
440
- FiniteField_ext_pariElement -- if possible, makes a finite field element from x.
441
442
EXAMPLES::
443
444
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
445
sage: k = FiniteField_ext_pari(3^4, 'a')
446
sage: b = k(5) # indirect doctest
447
sage: b.parent()
448
Finite Field in a of size 3^4
449
sage: a = k.gen()
450
sage: k(a + 2)
451
a + 2
452
453
Univariate polynomials coerce into finite fields by evaluating
454
the polynomial at the field's generator::
455
456
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
457
sage: R.<x> = QQ[]
458
sage: k, a = FiniteField_ext_pari(5^2, 'a').objgen()
459
sage: k(R(2/3))
460
4
461
sage: k(x^2)
462
a + 3
463
sage: R.<x> = GF(5)[]
464
sage: k(x^3-2*x+1)
465
2*a + 4
466
467
sage: x = polygen(QQ)
468
sage: k(x^25)
469
a
470
471
sage: Q, q = FiniteField_ext_pari(5^7, 'q').objgen()
472
sage: L = GF(5)
473
sage: LL.<xx> = L[]
474
sage: Q(xx^2 + 2*xx + 4)
475
q^2 + 2*q + 4
476
477
Multivariate polynomials only coerce if constant::
478
479
sage: R = k['x,y,z']; R
480
Multivariate Polynomial Ring in x, y, z over Finite Field in a of size 5^2
481
sage: k(R(2))
482
2
483
sage: R = QQ['x,y,z']
484
sage: k(R(1/5))
485
Traceback (most recent call last):
486
...
487
TypeError: unable to coerce
488
489
Gap elements can also be coerced into finite fields::
490
491
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
492
sage: F = FiniteField_ext_pari(8, 'a')
493
sage: a = F.multiplicative_generator(); a
494
a
495
sage: b = gap(a^3); b
496
Z(2^3)^3
497
sage: F(b)
498
a + 1
499
sage: a^3
500
a + 1
501
502
sage: a = GF(13)(gap('0*Z(13)')); a
503
0
504
sage: a.parent()
505
Finite Field of size 13
506
507
sage: F = GF(16, 'a')
508
sage: F(gap('Z(16)^3'))
509
a^3
510
sage: F(gap('Z(16)^2'))
511
a^2
512
513
You can also call a finite extension field with a string
514
to produce an element of that field, like this::
515
516
sage: k = GF(2^8, 'a')
517
sage: k('a^200')
518
a^4 + a^3 + a^2
519
520
This is especially useful for fast conversions from Singular etc.
521
to FiniteField_ext_pariElements.
522
523
AUTHORS:
524
525
-- David Joyner (2005-11)
526
-- Martin Albrecht (2006-01-23)
527
-- Martin Albrecht (2006-03-06): added coercion from string
528
"""
529
if isinstance(x, element_ext_pari.FiniteField_ext_pariElement):
530
if x.parent() is self:
531
return x
532
elif x.parent() == self:
533
# canonically isomorphic finite fields
534
return element_ext_pari.FiniteField_ext_pariElement(self, x)
535
else:
536
# This is where we *would* do coercion from one finite field to another...
537
raise TypeError, "no coercion defined"
538
539
elif sage.interfaces.gap.is_GapElement(x):
540
from sage.interfaces.gap import gfq_gap_to_sage
541
try:
542
return gfq_gap_to_sage(x, self)
543
except (ValueError, IndexError, TypeError):
544
raise TypeError, "no coercion defined"
545
546
if isinstance(x, (int, long, integer.Integer, rational.Rational,
547
pari.pari_gen, list)):
548
549
return element_ext_pari.FiniteField_ext_pariElement(self, x)
550
551
elif isinstance(x, multi_polynomial_element.MPolynomial):
552
if x.is_constant():
553
return self(x.constant_coefficient())
554
else:
555
raise TypeError, "no coercion defined"
556
557
elif isinstance(x, polynomial_element.Polynomial):
558
if x.is_constant():
559
return self(x.constant_coefficient())
560
else:
561
return x.change_ring(self)(self.gen())
562
563
elif isinstance(x, str):
564
x = x.replace(self.variable_name(),'a')
565
x = pari.pari(x)
566
t = x.type()
567
if t == 't_POL':
568
if (x.variable() == 'a' \
569
and x.polcoeff(0).type()[2] == 'I'): #t_INT and t_INTMOD
570
return self(x)
571
if t[2] == 'I': #t_INT and t_INTMOD
572
return self(x)
573
raise TypeError, "string element does not match this finite field"
574
575
try:
576
if x.parent() == self.vector_space():
577
x = pari.pari('+'.join(['%s*a^%s'%(x[i], i) for i in range(self.degree())]))
578
return element_ext_pari.FiniteField_ext_pariElement(self, x)
579
except AttributeError:
580
pass
581
try:
582
return element_ext_pari.FiniteField_ext_pariElement(self, integer.Integer(x))
583
except TypeError, msg:
584
raise TypeError, "%s\nno coercion defined"%msg
585
586
def _coerce_map_from_(self, R):
587
r"""
588
Canonical coercion to ``self``.
589
590
EXAMPLES::
591
592
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
593
sage: FiniteField_ext_pari(4,'a')._coerce_(GF(2)(1)) # indirect doctest
594
1
595
sage: k = FiniteField_ext_pari(4,'a')
596
sage: k._coerce_(k.0)
597
a
598
sage: FiniteField_ext_pari(4,'a')._coerce_(3)
599
1
600
sage: FiniteField_ext_pari(4,'a')._coerce_(2/3)
601
Traceback (most recent call last):
602
...
603
TypeError: no canonical coercion from Rational Field to Finite Field in a of size 2^2
604
sage: FiniteField_ext_pari(8,'a')._coerce_(FiniteField_ext_pari(4,'a').0)
605
Traceback (most recent call last):
606
...
607
TypeError: no canonical coercion from Finite Field in a of size 2^2 to Finite Field in a of size 2^3
608
sage: FiniteField_ext_pari(16,'a')._coerce_(FiniteField_ext_pari(4,'a').0)
609
Traceback (most recent call last):
610
...
611
TypeError: no canonical coercion from Finite Field in a of size 2^2 to Finite Field in a of size 2^4
612
sage: k = FiniteField_ext_pari(8,'a')
613
sage: k._coerce_(FiniteField(7,'a')(2))
614
Traceback (most recent call last):
615
...
616
TypeError: no canonical coercion from Finite Field of size 7 to Finite Field in a of size 2^3
617
"""
618
from sage.rings.integer_ring import ZZ
619
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic
620
if R is int or R is long or R is ZZ:
621
return True
622
if isinstance(R, FiniteField_ext_pari):
623
if R is self:
624
return True
625
if R.characteristic() == self.characteristic():
626
if R.degree() == 1:
627
return True
628
elif self.degree() % R.degree() == 0:
629
# TODO: This is where we *would* do coercion from one nontrivial finite field to another...
630
return False
631
from sage.rings.residue_field import ResidueField_generic
632
if isinstance(R, IntegerModRing_generic) and R.characteristic() == self.characteristic() and not isinstance(R, ResidueField_generic):
633
return True
634
635
def __len__(self):
636
"""
637
The number of elements of the finite field.
638
639
EXAMPLES::
640
641
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
642
sage: k = FiniteField_ext_pari(2^10, 'a')
643
sage: k
644
Finite Field in a of size 2^10
645
sage: len(k)
646
1024
647
"""
648
return self.__order
649
650
def order(self):
651
"""
652
The number of elements of the finite field.
653
654
EXAMPLES::
655
656
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
657
sage: k = FiniteField_ext_pari(2^10,'a')
658
sage: k
659
Finite Field in a of size 2^10
660
sage: k.order()
661
1024
662
"""
663
return self.__order
664
665
def polynomial(self, name=None):
666
"""
667
Return the irreducible characteristic polynomial of the
668
generator of this finite field, i.e., the polynomial `f(x)` so
669
elements of the finite field as elements modulo `f`.
670
671
EXAMPLES::
672
673
sage: k = FiniteField(17)
674
sage: k.polynomial('x')
675
x
676
sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari
677
sage: k = FiniteField_ext_pari(9,'a')
678
sage: k.polynomial('x')
679
x^2 + 2*x + 2
680
"""
681
if name is None:
682
name = self.variable_name()
683
try:
684
return self.__polynomial[name]
685
except (AttributeError, KeyError):
686
from constructor import FiniteField as GF
687
R = GF(self.characteristic())[name]
688
f = R(self._pari_modulus())
689
try:
690
self.__polynomial[name] = f
691
except (KeyError, AttributeError):
692
self.__polynomial = {}
693
self.__polynomial[name] = f
694
return f
695
696
def __hash__(self):
697
"""
698
Return the hash of this field.
699
700
EXAMPLES::
701
702
sage: {GF(9,'a'): 1} # indirect doctest
703
{Finite Field in a of size 3^2: 1}
704
sage: {GF(9,'b'): 1} # indirect doctest
705
{Finite Field in b of size 3^2: 1}
706
"""
707
try:
708
return self.__hash
709
except AttributeError:
710
self.__hash = hash((self.__order, self.variable_name(), self.__modulus))
711
return self.__hash
712
713