Path: blob/master/src/sage/rings/finite_rings/element_pari_ffelt.pyx
8820 views
"""1Finite field elements implemented via PARI's FFELT type23AUTHORS:45- Peter Bruin (June 2013): initial version, based on6element_ext_pari.py by William Stein et al. and7element_ntl_gf2e.pyx by Martin Albrecht.8"""910#*****************************************************************************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 of15# the License, or (at your option) any later version.16# http://www.gnu.org/licenses/17#*****************************************************************************181920include "sage/ext/stdsage.pxi"21include "sage/libs/pari/pari_err.pxi"2223from element_base cimport FinitePolyExtElement24from integer_mod import IntegerMod_abstract2526import sage.libs.pari27import sage.rings.integer28from sage.interfaces.gap import is_GapElement29from sage.libs.pari.gen cimport gen as pari_gen30from sage.libs.pari.pari_instance cimport PariInstance31from sage.modules.free_module_element import FreeModuleElement32from sage.rings.integer cimport Integer33from sage.rings.polynomial.polynomial_element import Polynomial34from sage.rings.polynomial.multi_polynomial_element import MPolynomial35from sage.rings.rational import Rational36from sage.structure.element cimport Element, ModuleElement, RingElement3738cdef long mpz_t_offset = sage.rings.integer.mpz_t_offset_python3940cdef PariInstance pari = sage.libs.pari.pari_instance.pari4142cdef extern from "sage/libs/pari/misc.h":43int gcmp_sage(GEN x, GEN y)444546cdef GEN _INT_to_FFELT(GEN g, GEN x) except NULL:47"""48Convert the t_INT `x` to an element of the field of definition of49the t_FFELT `g`.5051This function must be called within pari_catch_sig_on() ... pari_catch_sig_off().52"""53cdef GEN f, p = gel(g, 4), result54cdef long t5556x = modii(x, p)57if gequal0(x):58return FF_zero(g)59elif gequal1(x):60return FF_1(g)61else:62# In characteristic 2, we have already dealt with the63# two possible values of x, so we may assume that the64# characteristic is > 2.65t = g[1] # codeword: t_FF_FpXQ, t_FF_Flxq, t_FF_F2xq66if t == t_FF_FpXQ:67f = cgetg(3, t_POL)68set_gel(f, 1, gmael(g, 2, 1))69set_gel(f, 2, x)70elif t == t_FF_Flxq:71f = cgetg(3, t_VECSMALL)72set_gel(f, 1, gmael(g, 2, 1))73f[2] = itos(x)74else:75pari_catch_sig_off()76raise TypeError("unknown PARI finite field type")77result = cgetg(5, t_FFELT)78result[1] = t79set_gel(result, 2, f)80set_gel(result, 3, gel(g, 3)) # modulus81set_gel(result, 4, p)82return result8384cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement):85"""86An element of a finite field.8788EXAMPLE::8990sage: K = FiniteField(10007^10, 'a', impl='pari_ffelt')91sage: a = K.gen(); a92a93sage: type(a)94<type 'sage.rings.finite_rings.element_pari_ffelt.FiniteFieldElement_pari_ffelt'>9596TESTS::9798sage: n = 6399sage: m = 3;100sage: K.<a> = GF(2^n, impl='pari_ffelt')101sage: f = conway_polynomial(2, n)102sage: f(a) == 0103True104sage: e = (2^n - 1) / (2^m - 1)105sage: conway_polynomial(2, m)(a^e) == 0106True107108sage: K.<a> = FiniteField(2^16, impl='pari_ffelt')109sage: K(0).is_zero()110True111sage: (a - a).is_zero()112True113sage: a - a1140115sage: a == a116True117sage: a - a == 0118True119sage: a - a == K(0)120True121sage: TestSuite(a).run()122123Test creating elements from basic Python types::124125sage: K.<a> = FiniteField(7^20, impl='pari_ffelt')126sage: K(int(8))1271128sage: K(long(-2^300))1296130"""131132def __init__(FiniteFieldElement_pari_ffelt self, object parent, object x):133"""134Initialise ``self`` with the given ``parent`` and value135converted from ``x``.136137This is called when constructing elements from Python.138139TEST::140141sage: from sage.rings.finite_rings.element_pari_ffelt import FiniteFieldElement_pari_ffelt142sage: K = FiniteField(101^2, 'a', impl='pari_ffelt')143sage: x = FiniteFieldElement_pari_ffelt(K, 'a + 1')144sage: x145a + 1146"""147# FinitePolyExtElement.__init__(self, parent)148self._parent = parent149self.construct_from(x)150151# The Cython constructor __cinit__ is not necessary: according to152# the Cython documentation, C attributes are initialised to 0.153# def __cinit__(FiniteFieldElement_pari_ffelt self):154# self.block = NULL155156def __dealloc__(FiniteFieldElement_pari_ffelt self):157"""158Cython deconstructor.159"""160if self.block:161sage_free(self.block)162163cdef FiniteFieldElement_pari_ffelt _new(FiniteFieldElement_pari_ffelt self):164"""165Create an empty element with the same parent as ``self``.166"""167cdef FiniteFieldElement_pari_ffelt x168x = FiniteFieldElement_pari_ffelt.__new__(FiniteFieldElement_pari_ffelt)169x._parent = self._parent170return x171172cdef void construct(FiniteFieldElement_pari_ffelt self, GEN g):173"""174Initialise ``self`` to the FFELT ``g``, reset the PARI stack,175and call pari_catch_sig_off().176177This should be called exactly once on every instance.178"""179self.val = pari.deepcopy_to_python_heap(g, <pari_sp*>&self.block)180pari.clear_stack()181182cdef void construct_from(FiniteFieldElement_pari_ffelt self, object x) except *:183"""184Initialise ``self`` to an FFELT constructed from the Sage185object `x`.186"""187cdef GEN f, g, result, x_GEN188cdef long i, n, t189cdef Integer xi190191if isinstance(x, FiniteFieldElement_pari_ffelt):192if self._parent is (<FiniteFieldElement_pari_ffelt>x)._parent:193pari_catch_sig_on()194self.construct((<FiniteFieldElement_pari_ffelt>x).val)195else:196# This is where we *would* do coercion from one finite field to another...197raise TypeError("no coercion defined")198199elif isinstance(x, Integer):200g = (<pari_gen>self._parent._gen_pari).g201pari_catch_sig_on()202x_GEN = pari._new_GEN_from_mpz_t(<void *>x + mpz_t_offset)203self.construct(_INT_to_FFELT(g, x_GEN))204205elif isinstance(x, int) or isinstance(x, long):206g = (<pari_gen>self._parent._gen_pari).g207x = pari(x)208pari_catch_sig_on()209x_GEN = (<pari_gen>x).g210self.construct(_INT_to_FFELT(g, x_GEN))211212elif isinstance(x, IntegerMod_abstract):213if self._parent.characteristic().divides(x.modulus()):214g = (<pari_gen>self._parent._gen_pari).g215x = Integer(x)216pari_catch_sig_on()217x_GEN = pari._new_GEN_from_mpz_t(<void *>x + mpz_t_offset)218self.construct(_INT_to_FFELT(g, x_GEN))219else:220raise TypeError("no coercion defined")221222elif x is None:223g = (<pari_gen>self._parent._gen_pari).g224pari_catch_sig_on()225self.construct(FF_zero(g))226227elif isinstance(x, pari_gen):228g = (<pari_gen>self._parent._gen_pari).g229x_GEN = (<pari_gen>x).g230231pari_catch_sig_on()232if gequal0(x_GEN):233self.construct(FF_zero(g))234return235elif gequal1(x_GEN):236self.construct(FF_1(g))237return238239t = typ(x_GEN)240if t == t_FFELT and FF_samefield(x_GEN, g):241self.construct(x_GEN)242elif t == t_INT:243self.construct(_INT_to_FFELT(g, x_GEN))244elif t == t_INTMOD and gequal0(modii(gel(x_GEN, 1), FF_p_i(g))):245self.construct(_INT_to_FFELT(g, gel(x_GEN, 2)))246elif t == t_FRAC and not gequal0(modii(gel(x_GEN, 2), FF_p_i(g))):247self.construct(FF_div(_INT_to_FFELT(g, gel(x_GEN, 1)),248_INT_to_FFELT(g, gel(x_GEN, 2))))249else:250pari_catch_sig_off()251raise TypeError("no coercion defined")252253elif (isinstance(x, FreeModuleElement)254and x.parent() is self._parent.vector_space()):255g = (<pari_gen>self._parent._gen_pari).g256t = g[1] # codeword: t_FF_FpXQ, t_FF_Flxq, t_FF_F2xq257n = len(x)258while n > 0 and x[n - 1] == 0:259n -= 1260pari_catch_sig_on()261if n == 0:262self.construct(FF_zero(g))263return264if t == t_FF_FpXQ:265f = cgetg(n + 2, t_POL)266set_gel(f, 1, gmael(g, 2, 1))267for i in xrange(n):268xi = Integer(x[i])269set_gel(f, i + 2, pari._new_GEN_from_mpz_t(<void *>xi + mpz_t_offset))270elif t == t_FF_Flxq or t == t_FF_F2xq:271f = cgetg(n + 2, t_VECSMALL)272set_gel(f, 1, gmael(g, 2, 1))273for i in xrange(n):274f[i + 2] = x[i]275if t == t_FF_F2xq:276f = Flx_to_F2x(f)277else:278pari_catch_sig_off()279raise TypeError("unknown PARI finite field type")280result = cgetg(5, t_FFELT)281result[1] = t282set_gel(result, 2, f)283set_gel(result, 3, gel(g, 3)) # modulus284set_gel(result, 4, gel(g, 4)) # p285self.construct(result)286287elif isinstance(x, Rational):288self.construct_from(x % self._parent.characteristic())289290elif isinstance(x, Polynomial):291if x.base_ring() is not self._parent.base_ring():292x = x.change_ring(self._parent.base_ring())293self.construct_from(x.substitute(self._parent.gen()))294295elif isinstance(x, MPolynomial) and x.is_constant():296self.construct_from(x.constant_coefficient())297298elif isinstance(x, list):299if len(x) == self._parent.degree():300self.construct_from(self._parent.vector_space()(x))301else:302Fp = self._parent.base_ring()303self.construct_from(self._parent.polynomial_ring()([Fp(y) for y in x]))304305elif isinstance(x, str):306self.construct_from(self._parent.polynomial_ring()(x))307308elif is_GapElement(x):309from sage.interfaces.gap import gfq_gap_to_sage310try:311self.construct_from(gfq_gap_to_sage(x, self._parent))312except (ValueError, IndexError, TypeError):313raise TypeError("no coercion defined")314315else:316raise TypeError("no coercion defined")317318def _repr_(FiniteFieldElement_pari_ffelt self):319"""320Return the string representation of ``self``.321322EXAMPLE::323324sage: k.<c> = GF(3^17, impl='pari_ffelt')325sage: c^20 # indirect doctest326c^4 + 2*c^3327"""328pari_catch_sig_on()329return str(pari.new_gen(self.val))330331def __hash__(FiniteFieldElement_pari_ffelt self):332"""333Return the hash of ``self``. This is by definition equal to334the hash of ``self.polynomial()``.335336EXAMPLE::337338sage: k.<a> = GF(3^15, impl='pari_ffelt')339sage: R = GF(3)['a']; aa = R.gen()340sage: hash(a^2 + 1) == hash(aa^2 + 1)341True342"""343return hash(self.polynomial())344345def __reduce__(FiniteFieldElement_pari_ffelt self):346"""347For pickling.348349TEST::350351sage: K.<a> = FiniteField(10007^10, impl='pari_ffelt')352sage: loads(a.dumps()) == a353True354"""355return unpickle_FiniteFieldElement_pari_ffelt, (self._parent, str(self))356357def __copy__(FiniteFieldElement_pari_ffelt self):358"""359Return a copy of ``self``.360361TESTS::362363sage: k.<a> = FiniteField(3^3, impl='pari_ffelt')364sage: a365a366sage: b = copy(a); b367a368sage: a == b369True370sage: a is b371False372"""373cdef FiniteFieldElement_pari_ffelt x = self._new()374pari_catch_sig_on()375x.construct(self.val)376return x377378cdef int _cmp_c_impl(FiniteFieldElement_pari_ffelt self, Element other) except -2:379"""380Comparison of finite field elements.381382TESTS::383384sage: k.<a> = FiniteField(3^3, impl='pari_ffelt')385sage: a == 1386False387sage: a^0 == 1388True389sage: a == a390True391sage: a < a^2392True393sage: a > a^2394False395"""396return gcmp_sage(self.val, (<FiniteFieldElement_pari_ffelt>other).val)397398def __richcmp__(FiniteFieldElement_pari_ffelt left, object right, int op):399"""400Rich comparison of finite field elements.401402EXAMPLE::403404sage: k.<a> = GF(2^20, impl='pari_ffelt')405sage: e = k.random_element()406sage: f = loads(dumps(e))407sage: e is f408False409sage: e == f410True411sage: e != (e + 1)412True413414.. NOTE::415416Finite fields are unordered. However, for the purpose of417this function, we adopt the lexicographic ordering on the418representing polynomials.419420EXAMPLE::421422sage: K.<a> = GF(2^100, impl='pari_ffelt')423sage: a < a^2424True425sage: a > a^2426False427sage: a+1 > a^2428False429sage: a+1 < a^2430True431sage: a+1 < a432False433sage: a+1 == a434False435sage: a == a436True437"""438return (<Element>left)._richcmp(right, op)439440cpdef ModuleElement _add_(FiniteFieldElement_pari_ffelt self, ModuleElement right):441"""442Addition.443444EXAMPLE::445446sage: k.<a> = GF(3^17, impl='pari_ffelt')447sage: a + a^2 # indirect doctest448a^2 + a449"""450cdef FiniteFieldElement_pari_ffelt x = self._new()451pari_catch_sig_on()452x.construct(FF_add((<FiniteFieldElement_pari_ffelt>self).val,453(<FiniteFieldElement_pari_ffelt>right).val))454return x455456cpdef ModuleElement _sub_(FiniteFieldElement_pari_ffelt self, ModuleElement right):457"""458Subtraction.459460EXAMPLE::461462sage: k.<a> = GF(3^17, impl='pari_ffelt')463sage: a - a # indirect doctest4640465"""466cdef FiniteFieldElement_pari_ffelt x = self._new()467pari_catch_sig_on()468x.construct(FF_sub((<FiniteFieldElement_pari_ffelt>self).val,469(<FiniteFieldElement_pari_ffelt>right).val))470return x471472cpdef RingElement _mul_(FiniteFieldElement_pari_ffelt self, RingElement right):473"""474Multiplication.475476EXAMPLE::477478sage: k.<a> = GF(3^17, impl='pari_ffelt')479sage: (a^12 + 1)*(a^15 - 1) # indirect doctest480a^15 + 2*a^12 + a^11 + 2*a^10 + 2481"""482cdef FiniteFieldElement_pari_ffelt x = self._new()483pari_catch_sig_on()484x.construct(FF_mul((<FiniteFieldElement_pari_ffelt>self).val,485(<FiniteFieldElement_pari_ffelt>right).val))486return x487488cpdef RingElement _div_(FiniteFieldElement_pari_ffelt self, RingElement right):489"""490Division.491492EXAMPLE::493494sage: k.<a> = GF(3^17, impl='pari_ffelt')495sage: (a - 1) / (a + 1) # indirect doctest4962*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 + 1497"""498if FF_equal0((<FiniteFieldElement_pari_ffelt>right).val):499raise ZeroDivisionError500cdef FiniteFieldElement_pari_ffelt x = self._new()501pari_catch_sig_on()502x.construct(FF_div((<FiniteFieldElement_pari_ffelt>self).val,503(<FiniteFieldElement_pari_ffelt>right).val))504return x505506def is_zero(FiniteFieldElement_pari_ffelt self):507"""508Return ``True`` if ``self`` equals 0.509510EXAMPLE::511512sage: F.<a> = FiniteField(5^3, impl='pari_ffelt')513sage: a.is_zero()514False515sage: (a - a).is_zero()516True517"""518return bool(FF_equal0(self.val))519520def is_one(FiniteFieldElement_pari_ffelt self):521"""522Return ``True`` if ``self`` equals 1.523524EXAMPLE::525526sage: F.<a> = FiniteField(5^3, impl='pari_ffelt')527sage: a.is_one()528False529sage: (a/a).is_one()530True531"""532return bool(FF_equal1(self.val))533534def is_unit(FiniteFieldElement_pari_ffelt self):535"""536Return ``True`` if ``self`` is non-zero.537538EXAMPLE::539540sage: F.<a> = FiniteField(5^3, impl='pari_ffelt')541sage: a.is_unit()542True543"""544return not bool(FF_equal0(self.val))545546__nonzero__ = is_unit547548def __pos__(FiniteFieldElement_pari_ffelt self):549"""550Unitary positive operator...551552EXAMPLE::553554sage: k.<a> = GF(3^17, impl='pari_ffelt')555sage: +a556a557"""558return self559560def __neg__(FiniteFieldElement_pari_ffelt self):561"""562Negation.563564EXAMPLE::565566sage: k.<a> = GF(3^17, impl='pari_ffelt')567sage: -a5682*a569"""570cdef FiniteFieldElement_pari_ffelt x = self._new()571pari_catch_sig_on()572x.construct(FF_neg_i((<FiniteFieldElement_pari_ffelt>self).val))573return x574575def __invert__(FiniteFieldElement_pari_ffelt self):576"""577Return the multiplicative inverse of ``self``.578579EXAMPLE::580581sage: k.<a> = FiniteField(3^2, impl='pari_ffelt')582sage: ~a583a + 2584sage: (a+1)*a5852*a + 1586sage: ~((2*a)/a)5872588"""589if FF_equal0(self.val):590raise ZeroDivisionError591cdef FiniteFieldElement_pari_ffelt x = self._new()592pari_catch_sig_on()593x.construct(FF_inv((<FiniteFieldElement_pari_ffelt>self).val))594return x595596def __pow__(FiniteFieldElement_pari_ffelt self, object exp, object other):597"""598Exponentiation.599600TESTS::601602sage: K.<a> = GF(5^10, impl='pari_ffelt')603sage: n = (2*a)/a604sage: n^-156052606607Large exponents are not a problem::608609sage: e = 3^10000610sage: a^e6112*a^9 + a^5 + 4*a^4 + 4*a^3 + a^2 + 3*a612sage: a^(e % (5^10 - 1))6132*a^9 + a^5 + 4*a^4 + 4*a^3 + a^2 + 3*a614"""615if exp == 0:616return self._parent.one_element()617if exp < 0 and FF_equal0(self.val):618raise ZeroDivisionError619exp = pari(exp)620cdef FiniteFieldElement_pari_ffelt x = self._new()621pari_catch_sig_on()622x.construct(FF_pow(self.val, (<pari_gen>exp).g))623return x624625def polynomial(FiniteFieldElement_pari_ffelt self):626"""627Return the unique representative of ``self`` as a polynomial628over the prime field whose degree is less than the degree of629the finite field over its prime field.630631EXAMPLES::632633sage: k.<a> = FiniteField(3^2, impl='pari_ffelt')634sage: pol = a.polynomial()635sage: pol636a637sage: parent(pol)638Univariate Polynomial Ring in a over Finite Field of size 3639640::641642sage: k = FiniteField(3^4, 'alpha', impl='pari_ffelt')643sage: a = k.gen()644sage: a.polynomial()645alpha646sage: (a**2 + 1).polynomial()647alpha^2 + 1648sage: (a**2 + 1).polynomial().parent()649Univariate Polynomial Ring in alpha over Finite Field of size 3650"""651pari_catch_sig_on()652return self._parent.polynomial_ring()(pari.new_gen(FF_to_FpXQ_i(self.val)))653654def charpoly(FiniteFieldElement_pari_ffelt self, object var='x'):655"""656Return the characteristic polynomial of ``self``.657658INPUT:659660- ``var`` -- string (default: 'x'): variable name to use.661662EXAMPLE::663664sage: R.<x> = PolynomialRing(FiniteField(3))665sage: F.<a> = FiniteField(3^2, modulus=x^2 + 1)666sage: a.charpoly('y')667y^2 + 1668"""669pari_catch_sig_on()670return self._parent.polynomial_ring(var)(pari.new_gen(FF_charpoly(self.val)))671672def is_square(FiniteFieldElement_pari_ffelt self):673"""674Return ``True`` if and only if ``self`` is a square in the675finite field.676677EXAMPLES::678679sage: k.<a> = FiniteField(3^2, impl='pari_ffelt')680sage: a.is_square()681False682sage: (a**2).is_square()683True684685sage: k.<a> = FiniteField(2^2, impl='pari_ffelt')686sage: (a**2).is_square()687True688689sage: k.<a> = FiniteField(17^5, impl='pari_ffelt')690sage: (a**2).is_square()691True692sage: a.is_square()693False694sage: k(0).is_square()695True696"""697cdef long i698pari_catch_sig_on()699i = FF_issquare(self.val)700pari_catch_sig_off()701return bool(i)702703def sqrt(FiniteFieldElement_pari_ffelt self, extend=False, all=False):704"""705Return a square root of ``self``, if it exists.706707INPUT:708709- ``extend`` -- bool (default: ``False``)710711.. WARNING::712713This option is not implemented.714715- ``all`` - bool (default: ``False``)716717OUTPUT:718719A square root of ``self``, if it exists. If ``all`` is720``True``, a list containing all square roots of ``self``721(of length zero, one or two) is returned instead.722723If ``extend`` is ``True``, a square root is chosen in an724extension field if necessary. If ``extend`` is ``False``, a725ValueError is raised if the element is not a square in the726base field.727728.. WARNING::729730The ``extend`` option is not implemented (yet).731732EXAMPLES::733734sage: F = FiniteField(7^2, 'a', impl='pari_ffelt')735sage: F(2).sqrt()7364737sage: F(3).sqrt()7385*a + 1739sage: F(3).sqrt()**27403741sage: F(4).sqrt(all=True)742[2, 5]743744sage: K = FiniteField(7^3, 'alpha', impl='pari_ffelt')745sage: K(3).sqrt()746Traceback (most recent call last):747...748ValueError: element is not a square749sage: K(3).sqrt(all=True)750[]751752sage: K.<a> = GF(3^17, impl='pari_ffelt')753sage: (a^3 - a - 1).sqrt()754a^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 + 2755"""756if extend:757raise NotImplementedError758cdef GEN s759cdef FiniteFieldElement_pari_ffelt x, mx760pari_catch_sig_on()761if FF_issquareall(self.val, &s):762x = self._new()763x.construct(s)764if not all:765return x766elif gequal0(x.val) or self._parent.characteristic() == 2:767return [x]768else:769pari_catch_sig_on()770mx = self._new()771mx.construct(FF_neg_i(x.val))772return [x, mx]773else:774pari_catch_sig_off()775if all:776return []777else:778raise ValueError("element is not a square")779780def log(FiniteFieldElement_pari_ffelt self, object base):781"""782Return a discrete logarithm of ``self`` with respect to the783given base.784785INPUT:786787- ``base`` -- non-zero field element788789OUTPUT:790791An integer `x` such that ``self`` equals ``base`` raised to792the power `x`. If no such `x` exists, a ``ValueError`` is793raised.794795EXAMPLES::796797sage: F.<g> = FiniteField(2^10, impl='pari_ffelt')798sage: b = g; a = g^37799sage: a.log(b)80037801sage: b^37; a802g^8 + g^7 + g^4 + g + 1803g^8 + g^7 + g^4 + g + 1804805::806807sage: F.<a> = FiniteField(5^2, impl='pari_ffelt')808sage: F(-1).log(F(2))8092810sage: F(1).log(a)8110812813Some cases where the logarithm is not defined or does not exist::814815sage: F.<a> = GF(3^10, impl='pari_ffelt')816sage: a.log(-1)817Traceback (most recent call last):818...819ArithmeticError: element a does not lie in group generated by 2820sage: a.log(0)821Traceback (most recent call last):822...823ArithmeticError: discrete logarithm with base 0 is not defined824sage: F(0).log(1)825Traceback (most recent call last):826...827ArithmeticError: discrete logarithm of 0 is not defined828"""829base = self._parent(base)830if self.is_zero():831raise ArithmeticError("discrete logarithm of 0 is not defined")832if base.is_zero():833raise ArithmeticError("discrete logarithm with base 0 is not defined")834835# Compute the orders of self and base to check whether self836# actually lies in the cyclic group generated by base. PARI837# requires that this is the case.838# We also have to specify the order of the base anyway839# because PARI assumes by default that this element generates840# the multiplicative group.841cdef GEN x, base_order, self_order842pari_catch_sig_on()843base_order = FF_order((<FiniteFieldElement_pari_ffelt>base).val, NULL)844self_order = FF_order(self.val, NULL)845if not dvdii(base_order, self_order):846# self_order does not divide base_order847pari.clear_stack()848raise ArithmeticError("element %s does not lie in group generated by %s"%(self, base))849x = FF_log(self.val, (<FiniteFieldElement_pari_ffelt>base).val, base_order)850return Integer(pari.new_gen(x))851852def multiplicative_order(FiniteFieldElement_pari_ffelt self):853"""854Returns the order of ``self`` in the multiplicative group.855856EXAMPLE::857858sage: a = FiniteField(5^3, 'a', impl='pari_ffelt').0859sage: a.multiplicative_order()860124861sage: a**1248621863"""864if self.is_zero():865raise ArithmeticError("Multiplicative order of 0 not defined.")866cdef GEN order867pari_catch_sig_on()868order = FF_order(self.val, NULL)869return Integer(pari.new_gen(order))870871def lift(FiniteFieldElement_pari_ffelt self):872"""873If ``self`` is an element of the prime field, return a lift of874this element to an integer.875876EXAMPLE::877878sage: k = FiniteField(next_prime(10^10)^2, 'u', impl='pari_ffelt')879sage: a = k(17)/k(19)880sage: b = a.lift(); b8817894736858882sage: b.parent()883Integer Ring884"""885if FF_equal0(self.val):886return Integer(0)887f = self.polynomial()888if f.degree() == 0:889return f.constant_coefficient().lift()890else:891raise ValueError("element is not in the prime field")892893def _integer_(self, ZZ=None):894"""895Lift to a Sage integer, if possible.896897EXAMPLE::898899sage: k.<a> = GF(3^17, impl='pari_ffelt')900sage: b = k(2)901sage: b._integer_()9022903sage: a._integer_()904Traceback (most recent call last):905...906ValueError: element is not in the prime field907"""908return self.lift()909910def __int__(self):911"""912Lift to a python int, if possible.913914EXAMPLE::915916sage: k.<a> = GF(3^17, impl='pari_ffelt')917sage: b = k(2)918sage: int(b)9192920sage: int(a)921Traceback (most recent call last):922...923ValueError: element is not in the prime field924"""925return int(self.lift())926927def __long__(self):928"""929Lift to a python long, if possible.930931EXAMPLE::932933sage: k.<a> = GF(3^17, impl='pari_ffelt')934sage: b = k(2)935sage: long(b)9362L937"""938return long(self.lift())939940def __float__(self):941"""942Lift to a python float, if possible.943944EXAMPLE::945946sage: k.<a> = GF(3^17, impl='pari_ffelt')947sage: b = k(2)948sage: float(b)9492.0950"""951return float(self.lift())952953def _pari_(self, var=None):954"""955Return a PARI object representing ``self``.956957INPUT:958959- var -- ignored960961EXAMPLE::962963sage: k.<a> = FiniteField(3^3, impl='pari_ffelt')964sage: b = a**2 + 2*a + 1965sage: b._pari_()966a^2 + 2*a + 1967"""968pari_catch_sig_on()969return pari.new_gen(self.val)970971def _pari_init_(self):972"""973Return a string representing ``self`` in PARI.974975EXAMPLE::976977sage: k.<a> = GF(3^17, impl='pari_ffelt')978sage: a._pari_init_()979'subst(a+3*a,a,ffgen(Mod(1, 3)*x^17 + Mod(2, 3)*x + Mod(1, 3),a))'980sage: k(1)._pari_init_()981'subst(1+3*a,a,ffgen(Mod(1, 3)*x^17 + Mod(2, 3)*x + Mod(1, 3),a))'982983This is used for conversion to GP. The element is displayed984as "a" but has correct arithmetic::985986sage: gp(a)987a988sage: gp(a).type()989t_FFELT990sage: gp(a)^1009912*a^16 + 2*a^15 + a^4 + a + 1992sage: gp(a^100)9932*a^16 + 2*a^15 + a^4 + a + 1994sage: gp(k(0))9950996sage: gp(k(0)).type()997t_FFELT998"""999ffgen = "ffgen(%s,a)" % self._parent.modulus()._pari_init_()1000# Add this "zero" to ensure that the polynomial is not constant1001zero = "%s*a" % self._parent.characteristic()1002return "subst(%s+%s,a,%s)" % (self, zero, ffgen)10031004def _magma_init_(self, magma):1005"""1006Return a string representing ``self`` in Magma.10071008EXAMPLE::10091010sage: GF(7)(3)._magma_init_(magma) # optional - magma1011'GF(7)!3'1012"""1013k = self._parent1014km = magma(k)1015return str(self).replace(k.variable_name(), km.gen(1).name())10161017def _gap_init_(self):1018r"""1019Return the a string representing ``self`` in GAP.10201021.. NOTE::10221023The order of the parent field must be `\leq 65536`. This1024function can be slow since elements of non-prime finite1025fields are represented in GAP as powers of a generator for1026the multiplicative group, so a discrete logarithm must be1027computed.10281029EXAMPLE::10301031sage: F = FiniteField(2^3, 'a', impl='pari_ffelt')1032sage: a = F.multiplicative_generator()1033sage: gap(a) # indirect doctest1034Z(2^3)1035sage: b = F.multiplicative_generator()1036sage: a = b^31037sage: gap(a)1038Z(2^3)^31039sage: gap(a^3)1040Z(2^3)^210411042You can specify the instance of the Gap interpreter that is used::10431044sage: F = FiniteField(next_prime(200)^2, 'a', impl='pari_ffelt')1045sage: a = F.multiplicative_generator ()1046sage: a._gap_ (gap)1047Z(211^2)1048sage: (a^20)._gap_(gap)1049Z(211^2)^2010501051Gap only supports relatively small finite fields::10521053sage: F = FiniteField(next_prime(1000)^2, 'a', impl='pari_ffelt')1054sage: a = F.multiplicative_generator ()1055sage: gap._coerce_(a)1056Traceback (most recent call last):1057...1058TypeError: order must be at most 655361059"""1060F = self._parent1061if F.order() > 65536:1062raise TypeError("order must be at most 65536")10631064if self == 0:1065return '0*Z(%s)'%F.order()1066assert F.degree() > 11067g = F.multiplicative_generator()1068n = self.log(g)1069return 'Z(%s)^%s'%(F.order(), n)107010711072def unpickle_FiniteFieldElement_pari_ffelt(parent, elem):1073"""1074EXAMPLE::10751076sage: k.<a> = GF(2^20, impl='pari_ffelt')1077sage: e = k.random_element()1078sage: f = loads(dumps(e)) # indirect doctest1079sage: e == f1080True1081"""1082return parent(elem)108310841085