Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/rings/finite_rings/element_pari_ffelt.pyx
8820 views
1
"""
2
Finite field elements implemented via PARI's FFELT type
3
4
AUTHORS:
5
6
- Peter Bruin (June 2013): initial version, based on
7
element_ext_pari.py by William Stein et al. and
8
element_ntl_gf2e.pyx by Martin Albrecht.
9
"""
10
11
#*****************************************************************************
12
# Copyright (C) 2013 Peter Bruin <[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
include "sage/ext/stdsage.pxi"
22
include "sage/libs/pari/pari_err.pxi"
23
24
from element_base cimport FinitePolyExtElement
25
from integer_mod import IntegerMod_abstract
26
27
import sage.libs.pari
28
import sage.rings.integer
29
from sage.interfaces.gap import is_GapElement
30
from sage.libs.pari.gen cimport gen as pari_gen
31
from sage.libs.pari.pari_instance cimport PariInstance
32
from sage.modules.free_module_element import FreeModuleElement
33
from sage.rings.integer cimport Integer
34
from sage.rings.polynomial.polynomial_element import Polynomial
35
from sage.rings.polynomial.multi_polynomial_element import MPolynomial
36
from sage.rings.rational import Rational
37
from sage.structure.element cimport Element, ModuleElement, RingElement
38
39
cdef long mpz_t_offset = sage.rings.integer.mpz_t_offset_python
40
41
cdef PariInstance pari = sage.libs.pari.pari_instance.pari
42
43
cdef extern from "sage/libs/pari/misc.h":
44
int gcmp_sage(GEN x, GEN y)
45
46
47
cdef GEN _INT_to_FFELT(GEN g, GEN x) except NULL:
48
"""
49
Convert the t_INT `x` to an element of the field of definition of
50
the t_FFELT `g`.
51
52
This function must be called within pari_catch_sig_on() ... pari_catch_sig_off().
53
"""
54
cdef GEN f, p = gel(g, 4), result
55
cdef long t
56
57
x = modii(x, p)
58
if gequal0(x):
59
return FF_zero(g)
60
elif gequal1(x):
61
return FF_1(g)
62
else:
63
# In characteristic 2, we have already dealt with the
64
# two possible values of x, so we may assume that the
65
# characteristic is > 2.
66
t = g[1] # codeword: t_FF_FpXQ, t_FF_Flxq, t_FF_F2xq
67
if t == t_FF_FpXQ:
68
f = cgetg(3, t_POL)
69
set_gel(f, 1, gmael(g, 2, 1))
70
set_gel(f, 2, x)
71
elif t == t_FF_Flxq:
72
f = cgetg(3, t_VECSMALL)
73
set_gel(f, 1, gmael(g, 2, 1))
74
f[2] = itos(x)
75
else:
76
pari_catch_sig_off()
77
raise TypeError("unknown PARI finite field type")
78
result = cgetg(5, t_FFELT)
79
result[1] = t
80
set_gel(result, 2, f)
81
set_gel(result, 3, gel(g, 3)) # modulus
82
set_gel(result, 4, p)
83
return result
84
85
cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement):
86
"""
87
An element of a finite field.
88
89
EXAMPLE::
90
91
sage: K = FiniteField(10007^10, 'a', impl='pari_ffelt')
92
sage: a = K.gen(); a
93
a
94
sage: type(a)
95
<type 'sage.rings.finite_rings.element_pari_ffelt.FiniteFieldElement_pari_ffelt'>
96
97
TESTS::
98
99
sage: n = 63
100
sage: m = 3;
101
sage: K.<a> = GF(2^n, impl='pari_ffelt')
102
sage: f = conway_polynomial(2, n)
103
sage: f(a) == 0
104
True
105
sage: e = (2^n - 1) / (2^m - 1)
106
sage: conway_polynomial(2, m)(a^e) == 0
107
True
108
109
sage: K.<a> = FiniteField(2^16, impl='pari_ffelt')
110
sage: K(0).is_zero()
111
True
112
sage: (a - a).is_zero()
113
True
114
sage: a - a
115
0
116
sage: a == a
117
True
118
sage: a - a == 0
119
True
120
sage: a - a == K(0)
121
True
122
sage: TestSuite(a).run()
123
124
Test creating elements from basic Python types::
125
126
sage: K.<a> = FiniteField(7^20, impl='pari_ffelt')
127
sage: K(int(8))
128
1
129
sage: K(long(-2^300))
130
6
131
"""
132
133
def __init__(FiniteFieldElement_pari_ffelt self, object parent, object x):
134
"""
135
Initialise ``self`` with the given ``parent`` and value
136
converted from ``x``.
137
138
This is called when constructing elements from Python.
139
140
TEST::
141
142
sage: from sage.rings.finite_rings.element_pari_ffelt import FiniteFieldElement_pari_ffelt
143
sage: K = FiniteField(101^2, 'a', impl='pari_ffelt')
144
sage: x = FiniteFieldElement_pari_ffelt(K, 'a + 1')
145
sage: x
146
a + 1
147
"""
148
# FinitePolyExtElement.__init__(self, parent)
149
self._parent = parent
150
self.construct_from(x)
151
152
# The Cython constructor __cinit__ is not necessary: according to
153
# the Cython documentation, C attributes are initialised to 0.
154
# def __cinit__(FiniteFieldElement_pari_ffelt self):
155
# self.block = NULL
156
157
def __dealloc__(FiniteFieldElement_pari_ffelt self):
158
"""
159
Cython deconstructor.
160
"""
161
if self.block:
162
sage_free(self.block)
163
164
cdef FiniteFieldElement_pari_ffelt _new(FiniteFieldElement_pari_ffelt self):
165
"""
166
Create an empty element with the same parent as ``self``.
167
"""
168
cdef FiniteFieldElement_pari_ffelt x
169
x = FiniteFieldElement_pari_ffelt.__new__(FiniteFieldElement_pari_ffelt)
170
x._parent = self._parent
171
return x
172
173
cdef void construct(FiniteFieldElement_pari_ffelt self, GEN g):
174
"""
175
Initialise ``self`` to the FFELT ``g``, reset the PARI stack,
176
and call pari_catch_sig_off().
177
178
This should be called exactly once on every instance.
179
"""
180
self.val = pari.deepcopy_to_python_heap(g, <pari_sp*>&self.block)
181
pari.clear_stack()
182
183
cdef void construct_from(FiniteFieldElement_pari_ffelt self, object x) except *:
184
"""
185
Initialise ``self`` to an FFELT constructed from the Sage
186
object `x`.
187
"""
188
cdef GEN f, g, result, x_GEN
189
cdef long i, n, t
190
cdef Integer xi
191
192
if isinstance(x, FiniteFieldElement_pari_ffelt):
193
if self._parent is (<FiniteFieldElement_pari_ffelt>x)._parent:
194
pari_catch_sig_on()
195
self.construct((<FiniteFieldElement_pari_ffelt>x).val)
196
else:
197
# This is where we *would* do coercion from one finite field to another...
198
raise TypeError("no coercion defined")
199
200
elif isinstance(x, Integer):
201
g = (<pari_gen>self._parent._gen_pari).g
202
pari_catch_sig_on()
203
x_GEN = pari._new_GEN_from_mpz_t(<void *>x + mpz_t_offset)
204
self.construct(_INT_to_FFELT(g, x_GEN))
205
206
elif isinstance(x, int) or isinstance(x, long):
207
g = (<pari_gen>self._parent._gen_pari).g
208
x = pari(x)
209
pari_catch_sig_on()
210
x_GEN = (<pari_gen>x).g
211
self.construct(_INT_to_FFELT(g, x_GEN))
212
213
elif isinstance(x, IntegerMod_abstract):
214
if self._parent.characteristic().divides(x.modulus()):
215
g = (<pari_gen>self._parent._gen_pari).g
216
x = Integer(x)
217
pari_catch_sig_on()
218
x_GEN = pari._new_GEN_from_mpz_t(<void *>x + mpz_t_offset)
219
self.construct(_INT_to_FFELT(g, x_GEN))
220
else:
221
raise TypeError("no coercion defined")
222
223
elif x is None:
224
g = (<pari_gen>self._parent._gen_pari).g
225
pari_catch_sig_on()
226
self.construct(FF_zero(g))
227
228
elif isinstance(x, pari_gen):
229
g = (<pari_gen>self._parent._gen_pari).g
230
x_GEN = (<pari_gen>x).g
231
232
pari_catch_sig_on()
233
if gequal0(x_GEN):
234
self.construct(FF_zero(g))
235
return
236
elif gequal1(x_GEN):
237
self.construct(FF_1(g))
238
return
239
240
t = typ(x_GEN)
241
if t == t_FFELT and FF_samefield(x_GEN, g):
242
self.construct(x_GEN)
243
elif t == t_INT:
244
self.construct(_INT_to_FFELT(g, x_GEN))
245
elif t == t_INTMOD and gequal0(modii(gel(x_GEN, 1), FF_p_i(g))):
246
self.construct(_INT_to_FFELT(g, gel(x_GEN, 2)))
247
elif t == t_FRAC and not gequal0(modii(gel(x_GEN, 2), FF_p_i(g))):
248
self.construct(FF_div(_INT_to_FFELT(g, gel(x_GEN, 1)),
249
_INT_to_FFELT(g, gel(x_GEN, 2))))
250
else:
251
pari_catch_sig_off()
252
raise TypeError("no coercion defined")
253
254
elif (isinstance(x, FreeModuleElement)
255
and x.parent() is self._parent.vector_space()):
256
g = (<pari_gen>self._parent._gen_pari).g
257
t = g[1] # codeword: t_FF_FpXQ, t_FF_Flxq, t_FF_F2xq
258
n = len(x)
259
while n > 0 and x[n - 1] == 0:
260
n -= 1
261
pari_catch_sig_on()
262
if n == 0:
263
self.construct(FF_zero(g))
264
return
265
if t == t_FF_FpXQ:
266
f = cgetg(n + 2, t_POL)
267
set_gel(f, 1, gmael(g, 2, 1))
268
for i in xrange(n):
269
xi = Integer(x[i])
270
set_gel(f, i + 2, pari._new_GEN_from_mpz_t(<void *>xi + mpz_t_offset))
271
elif t == t_FF_Flxq or t == t_FF_F2xq:
272
f = cgetg(n + 2, t_VECSMALL)
273
set_gel(f, 1, gmael(g, 2, 1))
274
for i in xrange(n):
275
f[i + 2] = x[i]
276
if t == t_FF_F2xq:
277
f = Flx_to_F2x(f)
278
else:
279
pari_catch_sig_off()
280
raise TypeError("unknown PARI finite field type")
281
result = cgetg(5, t_FFELT)
282
result[1] = t
283
set_gel(result, 2, f)
284
set_gel(result, 3, gel(g, 3)) # modulus
285
set_gel(result, 4, gel(g, 4)) # p
286
self.construct(result)
287
288
elif isinstance(x, Rational):
289
self.construct_from(x % self._parent.characteristic())
290
291
elif isinstance(x, Polynomial):
292
if x.base_ring() is not self._parent.base_ring():
293
x = x.change_ring(self._parent.base_ring())
294
self.construct_from(x.substitute(self._parent.gen()))
295
296
elif isinstance(x, MPolynomial) and x.is_constant():
297
self.construct_from(x.constant_coefficient())
298
299
elif isinstance(x, list):
300
if len(x) == self._parent.degree():
301
self.construct_from(self._parent.vector_space()(x))
302
else:
303
Fp = self._parent.base_ring()
304
self.construct_from(self._parent.polynomial_ring()([Fp(y) for y in x]))
305
306
elif isinstance(x, str):
307
self.construct_from(self._parent.polynomial_ring()(x))
308
309
elif is_GapElement(x):
310
from sage.interfaces.gap import gfq_gap_to_sage
311
try:
312
self.construct_from(gfq_gap_to_sage(x, self._parent))
313
except (ValueError, IndexError, TypeError):
314
raise TypeError("no coercion defined")
315
316
else:
317
raise TypeError("no coercion defined")
318
319
def _repr_(FiniteFieldElement_pari_ffelt self):
320
"""
321
Return the string representation of ``self``.
322
323
EXAMPLE::
324
325
sage: k.<c> = GF(3^17, impl='pari_ffelt')
326
sage: c^20 # indirect doctest
327
c^4 + 2*c^3
328
"""
329
pari_catch_sig_on()
330
return str(pari.new_gen(self.val))
331
332
def __hash__(FiniteFieldElement_pari_ffelt self):
333
"""
334
Return the hash of ``self``. This is by definition equal to
335
the hash of ``self.polynomial()``.
336
337
EXAMPLE::
338
339
sage: k.<a> = GF(3^15, impl='pari_ffelt')
340
sage: R = GF(3)['a']; aa = R.gen()
341
sage: hash(a^2 + 1) == hash(aa^2 + 1)
342
True
343
"""
344
return hash(self.polynomial())
345
346
def __reduce__(FiniteFieldElement_pari_ffelt self):
347
"""
348
For pickling.
349
350
TEST::
351
352
sage: K.<a> = FiniteField(10007^10, impl='pari_ffelt')
353
sage: loads(a.dumps()) == a
354
True
355
"""
356
return unpickle_FiniteFieldElement_pari_ffelt, (self._parent, str(self))
357
358
def __copy__(FiniteFieldElement_pari_ffelt self):
359
"""
360
Return a copy of ``self``.
361
362
TESTS::
363
364
sage: k.<a> = FiniteField(3^3, impl='pari_ffelt')
365
sage: a
366
a
367
sage: b = copy(a); b
368
a
369
sage: a == b
370
True
371
sage: a is b
372
False
373
"""
374
cdef FiniteFieldElement_pari_ffelt x = self._new()
375
pari_catch_sig_on()
376
x.construct(self.val)
377
return x
378
379
cdef int _cmp_c_impl(FiniteFieldElement_pari_ffelt self, Element other) except -2:
380
"""
381
Comparison of finite field elements.
382
383
TESTS::
384
385
sage: k.<a> = FiniteField(3^3, impl='pari_ffelt')
386
sage: a == 1
387
False
388
sage: a^0 == 1
389
True
390
sage: a == a
391
True
392
sage: a < a^2
393
True
394
sage: a > a^2
395
False
396
"""
397
return gcmp_sage(self.val, (<FiniteFieldElement_pari_ffelt>other).val)
398
399
def __richcmp__(FiniteFieldElement_pari_ffelt left, object right, int op):
400
"""
401
Rich comparison of finite field elements.
402
403
EXAMPLE::
404
405
sage: k.<a> = GF(2^20, impl='pari_ffelt')
406
sage: e = k.random_element()
407
sage: f = loads(dumps(e))
408
sage: e is f
409
False
410
sage: e == f
411
True
412
sage: e != (e + 1)
413
True
414
415
.. NOTE::
416
417
Finite fields are unordered. However, for the purpose of
418
this function, we adopt the lexicographic ordering on the
419
representing polynomials.
420
421
EXAMPLE::
422
423
sage: K.<a> = GF(2^100, impl='pari_ffelt')
424
sage: a < a^2
425
True
426
sage: a > a^2
427
False
428
sage: a+1 > a^2
429
False
430
sage: a+1 < a^2
431
True
432
sage: a+1 < a
433
False
434
sage: a+1 == a
435
False
436
sage: a == a
437
True
438
"""
439
return (<Element>left)._richcmp(right, op)
440
441
cpdef ModuleElement _add_(FiniteFieldElement_pari_ffelt self, ModuleElement right):
442
"""
443
Addition.
444
445
EXAMPLE::
446
447
sage: k.<a> = GF(3^17, impl='pari_ffelt')
448
sage: a + a^2 # indirect doctest
449
a^2 + a
450
"""
451
cdef FiniteFieldElement_pari_ffelt x = self._new()
452
pari_catch_sig_on()
453
x.construct(FF_add((<FiniteFieldElement_pari_ffelt>self).val,
454
(<FiniteFieldElement_pari_ffelt>right).val))
455
return x
456
457
cpdef ModuleElement _sub_(FiniteFieldElement_pari_ffelt self, ModuleElement right):
458
"""
459
Subtraction.
460
461
EXAMPLE::
462
463
sage: k.<a> = GF(3^17, impl='pari_ffelt')
464
sage: a - a # indirect doctest
465
0
466
"""
467
cdef FiniteFieldElement_pari_ffelt x = self._new()
468
pari_catch_sig_on()
469
x.construct(FF_sub((<FiniteFieldElement_pari_ffelt>self).val,
470
(<FiniteFieldElement_pari_ffelt>right).val))
471
return x
472
473
cpdef RingElement _mul_(FiniteFieldElement_pari_ffelt self, RingElement right):
474
"""
475
Multiplication.
476
477
EXAMPLE::
478
479
sage: k.<a> = GF(3^17, impl='pari_ffelt')
480
sage: (a^12 + 1)*(a^15 - 1) # indirect doctest
481
a^15 + 2*a^12 + a^11 + 2*a^10 + 2
482
"""
483
cdef FiniteFieldElement_pari_ffelt x = self._new()
484
pari_catch_sig_on()
485
x.construct(FF_mul((<FiniteFieldElement_pari_ffelt>self).val,
486
(<FiniteFieldElement_pari_ffelt>right).val))
487
return x
488
489
cpdef RingElement _div_(FiniteFieldElement_pari_ffelt self, RingElement right):
490
"""
491
Division.
492
493
EXAMPLE::
494
495
sage: k.<a> = GF(3^17, impl='pari_ffelt')
496
sage: (a - 1) / (a + 1) # indirect doctest
497
2*a^16 + a^15 + 2*a^14 + a^13 + 2*a^12 + a^11 + 2*a^10 + a^9 + 2*a^8 + a^7 + 2*a^6 + a^5 + 2*a^4 + a^3 + 2*a^2 + a + 1
498
"""
499
if FF_equal0((<FiniteFieldElement_pari_ffelt>right).val):
500
raise ZeroDivisionError
501
cdef FiniteFieldElement_pari_ffelt x = self._new()
502
pari_catch_sig_on()
503
x.construct(FF_div((<FiniteFieldElement_pari_ffelt>self).val,
504
(<FiniteFieldElement_pari_ffelt>right).val))
505
return x
506
507
def is_zero(FiniteFieldElement_pari_ffelt self):
508
"""
509
Return ``True`` if ``self`` equals 0.
510
511
EXAMPLE::
512
513
sage: F.<a> = FiniteField(5^3, impl='pari_ffelt')
514
sage: a.is_zero()
515
False
516
sage: (a - a).is_zero()
517
True
518
"""
519
return bool(FF_equal0(self.val))
520
521
def is_one(FiniteFieldElement_pari_ffelt self):
522
"""
523
Return ``True`` if ``self`` equals 1.
524
525
EXAMPLE::
526
527
sage: F.<a> = FiniteField(5^3, impl='pari_ffelt')
528
sage: a.is_one()
529
False
530
sage: (a/a).is_one()
531
True
532
"""
533
return bool(FF_equal1(self.val))
534
535
def is_unit(FiniteFieldElement_pari_ffelt self):
536
"""
537
Return ``True`` if ``self`` is non-zero.
538
539
EXAMPLE::
540
541
sage: F.<a> = FiniteField(5^3, impl='pari_ffelt')
542
sage: a.is_unit()
543
True
544
"""
545
return not bool(FF_equal0(self.val))
546
547
__nonzero__ = is_unit
548
549
def __pos__(FiniteFieldElement_pari_ffelt self):
550
"""
551
Unitary positive operator...
552
553
EXAMPLE::
554
555
sage: k.<a> = GF(3^17, impl='pari_ffelt')
556
sage: +a
557
a
558
"""
559
return self
560
561
def __neg__(FiniteFieldElement_pari_ffelt self):
562
"""
563
Negation.
564
565
EXAMPLE::
566
567
sage: k.<a> = GF(3^17, impl='pari_ffelt')
568
sage: -a
569
2*a
570
"""
571
cdef FiniteFieldElement_pari_ffelt x = self._new()
572
pari_catch_sig_on()
573
x.construct(FF_neg_i((<FiniteFieldElement_pari_ffelt>self).val))
574
return x
575
576
def __invert__(FiniteFieldElement_pari_ffelt self):
577
"""
578
Return the multiplicative inverse of ``self``.
579
580
EXAMPLE::
581
582
sage: k.<a> = FiniteField(3^2, impl='pari_ffelt')
583
sage: ~a
584
a + 2
585
sage: (a+1)*a
586
2*a + 1
587
sage: ~((2*a)/a)
588
2
589
"""
590
if FF_equal0(self.val):
591
raise ZeroDivisionError
592
cdef FiniteFieldElement_pari_ffelt x = self._new()
593
pari_catch_sig_on()
594
x.construct(FF_inv((<FiniteFieldElement_pari_ffelt>self).val))
595
return x
596
597
def __pow__(FiniteFieldElement_pari_ffelt self, object exp, object other):
598
"""
599
Exponentiation.
600
601
TESTS::
602
603
sage: K.<a> = GF(5^10, impl='pari_ffelt')
604
sage: n = (2*a)/a
605
sage: n^-15
606
2
607
608
Large exponents are not a problem::
609
610
sage: e = 3^10000
611
sage: a^e
612
2*a^9 + a^5 + 4*a^4 + 4*a^3 + a^2 + 3*a
613
sage: a^(e % (5^10 - 1))
614
2*a^9 + a^5 + 4*a^4 + 4*a^3 + a^2 + 3*a
615
"""
616
if exp == 0:
617
return self._parent.one_element()
618
if exp < 0 and FF_equal0(self.val):
619
raise ZeroDivisionError
620
exp = pari(exp)
621
cdef FiniteFieldElement_pari_ffelt x = self._new()
622
pari_catch_sig_on()
623
x.construct(FF_pow(self.val, (<pari_gen>exp).g))
624
return x
625
626
def polynomial(FiniteFieldElement_pari_ffelt self):
627
"""
628
Return the unique representative of ``self`` as a polynomial
629
over the prime field whose degree is less than the degree of
630
the finite field over its prime field.
631
632
EXAMPLES::
633
634
sage: k.<a> = FiniteField(3^2, impl='pari_ffelt')
635
sage: pol = a.polynomial()
636
sage: pol
637
a
638
sage: parent(pol)
639
Univariate Polynomial Ring in a over Finite Field of size 3
640
641
::
642
643
sage: k = FiniteField(3^4, 'alpha', impl='pari_ffelt')
644
sage: a = k.gen()
645
sage: a.polynomial()
646
alpha
647
sage: (a**2 + 1).polynomial()
648
alpha^2 + 1
649
sage: (a**2 + 1).polynomial().parent()
650
Univariate Polynomial Ring in alpha over Finite Field of size 3
651
"""
652
pari_catch_sig_on()
653
return self._parent.polynomial_ring()(pari.new_gen(FF_to_FpXQ_i(self.val)))
654
655
def charpoly(FiniteFieldElement_pari_ffelt self, object var='x'):
656
"""
657
Return the characteristic polynomial of ``self``.
658
659
INPUT:
660
661
- ``var`` -- string (default: 'x'): variable name to use.
662
663
EXAMPLE::
664
665
sage: R.<x> = PolynomialRing(FiniteField(3))
666
sage: F.<a> = FiniteField(3^2, modulus=x^2 + 1)
667
sage: a.charpoly('y')
668
y^2 + 1
669
"""
670
pari_catch_sig_on()
671
return self._parent.polynomial_ring(var)(pari.new_gen(FF_charpoly(self.val)))
672
673
def is_square(FiniteFieldElement_pari_ffelt self):
674
"""
675
Return ``True`` if and only if ``self`` is a square in the
676
finite field.
677
678
EXAMPLES::
679
680
sage: k.<a> = FiniteField(3^2, impl='pari_ffelt')
681
sage: a.is_square()
682
False
683
sage: (a**2).is_square()
684
True
685
686
sage: k.<a> = FiniteField(2^2, impl='pari_ffelt')
687
sage: (a**2).is_square()
688
True
689
690
sage: k.<a> = FiniteField(17^5, impl='pari_ffelt')
691
sage: (a**2).is_square()
692
True
693
sage: a.is_square()
694
False
695
sage: k(0).is_square()
696
True
697
"""
698
cdef long i
699
pari_catch_sig_on()
700
i = FF_issquare(self.val)
701
pari_catch_sig_off()
702
return bool(i)
703
704
def sqrt(FiniteFieldElement_pari_ffelt self, extend=False, all=False):
705
"""
706
Return a square root of ``self``, if it exists.
707
708
INPUT:
709
710
- ``extend`` -- bool (default: ``False``)
711
712
.. WARNING::
713
714
This option is not implemented.
715
716
- ``all`` - bool (default: ``False``)
717
718
OUTPUT:
719
720
A square root of ``self``, if it exists. If ``all`` is
721
``True``, a list containing all square roots of ``self``
722
(of length zero, one or two) is returned instead.
723
724
If ``extend`` is ``True``, a square root is chosen in an
725
extension field if necessary. If ``extend`` is ``False``, a
726
ValueError is raised if the element is not a square in the
727
base field.
728
729
.. WARNING::
730
731
The ``extend`` option is not implemented (yet).
732
733
EXAMPLES::
734
735
sage: F = FiniteField(7^2, 'a', impl='pari_ffelt')
736
sage: F(2).sqrt()
737
4
738
sage: F(3).sqrt()
739
5*a + 1
740
sage: F(3).sqrt()**2
741
3
742
sage: F(4).sqrt(all=True)
743
[2, 5]
744
745
sage: K = FiniteField(7^3, 'alpha', impl='pari_ffelt')
746
sage: K(3).sqrt()
747
Traceback (most recent call last):
748
...
749
ValueError: element is not a square
750
sage: K(3).sqrt(all=True)
751
[]
752
753
sage: K.<a> = GF(3^17, impl='pari_ffelt')
754
sage: (a^3 - a - 1).sqrt()
755
a^16 + 2*a^15 + a^13 + 2*a^12 + a^10 + 2*a^9 + 2*a^8 + a^7 + a^6 + 2*a^5 + a^4 + 2*a^2 + 2*a + 2
756
"""
757
if extend:
758
raise NotImplementedError
759
cdef GEN s
760
cdef FiniteFieldElement_pari_ffelt x, mx
761
pari_catch_sig_on()
762
if FF_issquareall(self.val, &s):
763
x = self._new()
764
x.construct(s)
765
if not all:
766
return x
767
elif gequal0(x.val) or self._parent.characteristic() == 2:
768
return [x]
769
else:
770
pari_catch_sig_on()
771
mx = self._new()
772
mx.construct(FF_neg_i(x.val))
773
return [x, mx]
774
else:
775
pari_catch_sig_off()
776
if all:
777
return []
778
else:
779
raise ValueError("element is not a square")
780
781
def log(FiniteFieldElement_pari_ffelt self, object base):
782
"""
783
Return a discrete logarithm of ``self`` with respect to the
784
given base.
785
786
INPUT:
787
788
- ``base`` -- non-zero field element
789
790
OUTPUT:
791
792
An integer `x` such that ``self`` equals ``base`` raised to
793
the power `x`. If no such `x` exists, a ``ValueError`` is
794
raised.
795
796
EXAMPLES::
797
798
sage: F.<g> = FiniteField(2^10, impl='pari_ffelt')
799
sage: b = g; a = g^37
800
sage: a.log(b)
801
37
802
sage: b^37; a
803
g^8 + g^7 + g^4 + g + 1
804
g^8 + g^7 + g^4 + g + 1
805
806
::
807
808
sage: F.<a> = FiniteField(5^2, impl='pari_ffelt')
809
sage: F(-1).log(F(2))
810
2
811
sage: F(1).log(a)
812
0
813
814
Some cases where the logarithm is not defined or does not exist::
815
816
sage: F.<a> = GF(3^10, impl='pari_ffelt')
817
sage: a.log(-1)
818
Traceback (most recent call last):
819
...
820
ArithmeticError: element a does not lie in group generated by 2
821
sage: a.log(0)
822
Traceback (most recent call last):
823
...
824
ArithmeticError: discrete logarithm with base 0 is not defined
825
sage: F(0).log(1)
826
Traceback (most recent call last):
827
...
828
ArithmeticError: discrete logarithm of 0 is not defined
829
"""
830
base = self._parent(base)
831
if self.is_zero():
832
raise ArithmeticError("discrete logarithm of 0 is not defined")
833
if base.is_zero():
834
raise ArithmeticError("discrete logarithm with base 0 is not defined")
835
836
# Compute the orders of self and base to check whether self
837
# actually lies in the cyclic group generated by base. PARI
838
# requires that this is the case.
839
# We also have to specify the order of the base anyway
840
# because PARI assumes by default that this element generates
841
# the multiplicative group.
842
cdef GEN x, base_order, self_order
843
pari_catch_sig_on()
844
base_order = FF_order((<FiniteFieldElement_pari_ffelt>base).val, NULL)
845
self_order = FF_order(self.val, NULL)
846
if not dvdii(base_order, self_order):
847
# self_order does not divide base_order
848
pari.clear_stack()
849
raise ArithmeticError("element %s does not lie in group generated by %s"%(self, base))
850
x = FF_log(self.val, (<FiniteFieldElement_pari_ffelt>base).val, base_order)
851
return Integer(pari.new_gen(x))
852
853
def multiplicative_order(FiniteFieldElement_pari_ffelt self):
854
"""
855
Returns the order of ``self`` in the multiplicative group.
856
857
EXAMPLE::
858
859
sage: a = FiniteField(5^3, 'a', impl='pari_ffelt').0
860
sage: a.multiplicative_order()
861
124
862
sage: a**124
863
1
864
"""
865
if self.is_zero():
866
raise ArithmeticError("Multiplicative order of 0 not defined.")
867
cdef GEN order
868
pari_catch_sig_on()
869
order = FF_order(self.val, NULL)
870
return Integer(pari.new_gen(order))
871
872
def lift(FiniteFieldElement_pari_ffelt self):
873
"""
874
If ``self`` is an element of the prime field, return a lift of
875
this element to an integer.
876
877
EXAMPLE::
878
879
sage: k = FiniteField(next_prime(10^10)^2, 'u', impl='pari_ffelt')
880
sage: a = k(17)/k(19)
881
sage: b = a.lift(); b
882
7894736858
883
sage: b.parent()
884
Integer Ring
885
"""
886
if FF_equal0(self.val):
887
return Integer(0)
888
f = self.polynomial()
889
if f.degree() == 0:
890
return f.constant_coefficient().lift()
891
else:
892
raise ValueError("element is not in the prime field")
893
894
def _integer_(self, ZZ=None):
895
"""
896
Lift to a Sage integer, if possible.
897
898
EXAMPLE::
899
900
sage: k.<a> = GF(3^17, impl='pari_ffelt')
901
sage: b = k(2)
902
sage: b._integer_()
903
2
904
sage: a._integer_()
905
Traceback (most recent call last):
906
...
907
ValueError: element is not in the prime field
908
"""
909
return self.lift()
910
911
def __int__(self):
912
"""
913
Lift to a python int, if possible.
914
915
EXAMPLE::
916
917
sage: k.<a> = GF(3^17, impl='pari_ffelt')
918
sage: b = k(2)
919
sage: int(b)
920
2
921
sage: int(a)
922
Traceback (most recent call last):
923
...
924
ValueError: element is not in the prime field
925
"""
926
return int(self.lift())
927
928
def __long__(self):
929
"""
930
Lift to a python long, if possible.
931
932
EXAMPLE::
933
934
sage: k.<a> = GF(3^17, impl='pari_ffelt')
935
sage: b = k(2)
936
sage: long(b)
937
2L
938
"""
939
return long(self.lift())
940
941
def __float__(self):
942
"""
943
Lift to a python float, if possible.
944
945
EXAMPLE::
946
947
sage: k.<a> = GF(3^17, impl='pari_ffelt')
948
sage: b = k(2)
949
sage: float(b)
950
2.0
951
"""
952
return float(self.lift())
953
954
def _pari_(self, var=None):
955
"""
956
Return a PARI object representing ``self``.
957
958
INPUT:
959
960
- var -- ignored
961
962
EXAMPLE::
963
964
sage: k.<a> = FiniteField(3^3, impl='pari_ffelt')
965
sage: b = a**2 + 2*a + 1
966
sage: b._pari_()
967
a^2 + 2*a + 1
968
"""
969
pari_catch_sig_on()
970
return pari.new_gen(self.val)
971
972
def _pari_init_(self):
973
"""
974
Return a string representing ``self`` in PARI.
975
976
EXAMPLE::
977
978
sage: k.<a> = GF(3^17, impl='pari_ffelt')
979
sage: a._pari_init_()
980
'subst(a+3*a,a,ffgen(Mod(1, 3)*x^17 + Mod(2, 3)*x + Mod(1, 3),a))'
981
sage: k(1)._pari_init_()
982
'subst(1+3*a,a,ffgen(Mod(1, 3)*x^17 + Mod(2, 3)*x + Mod(1, 3),a))'
983
984
This is used for conversion to GP. The element is displayed
985
as "a" but has correct arithmetic::
986
987
sage: gp(a)
988
a
989
sage: gp(a).type()
990
t_FFELT
991
sage: gp(a)^100
992
2*a^16 + 2*a^15 + a^4 + a + 1
993
sage: gp(a^100)
994
2*a^16 + 2*a^15 + a^4 + a + 1
995
sage: gp(k(0))
996
0
997
sage: gp(k(0)).type()
998
t_FFELT
999
"""
1000
ffgen = "ffgen(%s,a)" % self._parent.modulus()._pari_init_()
1001
# Add this "zero" to ensure that the polynomial is not constant
1002
zero = "%s*a" % self._parent.characteristic()
1003
return "subst(%s+%s,a,%s)" % (self, zero, ffgen)
1004
1005
def _magma_init_(self, magma):
1006
"""
1007
Return a string representing ``self`` in Magma.
1008
1009
EXAMPLE::
1010
1011
sage: GF(7)(3)._magma_init_(magma) # optional - magma
1012
'GF(7)!3'
1013
"""
1014
k = self._parent
1015
km = magma(k)
1016
return str(self).replace(k.variable_name(), km.gen(1).name())
1017
1018
def _gap_init_(self):
1019
r"""
1020
Return the a string representing ``self`` in GAP.
1021
1022
.. NOTE::
1023
1024
The order of the parent field must be `\leq 65536`. This
1025
function can be slow since elements of non-prime finite
1026
fields are represented in GAP as powers of a generator for
1027
the multiplicative group, so a discrete logarithm must be
1028
computed.
1029
1030
EXAMPLE::
1031
1032
sage: F = FiniteField(2^3, 'a', impl='pari_ffelt')
1033
sage: a = F.multiplicative_generator()
1034
sage: gap(a) # indirect doctest
1035
Z(2^3)
1036
sage: b = F.multiplicative_generator()
1037
sage: a = b^3
1038
sage: gap(a)
1039
Z(2^3)^3
1040
sage: gap(a^3)
1041
Z(2^3)^2
1042
1043
You can specify the instance of the Gap interpreter that is used::
1044
1045
sage: F = FiniteField(next_prime(200)^2, 'a', impl='pari_ffelt')
1046
sage: a = F.multiplicative_generator ()
1047
sage: a._gap_ (gap)
1048
Z(211^2)
1049
sage: (a^20)._gap_(gap)
1050
Z(211^2)^20
1051
1052
Gap only supports relatively small finite fields::
1053
1054
sage: F = FiniteField(next_prime(1000)^2, 'a', impl='pari_ffelt')
1055
sage: a = F.multiplicative_generator ()
1056
sage: gap._coerce_(a)
1057
Traceback (most recent call last):
1058
...
1059
TypeError: order must be at most 65536
1060
"""
1061
F = self._parent
1062
if F.order() > 65536:
1063
raise TypeError("order must be at most 65536")
1064
1065
if self == 0:
1066
return '0*Z(%s)'%F.order()
1067
assert F.degree() > 1
1068
g = F.multiplicative_generator()
1069
n = self.log(g)
1070
return 'Z(%s)^%s'%(F.order(), n)
1071
1072
1073
def unpickle_FiniteFieldElement_pari_ffelt(parent, elem):
1074
"""
1075
EXAMPLE::
1076
1077
sage: k.<a> = GF(2^20, impl='pari_ffelt')
1078
sage: e = k.random_element()
1079
sage: f = loads(dumps(e)) # indirect doctest
1080
sage: e == f
1081
True
1082
"""
1083
return parent(elem)
1084
1085