Path: blob/master/sage/rings/finite_rings/finite_field_ext_pari.py
4128 views
"""1Finite Extension Fields implemented via PARI.23AUTHORS:45- William Stein: initial version67- Jeroen Demeyer (2010-12-16): fix formatting of docstrings (#10487)8"""9#*****************************************************************************10# Copyright (C) 2005,2007 William Stein <[email protected]>11# Copyright (C) 2010 Jeroen Demeyer <[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#*****************************************************************************181920import sage.rings.polynomial.polynomial_element as polynomial_element21import sage.rings.polynomial.multi_polynomial_element as multi_polynomial_element2223import sage.rings.integer as integer24import sage.rings.rational as rational2526import sage.libs.pari.all as pari2728import element_ext_pari2930from sage.rings.finite_rings.finite_field_base import FiniteField as FiniteField_generic313233import sage.interfaces.gap3435class FiniteField_ext_pari(FiniteField_generic):36r"""37Finite Field of order `q`, where `q` is a prime power (not a prime),38implemented using PARI ``POLMOD``s. This implementation is the default39implementation for `q \geq 2^{16}`.4041INPUT:4243- ``q`` -- int, prime power, order of the finite field44- ``name`` -- string (default: 'a'), string for printing the generator4546OUTPUT:4748- FiniteField_ext_pari -- finite field of order `q`.4950EXAMPLES::5152sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari53sage: k = FiniteField_ext_pari(9, 'a')54sage: k55Finite Field in a of size 3^256sage: k.is_field()57True58sage: k.characteristic()59360sage: a = k.gen()61sage: a62a63sage: a.parent()64Finite Field in a of size 3^265sage: a.charpoly('x')66x^2 + 2*x + 267sage: [a^i for i in range(8)]68[1, a, a + 1, 2*a + 1, 2, 2*a, 2*a + 2, a + 2]6970Fields can be coerced into sets or list and iterated over::7172sage: list(k)73[0, 1, 2, a, a + 1, a + 2, 2*a, 2*a + 1, 2*a + 2]7475The following is a native Python set::7677sage: set(k)78set([0, 1, 2, a, a + 1, a + 2, 2*a, 2*a + 1, 2*a + 2])7980And the following is a Sage set::8182sage: Set(k)83{0, 1, 2, a, a + 1, a + 2, 2*a, 2*a + 1, 2*a + 2}8485We can also make a list via comprehension:86sage: [x for x in k]87[0, 1, 2, a, a + 1, a + 2, 2*a, 2*a + 1, 2*a + 2]8889Next we compute with the finite field of order 16, where90the name is named b::9192sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari93sage: k16 = FiniteField_ext_pari(16, "b")94sage: z = k16.gen()95sage: z96b97sage: z.charpoly('x')98x^4 + x + 199sage: k16.is_field()100True101sage: k16.characteristic()1022103sage: z.multiplicative_order()10415105106Of course one can also make prime finite fields::107108sage: k = FiniteField(7)109110Note that the generator is 1::111112sage: k.gen()1131114sage: k.gen().multiplicative_order()1151116117Prime finite fields are implemented elsewhere, they cannot be118constructed using ``FiniteField_ext_pari``::119120sage: k = FiniteField_ext_pari(7, 'a')121Traceback (most recent call last):122...123ValueError: The size of the finite field must not be prime.124125Illustration of dumping and loading::126127sage: K = FiniteField(7)128sage: loads(K.dumps()) == K129True130sage: K = FiniteField(7^10, 'b')131sage: loads(K.dumps()) == K132True133sage: K = FiniteField(7^10, 'a')134sage: loads(K.dumps()) == K135True136137In this example `K` is large enough that Conway polynomials are not138used. Note that when the field is dumped the defining polynomial `f`139is also dumped. Since `f` is determined by a random algorithm, it's140important that `f` is dumped as part of `K`. If you quit Sage and141restart and remake a finite field of the same order (and the order is142large enough so that there is no Conway polynomial), then defining143polynomial is probably different. However, if you load a previously144saved field, that will have the same defining polynomial. ::145146sage: K = GF(10007^10, 'a')147sage: loads(K.dumps()) == K148True149150.. NOTE::151152We do NOT yet define natural consistent inclusion maps153between different finite fields.154"""155def __init__(self, q, name, modulus=None):156"""157Create finite field of order q with variable printed as name.158159INPUT:160161- ``q`` -- integer, size of the finite field, not prime162- ``name`` -- variable used for printing element of the finite163field. Also, two finite fields are considered164equal if they have the same variable name, and not165otherwise.166- ``modulus`` -- you may provide a polynomial to use for reduction or167a string:168'conway': force the use of a Conway polynomial, will169raise a RuntimeError if none is found in the database;170'random': use a random irreducible polynomial.171'default': a Conway polynomial is used if found. Otherwise172a random polynomial is used.173174OUTPUT:175176- FiniteField_ext_pari -- a finite field of order q with given variable name.177178EXAMPLES::179180sage: FiniteField(65537)181Finite Field of size 65537182sage: FiniteField(2^20, 'c')183Finite Field in c of size 2^20184sage: FiniteField(3^11, "b")185Finite Field in b of size 3^11186sage: FiniteField(3^11, "b").gen()187b188189You can also create a finite field using GF, which is a synonym190for FiniteField. ::191192sage: GF(19^5, 'a')193Finite Field in a of size 19^5194"""195if element_ext_pari.dynamic_FiniteField_ext_pariElement is None: element_ext_pari._late_import()196from constructor import FiniteField as GF197q = integer.Integer(q)198if q < 2:199raise ArithmeticError, "q must be a prime power"200from sage.structure.proof.all import arithmetic201proof = arithmetic()202if proof:203F = q.factor()204else:205from sage.rings.arith import is_pseudoprime_small_power206F = is_pseudoprime_small_power(q, get_data=True)207if len(F) != 1:208raise ArithmeticError, "q must be a prime power"209210if F[0][1] > 1:211base_ring = GF(F[0][0])212else:213raise ValueError, "The size of the finite field must not be prime."214#base_ring = self215216FiniteField_generic.__init__(self, base_ring, name, normalize=True)217218self._kwargs = {}219self.__char = F[0][0]220self.__pari_one = pari.pari(1).Mod(self.__char)221self.__degree = integer.Integer(F[0][1])222self.__order = q223self.__is_field = True224225if modulus is None or modulus == "default":226from constructor import exists_conway_polynomial227if exists_conway_polynomial(self.__char, self.__degree):228modulus = "conway"229else:230modulus = "random"231232if isinstance(modulus,str):233if modulus == "conway":234from constructor import conway_polynomial235modulus = conway_polynomial(self.__char, self.__degree)236elif modulus == "random":237# The following is fast/deterministic, but has serious problems since238# it crashes on 64-bit machines, and I can't figure out why:239# self.__pari_modulus = pari.pari.finitefield_init(self.__char, self.__degree, self.variable_name())240# So instead we iterate through random polys until we find an irreducible one.241242R = GF(self.__char)['x']243while True:244modulus = R.random_element(self.__degree)245modulus = modulus.monic()246if modulus.degree() == self.__degree and modulus.is_irreducible():247break248else:249raise ValueError("Modulus parameter not understood")250251elif isinstance(modulus, (list, tuple)):252modulus = GF(self.__char)['x'](modulus)253elif sage.rings.polynomial.polynomial_element.is_Polynomial(modulus):254if modulus.parent() is not base_ring:255modulus = modulus.change_ring(base_ring)256else:257raise ValueError("Modulus parameter not understood")258259self.__modulus = modulus260f = pari.pari(str(modulus))261self.__pari_modulus = f.subst(modulus.parent().variable_name(), 'a') * self.__pari_one262self.__gen = element_ext_pari.FiniteField_ext_pariElement(self, pari.pari('a'))263264self._zero_element = self._element_constructor_(0)265self._one_element = self._element_constructor_(1)266267def __reduce__(self):268"""269EXAMPLES::270271sage: k.<b> = GF(5^20); type(k)272<class 'sage.rings.finite_rings.finite_field_ext_pari.FiniteField_ext_pari_with_category'>273sage: k is loads(dumps(k))274True275"""276return self._factory_data[0].reduce_data(self)277278def __cmp__(self, other):279"""280EXAMPLES::281282sage: k = GF(7^20,'a')283sage: k == loads(dumps(k))284True285"""286if not isinstance(other, FiniteField_ext_pari):287return cmp(type(self), type(other))288return cmp((self.__order, self.variable_name(), self.__modulus), (other.__order, other.variable_name(), other.__modulus))289290def __richcmp__(left, right, op):291r"""292Compare ``left`` with ``right``.293294EXAMPLE::295296sage: k.<a> = GF(next_prime(2^17))297sage: j.<b> = GF(next_prime(2^18))298sage: k == j299False300301sage: GF(next_prime(2^17),'a') == copy(GF(next_prime(2^17),'a'))302True303"""304return left._richcmp_helper(right, op)305306def _pari_one(self):307r"""308The PARI object Mod(1,p). This is implementation specific309and should be ignored by users.310311EXAMPLES::312313sage: k = GF(7^20,'a')314sage: k._pari_one()315Mod(1, 7)316"""317return self.__pari_one318319def _pari_modulus(self):320"""321The polynomial mod p that defines the finite field, as a PARI322object. This is implementation specific, and some finite fields323might not be implemented using PARI, so you should avoid using324this function.325326OUTPUT:327328- ``gen`` -- a PARI polynomial gen329330EXAMPLES::331332sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari333sage: FiniteField_ext_pari(19^2, 'a')._pari_modulus()334Mod(1, 19)*a^2 + Mod(18, 19)*a + Mod(2, 19)335336sage: FiniteField_ext_pari(13^3, 'a')._pari_modulus()337Mod(1, 13)*a^3 + Mod(2, 13)*a + Mod(11, 13)338339Note that the PARI modulus is always in terms of a, even if340the field variable isn't. This is because the specific choice341of variable name has meaning in PARI, i.e., it can't be342arbitrary. ::343344sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari345sage: FiniteField_ext_pari(2^4, "b")._pari_modulus()346Mod(1, 2)*a^4 + Mod(1, 2)*a + Mod(1, 2)347"""348return self.__pari_modulus349350def gen(self, n=0):351"""352Return a generator of the finite field. This generator353is a root of the defining polynomial of the finite field, and354might differ between different runs or different355architectures.356357.. WARNING::358359This generator is not guaranteed to be a generator360for the multiplicative group. To obtain the latter, use361multiplicative_generator().362363INPUT:364365- ``n`` -- ignored366367OUTPUT:368369- FiniteField_ext_pariElement -- field generator of finite field370371EXAMPLES::372373sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari374sage: FiniteField_ext_pari(2^4, "b").gen()375b376sage: k = FiniteField_ext_pari(3^4, "alpha")377sage: a = k.gen()378sage: a379alpha380sage: a^4381alpha^3 + 1382383"""384return self.__gen385386def characteristic(self):387"""388Returns the characteristic of the finite field, which is a389prime number.390391EXAMPLES::392393sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari394sage: k = FiniteField_ext_pari(3^4, 'a')395sage: k.characteristic()3963397"""398return self.__char399400def modulus(self):401r"""402Return the minimal polynomial of the generator of self in403``self.polynomial_ring('x')``.404405EXAMPLES::406407sage: F.<a> = GF(7^20, 'a')408sage: f = F.modulus(); f409x^20 + x^12 + 6*x^11 + 2*x^10 + 5*x^9 + 2*x^8 + 3*x^7 + x^6 + 3*x^5 + 3*x^3 + x + 3410411sage: f(a)4120413"""414return self.__modulus415416def degree(self):417"""418Returns the degree of the finite field, which is a positive419integer.420421EXAMPLES::422423sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari424sage: FiniteField_ext_pari(3^20, 'a').degree()42520426"""427return self.__degree428429def _element_constructor_(self, x):430r"""431Coerce x into the finite field.432433INPUT:434435- ``x`` -- object436437OUTPUT:438439- FiniteField_ext_pariElement -- if possible, makes a finite field element from x.440441EXAMPLES::442443sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari444sage: k = FiniteField_ext_pari(3^4, 'a')445sage: b = k(5) # indirect doctest446sage: b.parent()447Finite Field in a of size 3^4448sage: a = k.gen()449sage: k(a + 2)450a + 2451452Univariate polynomials coerce into finite fields by evaluating453the polynomial at the field's generator::454455sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari456sage: R.<x> = QQ[]457sage: k, a = FiniteField_ext_pari(5^2, 'a').objgen()458sage: k(R(2/3))4594460sage: k(x^2)461a + 3462sage: R.<x> = GF(5)[]463sage: k(x^3-2*x+1)4642*a + 4465466sage: x = polygen(QQ)467sage: k(x^25)468a469470sage: Q, q = FiniteField_ext_pari(5^7, 'q').objgen()471sage: L = GF(5)472sage: LL.<xx> = L[]473sage: Q(xx^2 + 2*xx + 4)474q^2 + 2*q + 4475476Multivariate polynomials only coerce if constant::477478sage: R = k['x,y,z']; R479Multivariate Polynomial Ring in x, y, z over Finite Field in a of size 5^2480sage: k(R(2))4812482sage: R = QQ['x,y,z']483sage: k(R(1/5))484Traceback (most recent call last):485...486TypeError: unable to coerce487488Gap elements can also be coerced into finite fields::489490sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari491sage: F = FiniteField_ext_pari(8, 'a')492sage: a = F.multiplicative_generator(); a493a494sage: b = gap(a^3); b495Z(2^3)^3496sage: F(b)497a + 1498sage: a^3499a + 1500501sage: a = GF(13)(gap('0*Z(13)')); a5020503sage: a.parent()504Finite Field of size 13505506sage: F = GF(16, 'a')507sage: F(gap('Z(16)^3'))508a^3509sage: F(gap('Z(16)^2'))510a^2511512You can also call a finite extension field with a string513to produce an element of that field, like this::514515sage: k = GF(2^8, 'a')516sage: k('a^200')517a^4 + a^3 + a^2518519This is especially useful for fast conversions from Singular etc.520to FiniteField_ext_pariElements.521522AUTHORS:523524-- David Joyner (2005-11)525-- Martin Albrecht (2006-01-23)526-- Martin Albrecht (2006-03-06): added coercion from string527"""528if isinstance(x, element_ext_pari.FiniteField_ext_pariElement):529if x.parent() is self:530return x531elif x.parent() == self:532# canonically isomorphic finite fields533return element_ext_pari.FiniteField_ext_pariElement(self, x)534else:535# This is where we *would* do coercion from one finite field to another...536raise TypeError, "no coercion defined"537538elif sage.interfaces.gap.is_GapElement(x):539from sage.interfaces.gap import gfq_gap_to_sage540try:541return gfq_gap_to_sage(x, self)542except (ValueError, IndexError, TypeError):543raise TypeError, "no coercion defined"544545if isinstance(x, (int, long, integer.Integer, rational.Rational,546pari.pari_gen, list)):547548return element_ext_pari.FiniteField_ext_pariElement(self, x)549550elif isinstance(x, multi_polynomial_element.MPolynomial):551if x.is_constant():552return self(x.constant_coefficient())553else:554raise TypeError, "no coercion defined"555556elif isinstance(x, polynomial_element.Polynomial):557if x.is_constant():558return self(x.constant_coefficient())559else:560return x.change_ring(self)(self.gen())561562elif isinstance(x, str):563x = x.replace(self.variable_name(),'a')564x = pari.pari(x)565t = x.type()566if t == 't_POL':567if (x.variable() == 'a' \568and x.polcoeff(0).type()[2] == 'I'): #t_INT and t_INTMOD569return self(x)570if t[2] == 'I': #t_INT and t_INTMOD571return self(x)572raise TypeError, "string element does not match this finite field"573574try:575if x.parent() == self.vector_space():576x = pari.pari('+'.join(['%s*a^%s'%(x[i], i) for i in range(self.degree())]))577return element_ext_pari.FiniteField_ext_pariElement(self, x)578except AttributeError:579pass580try:581return element_ext_pari.FiniteField_ext_pariElement(self, integer.Integer(x))582except TypeError, msg:583raise TypeError, "%s\nno coercion defined"%msg584585def _coerce_map_from_(self, R):586r"""587Canonical coercion to ``self``.588589EXAMPLES::590591sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari592sage: FiniteField_ext_pari(4,'a')._coerce_(GF(2)(1)) # indirect doctest5931594sage: k = FiniteField_ext_pari(4,'a')595sage: k._coerce_(k.0)596a597sage: FiniteField_ext_pari(4,'a')._coerce_(3)5981599sage: FiniteField_ext_pari(4,'a')._coerce_(2/3)600Traceback (most recent call last):601...602TypeError: no canonical coercion from Rational Field to Finite Field in a of size 2^2603sage: FiniteField_ext_pari(8,'a')._coerce_(FiniteField_ext_pari(4,'a').0)604Traceback (most recent call last):605...606TypeError: no canonical coercion from Finite Field in a of size 2^2 to Finite Field in a of size 2^3607sage: FiniteField_ext_pari(16,'a')._coerce_(FiniteField_ext_pari(4,'a').0)608Traceback (most recent call last):609...610TypeError: no canonical coercion from Finite Field in a of size 2^2 to Finite Field in a of size 2^4611sage: k = FiniteField_ext_pari(8,'a')612sage: k._coerce_(FiniteField(7,'a')(2))613Traceback (most recent call last):614...615TypeError: no canonical coercion from Finite Field of size 7 to Finite Field in a of size 2^3616"""617from sage.rings.integer_ring import ZZ618from sage.rings.finite_rings.integer_mod_ring import IntegerModRing_generic619if R is int or R is long or R is ZZ:620return True621if isinstance(R, FiniteField_ext_pari):622if R is self:623return True624if R.characteristic() == self.characteristic():625if R.degree() == 1:626return True627elif self.degree() % R.degree() == 0:628# TODO: This is where we *would* do coercion from one nontrivial finite field to another...629return False630from sage.rings.residue_field import ResidueField_generic631if isinstance(R, IntegerModRing_generic) and R.characteristic() == self.characteristic() and not isinstance(R, ResidueField_generic):632return True633634def __len__(self):635"""636The number of elements of the finite field.637638EXAMPLES::639640sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari641sage: k = FiniteField_ext_pari(2^10, 'a')642sage: k643Finite Field in a of size 2^10644sage: len(k)6451024646"""647return self.__order648649def order(self):650"""651The number of elements of the finite field.652653EXAMPLES::654655sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari656sage: k = FiniteField_ext_pari(2^10,'a')657sage: k658Finite Field in a of size 2^10659sage: k.order()6601024661"""662return self.__order663664def polynomial(self, name=None):665"""666Return the irreducible characteristic polynomial of the667generator of this finite field, i.e., the polynomial `f(x)` so668elements of the finite field as elements modulo `f`.669670EXAMPLES::671672sage: k = FiniteField(17)673sage: k.polynomial('x')674x675sage: from sage.rings.finite_rings.finite_field_ext_pari import FiniteField_ext_pari676sage: k = FiniteField_ext_pari(9,'a')677sage: k.polynomial('x')678x^2 + 2*x + 2679"""680if name is None:681name = self.variable_name()682try:683return self.__polynomial[name]684except (AttributeError, KeyError):685from constructor import FiniteField as GF686R = GF(self.characteristic())[name]687f = R(self._pari_modulus())688try:689self.__polynomial[name] = f690except (KeyError, AttributeError):691self.__polynomial = {}692self.__polynomial[name] = f693return f694695def __hash__(self):696"""697Return the hash of this field.698699EXAMPLES::700701sage: {GF(9,'a'): 1} # indirect doctest702{Finite Field in a of size 3^2: 1}703sage: {GF(9,'b'): 1} # indirect doctest704{Finite Field in b of size 3^2: 1}705"""706try:707return self.__hash708except AttributeError:709self.__hash = hash((self.__order, self.variable_name(), self.__modulus))710return self.__hash711712713