Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/rings/finite_rings/finite_field_pari_ffelt.py
8820 views
1
"""
2
Finite fields implemented via PARI's FFELT type
3
4
AUTHORS:
5
6
- Peter Bruin (June 2013): initial version, based on
7
finite_field_ext_pari.py by William Stein et al.
8
"""
9
10
#*****************************************************************************
11
# Copyright (C) 2013 Peter Bruin <[email protected]>
12
#
13
# Distributed under the terms of the GNU General Public License (GPL)
14
# as published by the Free Software Foundation; either version 2 of
15
# the License, or (at your option) any later version.
16
# http://www.gnu.org/licenses/
17
#*****************************************************************************
18
19
20
from element_pari_ffelt import FiniteFieldElement_pari_ffelt
21
from finite_field_base import FiniteField
22
23
24
class FiniteField_pari_ffelt(FiniteField):
25
"""
26
Finite fields whose cardinality is a prime power (not a prime),
27
implemented using PARI's ``FFELT`` type.
28
29
INPUT:
30
31
- ``p`` -- prime number
32
33
- ``modulus`` -- an irreducible polynomial of degree at least 2
34
over the field of `p` elements
35
36
- ``name`` -- string: name of the distinguished generator
37
(default: variable name of ``modulus``)
38
39
OUTPUT:
40
41
A finite field of order `q = p^n`, generated by a distinguished
42
element with minimal polynomial ``modulus``. Elements are
43
represented as polynomials in ``name`` of degree less than `n`.
44
45
.. NOTE::
46
47
- Direct construction of FiniteField_pari_ffelt objects
48
requires specifying a characteristic and a modulus.
49
To construct a finite field by specifying a cardinality and
50
an algorithm for finding an irreducible polynomial, use the
51
FiniteField constructor with ``impl='pari_ffelt'``.
52
53
- Two finite fields are considered equal if and only if they
54
have the same cardinality, variable name, and modulus.
55
56
EXAMPLES:
57
58
Some computations with a finite field of order 9::
59
60
sage: k = FiniteField(9, 'a', impl='pari_ffelt')
61
sage: k
62
Finite Field in a of size 3^2
63
sage: k.is_field()
64
True
65
sage: k.characteristic()
66
3
67
sage: a = k.gen()
68
sage: a
69
a
70
sage: a.parent()
71
Finite Field in a of size 3^2
72
sage: a.charpoly('x')
73
x^2 + 2*x + 2
74
sage: [a^i for i in range(8)]
75
[1, a, a + 1, 2*a + 1, 2, 2*a, 2*a + 2, a + 2]
76
sage: TestSuite(k).run()
77
78
Next we compute with a finite field of order 16::
79
80
sage: k16 = FiniteField(16, 'b', impl='pari_ffelt')
81
sage: z = k16.gen()
82
sage: z
83
b
84
sage: z.charpoly('x')
85
x^4 + x + 1
86
sage: k16.is_field()
87
True
88
sage: k16.characteristic()
89
2
90
sage: z.multiplicative_order()
91
15
92
93
Illustration of dumping and loading::
94
95
sage: K = FiniteField(7^10, 'b', impl='pari_ffelt')
96
sage: loads(K.dumps()) == K
97
True
98
99
sage: K = FiniteField(10007^10, 'a', impl='pari_ffelt')
100
sage: loads(K.dumps()) == K
101
True
102
"""
103
def __init__(self, p, modulus, name=None):
104
"""
105
Create a finite field of characteristic `p` defined by the
106
polynomial ``modulus``, with distinguished generator called
107
``name``.
108
109
EXAMPLE::
110
111
sage: from sage.rings.finite_rings.finite_field_pari_ffelt import FiniteField_pari_ffelt
112
sage: R.<x> = PolynomialRing(GF(3))
113
sage: k = FiniteField_pari_ffelt(3, x^2 + 2*x + 2, 'a'); k
114
Finite Field in a of size 3^2
115
"""
116
import constructor
117
from sage.libs.pari.all import pari
118
from sage.rings.integer import Integer
119
from sage.structure.proof.all import arithmetic
120
proof = arithmetic()
121
122
p = Integer(p)
123
if ((p < 2)
124
or (proof and not p.is_prime())
125
or (not proof and not p.is_pseudoprime())):
126
raise ArithmeticError("p must be a prime number")
127
Fp = constructor.FiniteField(p)
128
129
if name is None:
130
name = modulus.variable_name()
131
132
FiniteField.__init__(self, base=Fp, names=name, normalize=True)
133
134
modulus = self.polynomial_ring()(modulus)
135
n = modulus.degree()
136
if n < 2:
137
raise ValueError("the degree must be at least 2")
138
139
self._modulus = modulus
140
self._degree = n
141
self._card = p ** n
142
self._kwargs = {}
143
144
self._gen_pari = pari(modulus).ffgen()
145
self._zero_element = self.element_class(self, 0)
146
self._one_element = self.element_class(self, 1)
147
self._gen = self.element_class(self, self._gen_pari)
148
149
Element = FiniteFieldElement_pari_ffelt
150
151
def __hash__(self):
152
"""
153
Return the hash of this field.
154
155
EXAMPLE::
156
157
sage: {GF(9, 'a', impl='pari_ffelt'): 1} # indirect doctest
158
{Finite Field in a of size 3^2: 1}
159
sage: {GF(9, 'b', impl='pari_ffelt'): 1} # indirect doctest
160
{Finite Field in b of size 3^2: 1}
161
"""
162
try:
163
return self.__hash
164
except AttributeError:
165
self.__hash = hash((self._card, self.variable_name(), self._modulus))
166
return self.__hash
167
168
def __reduce__(self):
169
"""
170
For pickling.
171
172
EXAMPLE::
173
174
sage: k.<b> = FiniteField(5^20, impl='pari_ffelt')
175
sage: type(k)
176
<class 'sage.rings.finite_rings.finite_field_pari_ffelt.FiniteField_pari_ffelt_with_category'>
177
sage: k is loads(dumps(k))
178
True
179
"""
180
return self._factory_data[0].reduce_data(self)
181
182
def __cmp__(self, other):
183
"""
184
Compare ``self`` to ``other``.
185
186
EXAMPLES::
187
188
sage: k = FiniteField(7^20, 'a', impl='pari_ffelt')
189
sage: k == k
190
True
191
sage: k2 = FiniteField(7^20, 'a', impl='pari_ffelt')
192
sage: k2 == k
193
True
194
sage: kb = FiniteField(7^20, 'b', impl='pari_ffelt')
195
sage: kb == k
196
False
197
"""
198
if not isinstance(other, FiniteField_pari_ffelt):
199
return cmp(type(self), type(other))
200
return cmp((self._card, self.variable_name(), self._modulus),
201
(other._card, other.variable_name(), other._modulus))
202
203
def __richcmp__(left, right, op):
204
"""
205
Compare ``left`` with ``right``.
206
207
EXAMPLE::
208
209
sage: k = FiniteField(2^17, 'a', impl='pari_ffelt')
210
sage: j = FiniteField(2^18, 'b', impl='pari_ffelt')
211
sage: k == j
212
False
213
214
sage: k == copy(k)
215
True
216
"""
217
return left._richcmp_helper(right, op)
218
219
def gen(self, n=0):
220
"""
221
Return a generator of the finite field.
222
223
INPUT:
224
225
- ``n`` -- ignored
226
227
OUTPUT:
228
229
A generator of the finite field.
230
231
This generator is a root of the defining polynomial of the
232
finite field.
233
234
.. WARNING::
235
236
This generator is not guaranteed to be a generator
237
for the multiplicative group. To obtain the latter, use
238
:meth:`~sage.rings.finite_rings.finite_field_base.FiniteFields.multiplicative_generator()`.
239
240
EXAMPLE::
241
242
sage: R.<x> = PolynomialRing(GF(2))
243
sage: FiniteField(2^4, 'b', impl='pari_ffelt').gen()
244
b
245
sage: k = FiniteField(3^4, 'alpha', impl='pari_ffelt')
246
sage: a = k.gen()
247
sage: a
248
alpha
249
sage: a^4
250
alpha^3 + 1
251
"""
252
return self._gen
253
254
def characteristic(self):
255
"""
256
Return the characteristic of ``self``.
257
258
EXAMPLE::
259
260
sage: F = FiniteField(3^4, 'a', impl='pari_ffelt')
261
sage: F.characteristic()
262
3
263
"""
264
# This works since self is not its own prime field.
265
return self.base_ring().characteristic()
266
267
def degree(self):
268
"""
269
Returns the degree of ``self`` over its prime field.
270
271
EXAMPLE::
272
273
sage: F = FiniteField(3^20, 'a', impl='pari_ffelt')
274
sage: F.degree()
275
20
276
"""
277
return self._degree
278
279
def polynomial(self):
280
"""
281
Return the minimal polynomial of the generator of ``self`` in
282
``self.polynomial_ring()``.
283
284
EXAMPLES::
285
286
sage: F = FiniteField(3^2, 'a', impl='pari_ffelt')
287
sage: F.polynomial()
288
a^2 + 2*a + 2
289
290
sage: F = FiniteField(7^20, 'a', impl='pari_ffelt')
291
sage: f = F.polynomial(); f
292
a^20 + a^12 + 6*a^11 + 2*a^10 + 5*a^9 + 2*a^8 + 3*a^7 + a^6 + 3*a^5 + 3*a^3 + a + 3
293
sage: f(F.gen())
294
0
295
"""
296
return self._modulus
297
298
def _element_constructor_(self, x):
299
"""
300
Construct an element of ``self``.
301
302
INPUT:
303
304
- ``x`` -- object
305
306
OUTPUT:
307
308
A finite field element generated from `x`, if possible.
309
310
.. NOTE::
311
312
If `x` is a list or an element of the underlying vector
313
space of the finite field, then it is interpreted as the
314
list of coefficients of a polynomial over the prime field,
315
and that polynomial is interpreted as an element of the
316
finite field.
317
318
EXAMPLES::
319
320
sage: k = FiniteField(3^4, 'a', impl='pari_ffelt')
321
sage: b = k(5) # indirect doctest
322
sage: b.parent()
323
Finite Field in a of size 3^4
324
sage: a = k.gen()
325
sage: k(a + 2)
326
a + 2
327
328
Univariate polynomials coerce into finite fields by evaluating
329
the polynomial at the field's generator::
330
331
sage: R.<x> = QQ[]
332
sage: k, a = FiniteField(5^2, 'a', impl='pari_ffelt').objgen()
333
sage: k(R(2/3))
334
4
335
sage: k(x^2)
336
a + 3
337
338
sage: R.<x> = GF(5)[]
339
sage: k(x^3-2*x+1)
340
2*a + 4
341
342
sage: x = polygen(QQ)
343
sage: k(x^25)
344
a
345
346
sage: Q, q = FiniteField(5^7, 'q', impl='pari_ffelt').objgen()
347
sage: L = GF(5)
348
sage: LL.<xx> = L[]
349
sage: Q(xx^2 + 2*xx + 4)
350
q^2 + 2*q + 4
351
352
sage: k = FiniteField(3^11, 't', impl='pari_ffelt')
353
sage: k.polynomial()
354
t^11 + 2*t^2 + 1
355
sage: P = k.polynomial_ring()
356
sage: k(P.0^11)
357
t^2 + 2
358
359
An element can be specified by its vector of coordinates with
360
respect to the basis consisting of powers of the generator:
361
362
sage: k = FiniteField(3^11, 't', impl='pari_ffelt')
363
sage: V = k.vector_space()
364
sage: V
365
Vector space of dimension 11 over Finite Field of size 3
366
sage: v = V([0,1,2,0,1,2,0,1,2,0,1])
367
sage: k(v)
368
t^10 + 2*t^8 + t^7 + 2*t^5 + t^4 + 2*t^2 + t
369
370
Multivariate polynomials only coerce if constant::
371
372
sage: k = FiniteField(5^2, 'a', impl='pari_ffelt')
373
sage: R = k['x,y,z']; R
374
Multivariate Polynomial Ring in x, y, z over Finite Field in a of size 5^2
375
sage: k(R(2))
376
2
377
sage: R = QQ['x,y,z']
378
sage: k(R(1/5))
379
Traceback (most recent call last):
380
...
381
ZeroDivisionError: Inverse does not exist.
382
383
Gap elements can also be coerced into finite fields::
384
385
sage: F = FiniteField(2^3, 'a', impl='pari_ffelt')
386
sage: a = F.multiplicative_generator(); a
387
a
388
sage: b = gap(a^3); b
389
Z(2^3)^3
390
sage: F(b)
391
a + 1
392
sage: a^3
393
a + 1
394
395
sage: a = GF(13)(gap('0*Z(13)')); a
396
0
397
sage: a.parent()
398
Finite Field of size 13
399
400
sage: F = FiniteField(2^4, 'a', impl='pari_ffelt')
401
sage: F(gap('Z(16)^3'))
402
a^3
403
sage: F(gap('Z(16)^2'))
404
a^2
405
406
You can also call a finite extension field with a string
407
to produce an element of that field, like this::
408
409
sage: k = GF(2^8, 'a')
410
sage: k('a^200')
411
a^4 + a^3 + a^2
412
413
This is especially useful for conversion from Singular etc.
414
415
TESTS::
416
417
sage: k = FiniteField(3^2, 'a', impl='pari_ffelt')
418
sage: a = k(11); a
419
2
420
sage: a.parent()
421
Finite Field in a of size 3^2
422
sage: V = k.vector_space(); v = V((1,2))
423
sage: k(v)
424
2*a + 1
425
426
We create elements using a list and verify that :trac:`10486` has
427
been fixed::
428
429
sage: k = FiniteField(3^11, 't', impl='pari_ffelt')
430
sage: x = k([1,0,2,1]); x
431
t^3 + 2*t^2 + 1
432
sage: x + x + x
433
0
434
sage: pari(x)
435
t^3 + 2*t^2 + 1
436
437
If the list is longer than the degree, we just get the result
438
modulo the modulus::
439
440
sage: from sage.rings.finite_rings.finite_field_pari_ffelt import FiniteField_pari_ffelt
441
sage: R.<a> = PolynomialRing(GF(5))
442
sage: k = FiniteField_pari_ffelt(5, a^2 - 2, 't')
443
sage: x = k([0,0,0,1]); x
444
2*t
445
sage: pari(x)
446
2*t
447
448
When initializing from a list, the elements are first coerced
449
to the prime field (:trac:`11685`)::
450
451
sage: k = FiniteField(3^11, 't', impl='pari_ffelt')
452
sage: k([ 0, 1/2 ])
453
2*t
454
sage: k([ k(0), k(1) ])
455
t
456
sage: k([ GF(3)(2), GF(3^5,'u')(1) ])
457
t + 2
458
sage: R.<x> = PolynomialRing(k)
459
sage: k([ R(-1), x/x ])
460
t + 2
461
462
Check that zeros are created correctly (:trac:`11685`)::
463
464
sage: K = FiniteField(3^11, 't', impl='pari_ffelt'); a = K.0
465
sage: v = 0; pari(K(v))
466
0
467
sage: v = Mod(0,3); pari(K(v))
468
0
469
sage: v = pari(0); pari(K(v))
470
0
471
sage: v = pari("Mod(0,3)"); pari(K(v))
472
0
473
sage: v = []; pari(K(v))
474
0
475
sage: v = [0]; pari(K(v))
476
0
477
sage: v = [0,0]; pari(K(v))
478
0
479
sage: v = pari("Pol(0)"); pari(K(v))
480
0
481
sage: v = pari("Mod(0, %s)"%K.modulus()); pari(K(v))
482
0
483
sage: v = pari("Mod(Pol(0), %s)"%K.modulus()); pari(K(v))
484
0
485
sage: v = K(1) - K(1); pari(K(v))
486
0
487
sage: v = K([1]) - K([1]); pari(K(v))
488
0
489
sage: v = a - a; pari(K(v))
490
0
491
sage: v = K(1)*0; pari(K(v))
492
0
493
sage: v = K([1])*K([0]); pari(K(v))
494
0
495
sage: v = a*0; pari(K(v))
496
0
497
"""
498
if isinstance(x, self.element_class) and x.parent() is self:
499
return x
500
else:
501
return self.element_class(self, x)
502
503
def order(self):
504
"""
505
The number of elements of the finite field.
506
507
EXAMPLE::
508
509
sage: k = FiniteField(2^10, 'a', impl='pari_ffelt')
510
sage: k
511
Finite Field in a of size 2^10
512
sage: k.order()
513
1024
514
"""
515
return self._card
516
517