Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Finite field elements implemented via PARI's FFELT type
AUTHORS:
- Peter Bruin (June 2013): initial version, based on element_ext_pari.py by William Stein et al. and element_ntl_gf2e.pyx by Martin Albrecht. """
#***************************************************************************** # Copyright (C) 2013 Peter Bruin <peter.bruin@math.uzh.ch> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import absolute_import
from cysignals.memory cimport sig_free from cysignals.signals cimport sig_on, sig_off
from cypari2.paridecl cimport * from cypari2.paripriv cimport * from sage.libs.pari.convert_gmp cimport _new_GEN_from_mpz_t from cypari2.stack cimport new_gen, clear_stack, deepcopy_to_python_heap from cypari2.gen cimport Gen as pari_gen, objtogen
from .element_base cimport FinitePolyExtElement from .integer_mod import IntegerMod_abstract
import sage.rings.integer from sage.interfaces.gap import is_GapElement from sage.modules.free_module_element import FreeModuleElement from sage.rings.integer cimport Integer from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.multi_polynomial_element import MPolynomial from sage.rings.rational import Rational from sage.structure.element cimport Element, ModuleElement, RingElement
cdef GEN _INT_to_FFELT(GEN g, GEN x) except NULL: """ Convert the t_INT `x` to an element of the field of definition of the t_FFELT `g`.
This function must be called within ``sig_on()`` ... ``sig_off()``.
TESTS:
Converting large integers to finite field elements does not lead to overflow errors (see :trac:`16807`)::
sage: p = previous_prime(2^64) sage: F.<x> = GF(p^2) sage: x * 2^63 9223372036854775808*x
""" cdef long t
else: # In characteristic 2, we have already dealt with the # two possible values of x, so we may assume that the # characteristic is > 2. else: sig_off() raise TypeError("unknown PARI finite field type")
cdef class FiniteFieldElement_pari_ffelt(FinitePolyExtElement): """ An element of a finite field.
EXAMPLES::
sage: K = FiniteField(10007^10, 'a', impl='pari_ffelt') sage: a = K.gen(); a a sage: type(a) <type 'sage.rings.finite_rings.element_pari_ffelt.FiniteFieldElement_pari_ffelt'>
TESTS::
sage: n = 63 sage: m = 3; sage: K.<a> = GF(2^n, impl='pari_ffelt') sage: f = conway_polynomial(2, n) sage: f(a) == 0 True sage: e = (2^n - 1) / (2^m - 1) sage: conway_polynomial(2, m)(a^e) == 0 True
sage: K.<a> = FiniteField(2^16, impl='pari_ffelt') sage: K(0).is_zero() True sage: (a - a).is_zero() True sage: a - a 0 sage: a == a True sage: a - a == 0 True sage: a - a == K(0) True sage: TestSuite(a).run()
Test creating elements from basic Python types::
sage: K.<a> = FiniteField(7^20, impl='pari_ffelt') sage: K(int(8)) 1 sage: K(long(-2^300)) 6 """
def __init__(FiniteFieldElement_pari_ffelt self, object parent, object x): """ Initialise ``self`` with the given ``parent`` and value converted from ``x``.
This is called when constructing elements from Python.
TESTS::
sage: from sage.rings.finite_rings.element_pari_ffelt import FiniteFieldElement_pari_ffelt sage: K = FiniteField(101^2, 'a', impl='pari_ffelt') sage: x = FiniteFieldElement_pari_ffelt(K, 'a + 1') sage: x a + 1 """ # FinitePolyExtElement.__init__(self, parent)
def __dealloc__(FiniteFieldElement_pari_ffelt self): """ Cython deconstructor. """
cdef FiniteFieldElement_pari_ffelt _new(FiniteFieldElement_pari_ffelt self): """ Create an empty element with the same parent as ``self``. """ cdef FiniteFieldElement_pari_ffelt x
cdef void construct(FiniteFieldElement_pari_ffelt self, GEN g): """ Initialise ``self`` to the FFELT ``g``, reset the PARI stack, and call sig_off().
This should be called exactly once on every instance. """
cdef void construct_from(FiniteFieldElement_pari_ffelt self, object x) except *: """ Initialise ``self`` to an FFELT constructed from the Sage object `x`.
TESTS:
Conversion of elements of the underlying vector space works in large characteristic (see :trac:`21186`)::
sage: p = 13189065031705623239 sage: Fq = FiniteField(p^3, "a") sage: Fq_X = PolynomialRing(Fq, "x") sage: pol = Fq_X("x^9 + 13189065031705622723*x^7 + 13189065031705622723*x^6 + 9288*x^5 + 18576*x^4 + 13189065031705590731*x^3 + 13189065031705497851*x^2 + 13189065031705497851*x + 13189065031705581443") sage: R = [r[0] for r in pol.roots()] sage: prod(Fq_X.gen() - r for r in R) == pol True
""" cdef GEN f, g, result, x_GEN cdef long i, n, t cdef Integer xi
else: raise TypeError("no coercion defined")
else: raise TypeError("no coercion defined")
elif t == t_INTMOD and gequal0(modii(gel(x_GEN, 1), FF_p_i(g))): self.construct(_INT_to_FFELT(g, gel(x_GEN, 2))) elif t == t_FRAC and not gequal0(modii(gel(x_GEN, 2), FF_p_i(g))): self.construct(FF_div(_INT_to_FFELT(g, gel(x_GEN, 1)), _INT_to_FFELT(g, gel(x_GEN, 2)))) else: sig_off() raise TypeError("no coercion defined")
else: sig_off() raise TypeError("unknown PARI finite field type")
else:
except (ValueError, IndexError, TypeError): raise TypeError("no coercion defined")
else:
def _repr_(FiniteFieldElement_pari_ffelt self): """ Return the string representation of ``self``.
EXAMPLES::
sage: k.<c> = GF(3^17, impl='pari_ffelt') sage: c^20 # indirect doctest c^4 + 2*c^3 """
def __hash__(FiniteFieldElement_pari_ffelt self): """ Return the hash of ``self``. This is by definition equal to the hash of ``self.polynomial()``.
EXAMPLES::
sage: k.<a> = GF(3^15, impl='pari_ffelt') sage: R = GF(3)['a']; aa = R.gen() sage: hash(a^2 + 1) == hash(aa^2 + 1) True """
def __reduce__(FiniteFieldElement_pari_ffelt self): """ For pickling.
TESTS::
sage: K.<a> = FiniteField(10007^10, impl='pari_ffelt') sage: loads(a.dumps()) == a True """
def __copy__(FiniteFieldElement_pari_ffelt self): """ Return a copy of ``self``.
TESTS::
sage: k.<a> = FiniteField(3^3, impl='pari_ffelt') sage: a a sage: b = copy(a); b a sage: a == b True sage: a is b False """
cpdef int _cmp_(self, other) except -2: """ Comparison of finite field elements.
.. NOTE::
Finite fields are unordered. However, for the purpose of this function, we adopt the lexicographic ordering on the representing polynomials.
EXAMPLES::
sage: k.<a> = GF(2^20, impl='pari_ffelt') sage: e = k.random_element() sage: f = loads(dumps(e)) sage: e is f False sage: e == f True sage: e != (e + 1) True
::
sage: K.<a> = GF(2^100, impl='pari_ffelt') sage: a < a^2 True sage: a > a^2 False sage: a+1 > a^2 False sage: a+1 < a^2 True sage: a+1 < a False sage: a+1 == a False sage: a == a True
TESTS::
sage: k.<a> = FiniteField(3^3, impl='pari_ffelt') sage: a == 1 False sage: a^0 == 1 True sage: a == a True sage: a < a^2 True sage: a > a^2 False """ cdef int r
cpdef _add_(self, right): """ Addition.
EXAMPLES::
sage: k.<a> = GF(3^17, impl='pari_ffelt') sage: a + a^2 # indirect doctest a^2 + a """ (<FiniteFieldElement_pari_ffelt>right).val))
cpdef _sub_(self, right): """ Subtraction.
EXAMPLES::
sage: k.<a> = GF(3^17, impl='pari_ffelt') sage: a - a # indirect doctest 0 """ (<FiniteFieldElement_pari_ffelt>right).val))
cpdef _mul_(self, right): """ Multiplication.
EXAMPLES::
sage: k.<a> = GF(3^17, impl='pari_ffelt') sage: (a^12 + 1)*(a^15 - 1) # indirect doctest a^15 + 2*a^12 + a^11 + 2*a^10 + 2 """ (<FiniteFieldElement_pari_ffelt>right).val))
cpdef _div_(self, right): """ Division.
EXAMPLES::
sage: k.<a> = GF(3^17, impl='pari_ffelt') sage: (a - 1) / (a + 1) # indirect doctest 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 """ raise ZeroDivisionError (<FiniteFieldElement_pari_ffelt>right).val))
def is_zero(FiniteFieldElement_pari_ffelt self): """ Return ``True`` if ``self`` equals 0.
EXAMPLES::
sage: F.<a> = FiniteField(5^3, impl='pari_ffelt') sage: a.is_zero() False sage: (a - a).is_zero() True """
def is_one(FiniteFieldElement_pari_ffelt self): """ Return ``True`` if ``self`` equals 1.
EXAMPLES::
sage: F.<a> = FiniteField(5^3, impl='pari_ffelt') sage: a.is_one() False sage: (a/a).is_one() True """
def is_unit(FiniteFieldElement_pari_ffelt self): """ Return ``True`` if ``self`` is non-zero.
EXAMPLES::
sage: F.<a> = FiniteField(5^3, impl='pari_ffelt') sage: a.is_unit() True """
__nonzero__ = is_unit
def __pos__(FiniteFieldElement_pari_ffelt self): """ Unitary positive operator...
EXAMPLES::
sage: k.<a> = GF(3^17, impl='pari_ffelt') sage: +a a """
def __neg__(FiniteFieldElement_pari_ffelt self): """ Negation.
EXAMPLES::
sage: k.<a> = GF(3^17, impl='pari_ffelt') sage: -a 2*a """
def __invert__(FiniteFieldElement_pari_ffelt self): """ Return the multiplicative inverse of ``self``.
EXAMPLES::
sage: k.<a> = FiniteField(3^2, impl='pari_ffelt') sage: ~a a + 2 sage: (a+1)*a 2*a + 1 sage: ~((2*a)/a) 2 """ raise ZeroDivisionError
def __pow__(FiniteFieldElement_pari_ffelt self, object exp, object other): """ Exponentiation.
TESTS::
sage: K.<a> = GF(5^10, impl='pari_ffelt') sage: n = (2*a)/a sage: n^-15 2
Large exponents are not a problem::
sage: e = 3^10000 sage: a^e 2*a^9 + a^5 + 4*a^4 + 4*a^3 + a^2 + 3*a sage: a^(e % (5^10 - 1)) 2*a^9 + a^5 + 4*a^4 + 4*a^3 + a^2 + 3*a
The exponent is converted to an integer (see :trac:`16540`)::
sage: q = 11^23 sage: F.<a> = FiniteField(q) sage: a^Mod(1, q - 1) a
.. WARNING::
For efficiency reasons, we do not verify that the exponentiation is well defined before converting the exponent to an integer. This means that ``a^Mod(1, n)`` returns `a` even if `n` is not a multiple of the multiplicative order of `a`.
""" raise ZeroDivisionError
def polynomial(FiniteFieldElement_pari_ffelt self, name=None): """ Return the unique representative of ``self`` as a polynomial over the prime field whose degree is less than the degree of the finite field over its prime field.
INPUT:
- ``name`` -- (optional) variable name
EXAMPLES::
sage: k.<a> = FiniteField(3^2, impl='pari_ffelt') sage: pol = a.polynomial() sage: pol a sage: parent(pol) Univariate Polynomial Ring in a over Finite Field of size 3
::
sage: k = FiniteField(3^4, 'alpha', impl='pari_ffelt') sage: a = k.gen() sage: a.polynomial() alpha sage: (a**2 + 1).polynomial('beta') beta^2 + 1 sage: (a**2 + 1).polynomial().parent() Univariate Polynomial Ring in alpha over Finite Field of size 3 sage: (a**2 + 1).polynomial('beta').parent() Univariate Polynomial Ring in beta over Finite Field of size 3 """
def minpoly(self, var='x'): """ Return the minimal polynomial of ``self``.
INPUT:
- ``var`` -- string (default: 'x'): variable name to use.
EXAMPLES::
sage: R.<x> = PolynomialRing(FiniteField(3)) sage: F.<a> = FiniteField(3^2, modulus=x^2 + 1, impl='pari_ffelt') sage: a.minpoly('y') y^2 + 1 """
def charpoly(FiniteFieldElement_pari_ffelt self, object var='x'): """ Return the characteristic polynomial of ``self``.
INPUT:
- ``var`` -- string (default: 'x'): variable name to use.
EXAMPLES::
sage: R.<x> = PolynomialRing(FiniteField(3)) sage: F.<a> = FiniteField(3^2, modulus=x^2 + 1, impl='pari_ffelt') sage: a.charpoly('y') y^2 + 1 """
def is_square(FiniteFieldElement_pari_ffelt self): """ Return ``True`` if and only if ``self`` is a square in the finite field.
EXAMPLES::
sage: k.<a> = FiniteField(3^2, impl='pari_ffelt') sage: a.is_square() False sage: (a**2).is_square() True
sage: k.<a> = FiniteField(2^2, impl='pari_ffelt') sage: (a**2).is_square() True
sage: k.<a> = FiniteField(17^5, impl='pari_ffelt') sage: (a**2).is_square() True sage: a.is_square() False sage: k(0).is_square() True """ cdef long i
def sqrt(FiniteFieldElement_pari_ffelt self, extend=False, all=False): """ Return a square root of ``self``, if it exists.
INPUT:
- ``extend`` -- bool (default: ``False``)
.. WARNING::
This option is not implemented.
- ``all`` - bool (default: ``False``)
OUTPUT:
A square root of ``self``, if it exists. If ``all`` is ``True``, a list containing all square roots of ``self`` (of length zero, one or two) is returned instead.
If ``extend`` is ``True``, a square root is chosen in an extension field if necessary. If ``extend`` is ``False``, a ValueError is raised if the element is not a square in the base field.
.. WARNING::
The ``extend`` option is not implemented (yet).
EXAMPLES::
sage: F = FiniteField(7^2, 'a', impl='pari_ffelt') sage: F(2).sqrt() 4 sage: F(3).sqrt() in (2*F.gen() + 6, 5*F.gen() + 1) True sage: F(3).sqrt()**2 3 sage: F(4).sqrt(all=True) [2, 5]
sage: K = FiniteField(7^3, 'alpha', impl='pari_ffelt') sage: K(3).sqrt() Traceback (most recent call last): ... ValueError: element is not a square sage: K(3).sqrt(all=True) []
sage: K.<a> = GF(3^17, impl='pari_ffelt') sage: (a^3 - a - 1).sqrt() 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 """ raise NotImplementedError cdef GEN s cdef FiniteFieldElement_pari_ffelt x, mx else: else: else:
def log(FiniteFieldElement_pari_ffelt self, object base): """ Return a discrete logarithm of ``self`` with respect to the given base.
INPUT:
- ``base`` -- non-zero field element
OUTPUT:
An integer `x` such that ``self`` equals ``base`` raised to the power `x`. If no such `x` exists, a ``ValueError`` is raised.
EXAMPLES::
sage: F.<g> = FiniteField(2^10, impl='pari_ffelt') sage: b = g; a = g^37 sage: a.log(b) 37 sage: b^37; a g^8 + g^7 + g^4 + g + 1 g^8 + g^7 + g^4 + g + 1
::
sage: F.<a> = FiniteField(5^2, impl='pari_ffelt') sage: F(-1).log(F(2)) 2 sage: F(1).log(a) 0
Some cases where the logarithm is not defined or does not exist::
sage: F.<a> = GF(3^10, impl='pari_ffelt') sage: a.log(-1) Traceback (most recent call last): ... ArithmeticError: element a does not lie in group generated by 2 sage: a.log(0) Traceback (most recent call last): ... ArithmeticError: discrete logarithm with base 0 is not defined sage: F(0).log(1) Traceback (most recent call last): ... ArithmeticError: discrete logarithm of 0 is not defined """
# Compute the orders of self and base to check whether self # actually lies in the cyclic group generated by base. PARI # requires that this is the case. # We also have to specify the order of the base anyway # because PARI assumes by default that this element generates # the multiplicative group. cdef GEN x, base_order, self_order # self_order does not divide base_order
def multiplicative_order(FiniteFieldElement_pari_ffelt self): """ Returns the order of ``self`` in the multiplicative group.
EXAMPLES::
sage: a = FiniteField(5^3, 'a', impl='pari_ffelt').0 sage: a.multiplicative_order() 124 sage: a**124 1 """ raise ArithmeticError("Multiplicative order of 0 not defined.") cdef GEN order
def lift(FiniteFieldElement_pari_ffelt self): """ If ``self`` is an element of the prime field, return a lift of this element to an integer.
EXAMPLES::
sage: k = FiniteField(next_prime(10^10)^2, 'u', impl='pari_ffelt') sage: a = k(17)/k(19) sage: b = a.lift(); b 7894736858 sage: b.parent() Integer Ring """ else:
def _integer_(self, ZZ=None): """ Lift to a Sage integer, if possible.
EXAMPLES::
sage: k.<a> = GF(3^17, impl='pari_ffelt') sage: b = k(2) sage: b._integer_() 2 sage: a._integer_() Traceback (most recent call last): ... ValueError: element is not in the prime field """
def __int__(self): """ Lift to a python int, if possible.
EXAMPLES::
sage: k.<a> = GF(3^17, impl='pari_ffelt') sage: b = k(2) sage: int(b) 2 sage: int(a) Traceback (most recent call last): ... ValueError: element is not in the prime field """
def __long__(self): """ Lift to a python long, if possible.
EXAMPLES::
sage: k.<a> = GF(3^17, impl='pari_ffelt') sage: b = k(2) sage: long(b) 2L """
def __float__(self): """ Lift to a python float, if possible.
EXAMPLES::
sage: k.<a> = GF(3^17, impl='pari_ffelt') sage: b = k(2) sage: float(b) 2.0 """
def __pari__(self, var=None): """ Return a PARI object representing ``self``.
INPUT:
- var -- ignored
EXAMPLES::
sage: k.<a> = FiniteField(3^3, impl='pari_ffelt') sage: b = a**2 + 2*a + 1 sage: b.__pari__() a^2 + 2*a + 1 """
def _pari_init_(self): """ Return a string representing ``self`` in PARI.
EXAMPLES::
sage: k.<a> = GF(3^17, impl='pari_ffelt') sage: a._pari_init_() 'subst(a+3*a,a,ffgen(Mod(1, 3)*x^17 + Mod(2, 3)*x + Mod(1, 3),a))' sage: k(1)._pari_init_() 'subst(1+3*a,a,ffgen(Mod(1, 3)*x^17 + Mod(2, 3)*x + Mod(1, 3),a))'
This is used for conversion to GP. The element is displayed as "a" but has correct arithmetic::
sage: gp(a) a sage: gp(a).type() t_FFELT sage: gp(a)^100 2*a^16 + 2*a^15 + a^4 + a + 1 sage: gp(a^100) 2*a^16 + 2*a^15 + a^4 + a + 1 sage: gp(k(0)) 0 sage: gp(k(0)).type() t_FFELT """ # Add this "zero" to ensure that the polynomial is not constant
def _magma_init_(self, magma): """ Return a string representing ``self`` in Magma.
EXAMPLES::
sage: GF(7)(3)._magma_init_(magma) # optional - magma 'GF(7)!3' """ k = self._parent km = magma(k) return str(self).replace(k.variable_name(), km.gen(1).name())
def _gap_init_(self): r""" Return the a string representing ``self`` in GAP.
.. NOTE::
The order of the parent field must be `\leq 65536`. This function can be slow since elements of non-prime finite fields are represented in GAP as powers of a generator for the multiplicative group, so a discrete logarithm must be computed.
EXAMPLES::
sage: F = FiniteField(2^3, 'a', impl='pari_ffelt') sage: a = F.multiplicative_generator() sage: gap(a) # indirect doctest Z(2^3) sage: b = F.multiplicative_generator() sage: a = b^3 sage: gap(a) Z(2^3)^3 sage: gap(a^3) Z(2^3)^2
You can specify the instance of the Gap interpreter that is used::
sage: F = FiniteField(next_prime(200)^2, 'a', impl='pari_ffelt') sage: a = F.multiplicative_generator () sage: a._gap_ (gap) Z(211^2) sage: (a^20)._gap_(gap) Z(211^2)^20
Gap only supports relatively small finite fields::
sage: F = FiniteField(next_prime(1000)^2, 'a', impl='pari_ffelt') sage: a = F.multiplicative_generator () sage: gap._coerce_(a) Traceback (most recent call last): ... TypeError: order must be at most 65536 """
def unpickle_FiniteFieldElement_pari_ffelt(parent, elem): """ EXAMPLES::
sage: k.<a> = GF(2^20, impl='pari_ffelt') sage: e = k.random_element() sage: f = loads(dumps(e)) # indirect doctest sage: e == f True """ |