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