Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/rings/finite_rings/element_base.pyx
4084 views
1
"""
2
Base class for finite field elements
3
4
AUTHORS::
5
6
- David Roe (2010-1-14) -- factored out of sage.structure.element
7
8
"""
9
include "../../ext/stdsage.pxi"
10
11
from sage.structure.element cimport Element
12
from sage.structure.parent cimport Parent
13
from sage.rings.integer import Integer
14
15
def is_FiniteFieldElement(x):
16
"""
17
Returns if x is a finite field element.
18
19
EXAMPLE::
20
21
sage: from sage.rings.finite_rings.element_ext_pari import is_FiniteFieldElement
22
sage: is_FiniteFieldElement(1)
23
False
24
sage: is_FiniteFieldElement(IntegerRing())
25
False
26
sage: is_FiniteFieldElement(GF(5)(2))
27
True
28
"""
29
from sage.rings.finite_rings.finite_field_base import is_FiniteField
30
return isinstance(x, Element) and is_FiniteField(x.parent())
31
32
cdef class FiniteRingElement(CommutativeRingElement):
33
def _nth_root_common(self, n, all, algorithm, cunningham):
34
"""
35
This function exists to reduce code duplication between finite field nth roots and integer_mod nth roots.
36
37
The inputs are described there.
38
39
TESTS::
40
41
sage: a = Zmod(17)(13)
42
sage: a._nth_root_common(4, True, "Johnston", False)
43
[3, 5, 14, 12]
44
"""
45
K = self.parent()
46
q = K.order()
47
if self.is_one():
48
gcd = n.gcd(q-1)
49
if gcd == 1:
50
if all: return [self]
51
else: return self
52
else:
53
# the following may eventually be improved to not need a multiplicative generator.
54
g = K.multiplicative_generator()
55
q1overn = (q-1)//gcd
56
nthroot = g**q1overn
57
return [nthroot**a for a in range(gcd)] if all else nthroot
58
n = n % (q-1)
59
if n == 0:
60
if all: return []
61
else: raise ValueError, "no nth root"
62
gcd, alpha, beta = n.xgcd(q-1) # gcd = alpha*n + beta*(q-1), so 1/n = alpha/gcd (mod q-1)
63
if gcd == 1:
64
return [self**alpha] if all else self**alpha
65
n = gcd
66
q1overn = (q-1)//n
67
if self**q1overn != 1:
68
if all: return []
69
else: raise ValueError, "no nth root"
70
self = self**alpha
71
if cunningham:
72
F = n._factor_cunningham()
73
else:
74
F = n.factor()
75
from sage.groups.generic import discrete_log
76
if algorithm is None or algorithm == 'Johnston':
77
g = K.multiplicative_generator()
78
for r, v in F:
79
k, h = (q-1).val_unit(r)
80
z = h * (-h).inverse_mod(r**v)
81
x = (1 + z) // r**v
82
if k == 1:
83
self = self**x
84
else:
85
t = discrete_log(self**h, g**(r**v*h), r**(k-v), operation='*')
86
self = self**x * g**(-z*t)
87
if all:
88
nthroot = g**q1overn
89
L = [self]
90
for i in range(1,n):
91
self *= nthroot
92
L.append(self)
93
return L
94
else:
95
return self
96
else:
97
raise ValueError, "unknown algorithm"
98
99
cdef class FinitePolyExtElement(FiniteRingElement):
100
"""
101
Elements represented as polynomials modulo a given ideal.
102
103
TESTS::
104
105
sage: k.<a> = GF(64)
106
sage: TestSuite(a).run()
107
"""
108
def _im_gens_(self, codomain, im_gens):
109
"""
110
Used for applying homomorphisms of finite fields.
111
112
EXAMPLES::
113
114
sage: k.<a> = FiniteField(73^2, 'a')
115
sage: K.<b> = FiniteField(73^4, 'b')
116
sage: phi = k.hom([ b^(73*73+1) ]) # indirect doctest
117
sage: phi(0)
118
0
119
sage: phi(a)
120
7*b^3 + 13*b^2 + 65*b + 71
121
122
sage: phi(a+3)
123
7*b^3 + 13*b^2 + 65*b + 1
124
"""
125
## NOTE: see the note in sage/rings/number_field_element.pyx,
126
## in the comments for _im_gens_ there -- something analogous
127
## applies here.
128
return codomain(self.polynomial()(im_gens[0]))
129
130
def minpoly(self,var='x'):
131
"""
132
Returns the minimal polynomial of this element
133
(over the corresponding prime subfield).
134
135
EXAMPLES::
136
137
sage: k.<a> = FiniteField(19^2)
138
sage: parent(a)
139
Finite Field in a of size 19^2
140
sage: b=a**20;p=b.charpoly("x");p
141
x^2 + 15*x + 4
142
sage: factor(p)
143
(x + 17)^2
144
sage: b.minpoly('x')
145
x + 17
146
"""
147
p=self.charpoly(var);
148
for q in p.factor():
149
if q[0](self)==0:
150
return q[0]
151
# This shouldn't be reached, but you never know!
152
raise ArithmeticError("Could not find the minimal polynomial")
153
154
## We have two names for the same method
155
## for compatibility with sage.matrix
156
def minimal_polynomial(self,var='x'):
157
"""
158
Returns the minimal polynomial of this element
159
(over the corresponding prime subfield).
160
161
EXAMPLES::
162
163
sage: k.<a> = FiniteField(3^4)
164
sage: parent(a)
165
Finite Field in a of size 3^4
166
sage: b=a**20;p=charpoly(b,"y");p
167
y^4 + 2*y^2 + 1
168
sage: factor(p)
169
(y^2 + 1)^2
170
sage: b.minimal_polynomial('y')
171
y^2 + 1
172
"""
173
return self.minpoly(var)
174
175
def vector(self, reverse=False):
176
r"""
177
See :meth:`_vector_`.
178
179
EXAMPLE::
180
181
sage: k.<a> = GF(2^16)
182
sage: e = a^2 + 1
183
sage: e.vector() # random-ish error message
184
doctest:1: DeprecationWarning:The function vector is replaced by _vector_.
185
(1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
186
"""
187
from sage.misc.misc import deprecation
188
deprecation("The function vector is replaced by _vector_.")
189
return self._vector_()
190
191
def _vector_(self, reverse=False):
192
"""
193
Return a vector in self.parent().vector_space() matching
194
self. The most significant bit is to the right.
195
196
INPUT::
197
198
- ``reverse`` -- reverse the order of the bits
199
from little endian to big endian.
200
201
EXAMPLES::
202
203
sage: k.<a> = GF(2^16)
204
sage: e = a^2 + 1
205
sage: v = vector(e)
206
sage: v
207
(1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
208
sage: k(v)
209
a^2 + 1
210
211
sage: k.<a> = GF(3^16)
212
sage: e = 2*a^2 + 1
213
sage: v = vector(e)
214
sage: v
215
(1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
216
sage: k(v)
217
2*a^2 + 1
218
219
You can also compute the vector in the other order::
220
221
sage: e._vector_(reverse=True)
222
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1)
223
"""
224
#vector(foo) might pass in ZZ
225
if PY_TYPE_CHECK(reverse, Parent):
226
raise TypeError, "Base field is fixed to prime subfield."
227
228
k = self.parent()
229
230
v = self.polynomial().list()
231
232
ret = [v[i] for i in range(len(v))]
233
234
for i in range(k.degree() - len(ret)):
235
ret.append(0)
236
237
if reverse:
238
ret = list(reversed(ret))
239
return k.vector_space()(ret)
240
241
def matrix(self, reverse=False):
242
r"""
243
See :meth:`_matrix_`.
244
245
EXAMPLE::
246
247
sage: k.<a> = GF(2^16)
248
sage: e = a^2 + 1
249
sage: e.matrix() # random-ish error message
250
doctest:1: DeprecationWarning:The function matrix is replaced by _matrix_.
251
[1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0]
252
[0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1]
253
[1 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0]
254
[0 1 0 1 0 0 0 0 0 0 0 0 0 0 1 1]
255
[0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1]
256
[0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0]
257
[0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1]
258
[0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0]
259
[0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0]
260
[0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0]
261
[0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0]
262
[0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0]
263
[0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0]
264
[0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0]
265
[0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0]
266
[0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1]
267
"""
268
from sage.misc.misc import deprecation
269
deprecation("The function matrix is replaced by _matrix_.")
270
return self._matrix_()
271
272
273
def _matrix_(self, reverse=False):
274
"""
275
Return the matrix of right multiplication by the element on
276
the power basis `1, x, x^2, \ldots, x^{d-1}` for the field
277
extension. Thus the \emph{rows} of this matrix give the images
278
of each of the `x^i`.
279
280
INPUT:
281
282
- ``reverse`` - if True act on vectors in reversed order
283
284
EXAMPLE::
285
286
sage: k.<a> = GF(2^4)
287
sage: a._vector_(reverse=True), a._matrix_(reverse=True) * a._vector_(reverse=True)
288
((0, 0, 1, 0), (0, 1, 0, 0))
289
sage: vector(a), matrix(a) * vector(a)
290
((0, 1, 0, 0), (0, 0, 1, 0))
291
"""
292
import sage.matrix.matrix_space
293
294
K = self.parent()
295
a = K.gen()
296
x = K(1)
297
d = K.degree()
298
299
columns = []
300
301
if not reverse:
302
l = xrange(d)
303
else:
304
l = reversed(range(d))
305
306
for i in l:
307
columns.append( (self * x)._vector_() )
308
x *= a
309
310
k = K.base_ring()
311
M = sage.matrix.matrix_space.MatrixSpace(k, d)
312
313
if reverse:
314
return M(columns)
315
else:
316
return M(columns).transpose()
317
def _latex_(self):
318
r"""
319
Return the latex representation of self, which is just the
320
latex representation of the polynomial representation of self.
321
322
EXAMPLES::
323
324
sage: k.<b> = GF(5^2); k
325
Finite Field in b of size 5^2
326
sage: b._latex_()
327
'b'
328
sage: (b^2+1)._latex_()
329
'b + 4'
330
"""
331
if self.parent().degree()>1:
332
return self.polynomial()._latex_()
333
else:
334
return str(self)
335
336
def _pari_init_(self, var=None):
337
r"""
338
Return a string that defines this element when evaluated in PARI.
339
340
INPUT:
341
342
- ``var`` - default: ``None`` - a string for a new variable name to use.
343
344
EXAMPLES::
345
346
sage: S.<b> = GF(5^2); S
347
Finite Field in b of size 5^2
348
sage: b._pari_init_()
349
'Mod(Mod(1, 5)*b, Mod(1, 5)*b^2 + Mod(4, 5)*b + Mod(2, 5))'
350
sage: (2*b+3)._pari_init_()
351
'Mod(Mod(2, 5)*b + Mod(3, 5), Mod(1, 5)*b^2 + Mod(4, 5)*b + Mod(2, 5))'
352
353
TESTS:
354
355
The following tests against a bug fixed in trac ticket #11530. ::
356
357
sage: F.<d> = GF(3^4)
358
sage: F.modulus()
359
x^4 + 2*x^3 + 2
360
sage: d._pari_init_()
361
'Mod(Mod(1, 3)*d, Mod(1, 3)*d^4 + Mod(2, 3)*d^3 + Mod(2, 3))'
362
sage: (d^2+2*d+1)._pari_init_("p")
363
'Mod(Mod(1, 3)*p^2 + Mod(2, 3)*p + Mod(1, 3), Mod(1, 3)*p^4 + Mod(2, 3)*p^3 + Mod(2, 3))'
364
sage: d._pari_()
365
Mod(Mod(1, 3)*d, Mod(1, 3)*d^4 + Mod(2, 3)*d^3 + Mod(2, 3))
366
367
sage: K.<M> = GF(2^8)
368
sage: K.modulus()
369
x^8 + x^4 + x^3 + x^2 + 1
370
sage: (M^3+1)._pari_init_()
371
'Mod(Mod(1, 2)*M^3 + Mod(1, 2), Mod(1, 2)*M^8 + Mod(1, 2)*M^4 + Mod(1, 2)*M^3 + Mod(1, 2)*M^2 + Mod(1, 2))'
372
sage: M._pari_init_(var='foo')
373
'Mod(Mod(1, 2)*foo, Mod(1, 2)*foo^8 + Mod(1, 2)*foo^4 + Mod(1, 2)*foo^3 + Mod(1, 2)*foo^2 + Mod(1, 2))'
374
"""
375
if var is None:
376
var = self.parent().variable_name()
377
g = self.parent().modulus()._pari_with_name(var)
378
f = self.polynomial()._pari_with_name(var)
379
return 'Mod({0}, {1})'.format(f, g)
380
381
def charpoly(self, var='x', algorithm='matrix'):
382
"""
383
Return the characteristic polynomial of self as a polynomial with given variable.
384
385
INPUT:
386
387
- ``var`` - string (default: 'x')
388
389
- ``algorithm`` - string (default: 'matrix')
390
391
- 'matrix' - return the charpoly computed from the matrix of
392
left multiplication by self
393
394
- 'pari' -- use pari's charpoly routine on polymods, which
395
is not very good except in small cases
396
397
The result is not cached.
398
399
EXAMPLES::
400
401
sage: k.<a> = GF(19^2)
402
sage: parent(a)
403
Finite Field in a of size 19^2
404
sage: a.charpoly('X')
405
X^2 + 18*X + 2
406
sage: a^2 + 18*a + 2
407
0
408
sage: a.charpoly('X', algorithm='pari')
409
X^2 + 18*X + 2
410
"""
411
if algorithm == 'matrix':
412
return self._matrix_().charpoly(var)
413
elif algorithm == 'pari':
414
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
415
R = PolynomialRing(self.parent().prime_subfield(), var)
416
return R(self._pari_().charpoly('x').lift())
417
else:
418
raise ValueError, "unknown algorithm '%s'"%algorithm
419
420
def norm(self):
421
"""
422
Return the norm of self down to the prime subfield.
423
424
This is the product of the Galois conjugates of self.
425
426
EXAMPLES::
427
428
sage: S.<b> = GF(5^2); S
429
Finite Field in b of size 5^2
430
sage: b.norm()
431
2
432
sage: b.charpoly('t')
433
t^2 + 4*t + 2
434
435
Next we consider a cubic extension::
436
437
sage: S.<a> = GF(5^3); S
438
Finite Field in a of size 5^3
439
sage: a.norm()
440
2
441
sage: a.charpoly('t')
442
t^3 + 3*t + 3
443
sage: a * a^5 * (a^25)
444
2
445
"""
446
f = self.charpoly('x')
447
n = f[0]
448
if f.degree() % 2 != 0:
449
return -n
450
else:
451
return n
452
453
def trace(self):
454
"""
455
Return the trace of this element, which is the sum of the
456
Galois conjugates.
457
458
EXAMPLES::
459
460
sage: S.<a> = GF(5^3); S
461
Finite Field in a of size 5^3
462
sage: a.trace()
463
0
464
sage: a.charpoly('t')
465
t^3 + 3*t + 3
466
sage: a + a^5 + a^25
467
0
468
sage: z = a^2 + a + 1
469
sage: z.trace()
470
2
471
sage: z.charpoly('t')
472
t^3 + 3*t^2 + 2*t + 2
473
sage: z + z^5 + z^25
474
2
475
"""
476
return self.parent().prime_subfield()(self._pari_().trace().lift())
477
478
def multiplicative_order(self):
479
r"""
480
Return the multiplicative order of this field element.
481
482
EXAMPLE::
483
484
sage: S.<a> = GF(5^3); S
485
Finite Field in a of size 5^3
486
sage: a.multiplicative_order()
487
124
488
sage: (a^8).multiplicative_order()
489
31
490
sage: S(0).multiplicative_order()
491
Traceback (most recent call last):
492
...
493
ArithmeticError: Multiplicative order of 0 not defined.
494
"""
495
import sage.rings.arith
496
497
if self.is_zero():
498
raise ArithmeticError("Multiplicative order of 0 not defined.")
499
n = self._parent.order() - 1
500
F = self._parent.factored_unit_order()[0]
501
order = 1
502
for p, e in F:
503
# Determine the power of p that divides the order.
504
a = self**(n//(p**e))
505
while a != 1:
506
order = order * p
507
a = a**p
508
509
return order
510
511
def additive_order(self):
512
"""
513
Return the additive order of this finite field element.
514
515
EXAMPLES::
516
517
sage: k.<a> = FiniteField(2^12, 'a')
518
sage: b = a^3 + a + 1
519
sage: b.additive_order()
520
2
521
sage: k(0).additive_order()
522
1
523
"""
524
if self.is_zero():
525
from sage.rings.integer import Integer
526
return Integer(1)
527
return self.parent().characteristic()
528
529
def nth_root(self, n, extend = False, all = False, algorithm=None, cunningham=False):
530
r"""
531
Returns an `n`\th root of ``self``.
532
533
INPUT:
534
535
- ``n`` - integer `\geq 1`
536
537
- ``extend`` - bool (default: ``False``); if ``True``, return an `n`\th
538
root in an extension ring, if necessary. Otherwise, raise a
539
ValueError if the root is not in the base ring. Warning:
540
this option is not implemented!
541
542
- ``all`` - bool (default: ``False``); if ``True``, return all `n`\th
543
roots of ``self``, instead of just one.
544
545
- ``algorithm`` - string (default: ``None``); 'Johnston' is the only
546
currently supported option. For IntegerMod elements, the problem
547
is reduced to the prime modulus case using CRT and `p`-adic logs,
548
and then this algorithm used.
549
550
OUTPUT:
551
552
If self has an `n`\th root, returns one (if ``all`` is ``False``) or a
553
list of all of them (if ``all`` is ``True``). Otherwise, raises a
554
ValueError (if ``extend`` is ``False``) or a ``NotImplementedError`` (if
555
``extend`` is ``True``).
556
557
.. warning::
558
559
The 'extend' option is not implemented (yet).
560
561
EXAMPLES::
562
563
sage: K = GF(31)
564
sage: a = K(22)
565
sage: K(22).nth_root(7)
566
13
567
sage: K(25).nth_root(5)
568
5
569
sage: K(23).nth_root(3)
570
29
571
572
sage: K.<a> = GF(625)
573
sage: (3*a^2+a+1).nth_root(13)**13
574
3*a^2 + a + 1
575
576
sage: k.<a> = GF(29^2)
577
sage: b = a^2 + 5*a + 1
578
sage: b.nth_root(11)
579
3*a + 20
580
sage: b.nth_root(5)
581
Traceback (most recent call last):
582
...
583
ValueError: no nth root
584
sage: b.nth_root(5, all = True)
585
[]
586
sage: b.nth_root(3, all = True)
587
[14*a + 18, 10*a + 13, 5*a + 27]
588
589
sage: k.<a> = GF(29^5)
590
sage: b = a^2 + 5*a + 1
591
sage: b.nth_root(5)
592
19*a^4 + 2*a^3 + 2*a^2 + 16*a + 3
593
sage: b.nth_root(7)
594
Traceback (most recent call last):
595
...
596
ValueError: no nth root
597
sage: b.nth_root(4, all=True)
598
[]
599
600
TESTS::
601
602
sage: for p in [2,3,5,7,11]: # long
603
... for n in [2,5,10]:
604
... q = p^n
605
... K.<a> = GF(q)
606
... for r in (q-1).divisors():
607
... if r == 1: continue
608
... x = K.random_element()
609
... y = x^r
610
... if y.nth_root(r)**r != y: raise RuntimeError
611
... if (y^41).nth_root(41*r)**(41*r) != y^41: raise RuntimeError
612
... if (y^307).nth_root(307*r)**(307*r) != y^307: raise RuntimeError
613
614
sage: k.<a> = GF(4)
615
sage: a.nth_root(0,all=True)
616
[]
617
sage: k(1).nth_root(0,all=True)
618
[a, a + 1, 1]
619
620
ALGORITHMS:
621
622
- The default is currently an algorithm described in the following paper:
623
624
Johnston, Anna M. A generalized qth root algorithm. Proceedings of the tenth annual ACM-SIAM symposium on Discrete algorithms. Baltimore, 1999: pp 929-930.
625
626
AUTHOR:
627
628
- David Roe (2010-02-13)
629
"""
630
if self.is_zero():
631
if n <= 0:
632
if all: return []
633
else: raise ValueError
634
if all: return [self]
635
else: return self
636
if n < 0:
637
self = ~self
638
n = -n
639
elif n == 0:
640
if self == 1:
641
if all: return [a for a in self.parent().list() if a != 0]
642
else: return self
643
else:
644
if all: return []
645
else: raise ValueError
646
if extend:
647
raise NotImplementedError
648
from sage.rings.integer import Integer
649
n = Integer(n)
650
return self._nth_root_common(n, all, algorithm, cunningham)
651
652
def pth_power(self, int k = 1):
653
"""
654
Return the `(p^k)^{th}` power of self, where `p` is the
655
characteristic of the field.
656
657
INPUT:
658
659
- ``k`` - integer (default: 1, must fit in C int type)
660
661
Note that if `k` is negative, then this computes the appropriate root.
662
663
EXAMPLES::
664
665
sage: F.<a> = GF(29^2)
666
sage: z = a^2 + 5*a + 1
667
sage: z.pth_power()
668
19*a + 20
669
sage: z.pth_power(10)
670
10*a + 28
671
sage: z.pth_power(-10) == z
672
True
673
sage: F.<b> = GF(2^12)
674
sage: y = b^3 + b + 1
675
sage: y == (y.pth_power(-3))^(2^3)
676
True
677
sage: y.pth_power(2)
678
b^7 + b^6 + b^5 + b^4 + b^3 + b
679
"""
680
p = self.additive_order()
681
n = self.parent().degree()
682
return self**(p**(k % n))
683
684
frobenius = pth_power
685
686
def pth_root(self, int k = 1):
687
"""
688
Return the `(p^k)^{th}` root of self, where `p` is the characteristic
689
of the field.
690
691
INPUT:
692
693
- ``k`` - integer (default: 1, must fit in C int type)
694
695
Note that if `k` is negative, then this computes the appropriate power.
696
697
EXAMPLES::
698
699
sage: F.<b> = GF(2^12)
700
sage: y = b^3 + b + 1
701
sage: y == (y.pth_root(3))^(2^3)
702
True
703
sage: y.pth_root(2)
704
b^11 + b^10 + b^9 + b^7 + b^5 + b^4 + b^2 + b
705
"""
706
return self.pth_power(-k)
707
708
709