Ticket #12142: trac_12142-FiniteField_pari_ffelt.improved.patch

File trac_12142-FiniteField_pari_ffelt.improved.patch, 54.7 KB (added by pbruin, 10 years ago)

more speedups in element construction; initialisation from None allowed

  • doc/en/reference/finite_rings/index.rst

    # HG changeset patch
    # User Peter Bruin <peter.bruin@math.uzh.ch>
    # Date 1372107280 -7200
    # Node ID 0867b39b56bca1f0fec34057b502941009c4171d
    # Parent  ce97cf0df86b90a9aa618620635e449b835eedec
    Trac 12142: finite fields using PARI's FFELT type
    
    diff --git a/doc/en/reference/finite_rings/index.rst b/doc/en/reference/finite_rings/index.rst
    a b  
    66
    77   sage/rings/finite_rings/element_givaro
    88   sage/rings/finite_rings/element_ntl_gf2e
     9   sage/rings/finite_rings/element_pari_ffelt
    910   sage/rings/finite_rings/finite_field_base
    1011   sage/rings/finite_rings/finite_field_ext_pari
    1112   sage/rings/finite_rings/finite_field_givaro
    1213   sage/rings/finite_rings/finite_field_ntl_gf2e
     14   sage/rings/finite_rings/finite_field_pari_ffelt
    1315   sage/rings/finite_rings/finite_field_prime_modn
    1416   sage/rings/finite_rings/homset
    1517
  • module_list.py

    diff --git a/module_list.py b/module_list.py
    a b  
    15521552              libraries = ['ntl', 'gmp'],
    15531553              language = 'c++'),
    15541554
     1555    Extension('sage.rings.finite_rings.element_pari_ffelt',
     1556              sources = ['sage/rings/finite_rings/element_pari_ffelt.pyx'],
     1557              libraries = ['pari', 'gmp']),
     1558
    15551559        ################################
    15561560        ##
    15571561        ## sage.rings.function_field
  • sage/rings/finite_rings/constructor.py

    diff --git a/sage/rings/finite_rings/constructor.py b/sage/rings/finite_rings/constructor.py
    a b  
    434434                        raise ValueError("The degree of the modulus does not correspond to the cardinality of the field.")
    435435                if name is None:
    436436                    raise TypeError("you must specify the generator name.")
    437                 if order < zech_log_bound: 
    438                     # DO *NOT* use for prime subfield, since that would lead to
    439                     # a circular reference in the call to ParentWithGens in the
    440                     # __init__ method.
     437                if impl is None:
     438                    if order < zech_log_bound:
     439                        # DO *NOT* use for prime subfield, since that would lead to
     440                        # a circular reference in the call to ParentWithGens in the
     441                        # __init__ method.
     442                        impl = 'givaro'
     443                    elif order % 2 == 0:
     444                        impl = 'ntl'
     445                    else:
     446                        impl = 'pari_mod'
     447                if impl == 'givaro':
    441448                    K = FiniteField_givaro(order, name, modulus, cache=elem_cache,**kwds)
     449                elif impl == 'ntl':
     450                    from finite_field_ntl_gf2e import FiniteField_ntl_gf2e
     451                    K = FiniteField_ntl_gf2e(order, name, modulus, **kwds)
     452                elif impl == 'pari_ffelt':
     453                    from finite_field_pari_ffelt import FiniteField_pari_ffelt
     454                    K = FiniteField_pari_ffelt(p, modulus, name, **kwds)
     455                elif (impl == 'pari_mod'
     456                      or impl == 'pari'):    # for unpickling old pickles
     457                    from finite_field_ext_pari import FiniteField_ext_pari
     458                    K = FiniteField_ext_pari(order, name, modulus, **kwds)
    442459                else:
    443                     if order % 2 == 0 and (impl is None or impl == 'ntl'):
    444                         from finite_field_ntl_gf2e import FiniteField_ntl_gf2e
    445                         K = FiniteField_ntl_gf2e(order, name, modulus, **kwds)
    446                     else:
    447                         from finite_field_ext_pari import FiniteField_ext_pari
    448                         K = FiniteField_ext_pari(order, name, modulus, **kwds)
     460                    raise ValueError("no such finite field implementation: %s" % impl)
    449461
    450462        return K
    451463
     
    481493            else:
    482494                from finite_field_ntl_gf2e import FiniteField_ntl_gf2e
    483495                from finite_field_ext_pari import FiniteField_ext_pari
     496                from finite_field_pari_ffelt import FiniteField_pari_ffelt
    484497                if isinstance(K, FiniteField_ntl_gf2e):
    485498                    impl = 'ntl'
    486499                elif isinstance(K, FiniteField_ext_pari):
    487                     impl = 'pari'
     500                    impl = 'pari_mod'
     501                elif isinstance(K, FiniteField_pari_ffelt):
     502                    impl = 'pari_ffelt'
    488503            new_keys.append( (order, name, modulus, impl, _, p, n, proof) )
    489504            return new_keys
    490505
  • new file sage/rings/finite_rings/element_pari_ffelt.pxd

    diff --git a/sage/rings/finite_rings/element_pari_ffelt.pxd b/sage/rings/finite_rings/element_pari_ffelt.pxd
    new file mode 100644
    - +  
     1include "sage/libs/pari/decl.pxi"
     2
     3from sage.rings.finite_rings.element_base cimport FinitePolyExtElement
     4
     5cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement):
     6    cdef GEN val        # PARI t_FFELT describing the element
     7    cdef void *block    # memory block containing the data
     8    cdef FiniteFieldElement_pari_ffelt _new(FiniteFieldElement_pari_ffelt self)
     9    cdef void construct(FiniteFieldElement_pari_ffelt self, GEN g)
     10    cdef void construct_from(FiniteFieldElement_pari_ffelt self, object x) except *
  • new file sage/rings/finite_rings/element_pari_ffelt.pyx

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

    diff --git a/sage/rings/finite_rings/finite_field_pari_ffelt.py b/sage/rings/finite_rings/finite_field_pari_ffelt.py
    new file mode 100644
    - +  
     1"""
     2Finite fields implemented via PARI's FFELT type
     3
     4AUTHORS:
     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 <peter.bruin@math.uzh.ch>
     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
     20from element_pari_ffelt import FiniteFieldElement_pari_ffelt
     21from finite_field_base import FiniteField
     22
     23
     24class 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 _coerce_map_from_(self, R):
     504        """
     505        Canonical coercion to ``self``.
     506
     507        EXAMPLES::
     508
     509            sage: FiniteField(2^2, 'a', impl='pari_ffelt')._coerce_(GF(2)(1)) # indirect doctest
     510            1
     511            sage: k = FiniteField(2^2, 'a', impl='pari_ffelt')
     512            sage: k._coerce_(k.0)
     513            a
     514            sage: FiniteField(2^2, 'a', impl='pari_ffelt')._coerce_(3)
     515            1
     516            sage: FiniteField(2^2, 'a', impl='pari_ffelt')._coerce_(2/3)
     517            Traceback (most recent call last):
     518            ...
     519            TypeError: no canonical coercion from Rational Field to Finite Field in a of size 2^2
     520            sage: FiniteField(2^3, 'a', impl='pari_ffelt')._coerce_(FiniteField(2^2, 'a', impl='pari_ffelt').0)
     521            Traceback (most recent call last):
     522            ...
     523            TypeError: no canonical coercion from Finite Field in a of size 2^2 to Finite Field in a of size 2^3
     524            sage: FiniteField(2^4, 'a', impl='pari_ffelt')._coerce_(FiniteField(2^2, 'a', impl='pari_ffelt').0)
     525            Traceback (most recent call last):
     526            ...
     527            TypeError: no canonical coercion from Finite Field in a of size 2^2 to Finite Field in a of size 2^4
     528            sage: k = FiniteField(2^3, 'a', impl='pari_ffelt')
     529            sage: k._coerce_(FiniteField(7, 'a')(2))
     530            Traceback (most recent call last):
     531            ...
     532            TypeError: no canonical coercion from Finite Field of size 7 to Finite Field in a of size 2^3
     533        """
     534        from integer_mod_ring import is_IntegerModRing
     535        from sage.rings.integer_ring import ZZ
     536        if R is int or R is long or R is ZZ:
     537            return True
     538        if isinstance(R, FiniteField_pari_ffelt):
     539            if R is self:
     540                return True
     541            if R.characteristic() == self.characteristic():
     542                if R.degree() == 1:
     543                    return True
     544                elif R.degree().divides(self.degree()):
     545                    # TODO: This is where we *would* do coercion from one nontrivial finite field to another...
     546                    return False
     547        if is_IntegerModRing(R) and self.characteristic().divides(R.characteristic()):
     548            return True
     549
     550    def order(self):
     551        """
     552        The number of elements of the finite field.
     553
     554        EXAMPLE::
     555
     556            sage: k = FiniteField(2^10, 'a', impl='pari_ffelt')
     557            sage: k
     558            Finite Field in a of size 2^10
     559            sage: k.order()
     560            1024
     561        """
     562        return self._card