Path: blob/master/sage/rings/finite_rings/element_base.pyx
4084 views
"""1Base class for finite field elements23AUTHORS::45- David Roe (2010-1-14) -- factored out of sage.structure.element67"""8include "../../ext/stdsage.pxi"910from sage.structure.element cimport Element11from sage.structure.parent cimport Parent12from sage.rings.integer import Integer1314def is_FiniteFieldElement(x):15"""16Returns if x is a finite field element.1718EXAMPLE::1920sage: from sage.rings.finite_rings.element_ext_pari import is_FiniteFieldElement21sage: is_FiniteFieldElement(1)22False23sage: is_FiniteFieldElement(IntegerRing())24False25sage: is_FiniteFieldElement(GF(5)(2))26True27"""28from sage.rings.finite_rings.finite_field_base import is_FiniteField29return isinstance(x, Element) and is_FiniteField(x.parent())3031cdef class FiniteRingElement(CommutativeRingElement):32def _nth_root_common(self, n, all, algorithm, cunningham):33"""34This function exists to reduce code duplication between finite field nth roots and integer_mod nth roots.3536The inputs are described there.3738TESTS::3940sage: a = Zmod(17)(13)41sage: a._nth_root_common(4, True, "Johnston", False)42[3, 5, 14, 12]43"""44K = self.parent()45q = K.order()46if self.is_one():47gcd = n.gcd(q-1)48if gcd == 1:49if all: return [self]50else: return self51else:52# the following may eventually be improved to not need a multiplicative generator.53g = K.multiplicative_generator()54q1overn = (q-1)//gcd55nthroot = g**q1overn56return [nthroot**a for a in range(gcd)] if all else nthroot57n = n % (q-1)58if n == 0:59if all: return []60else: raise ValueError, "no nth root"61gcd, alpha, beta = n.xgcd(q-1) # gcd = alpha*n + beta*(q-1), so 1/n = alpha/gcd (mod q-1)62if gcd == 1:63return [self**alpha] if all else self**alpha64n = gcd65q1overn = (q-1)//n66if self**q1overn != 1:67if all: return []68else: raise ValueError, "no nth root"69self = self**alpha70if cunningham:71F = n._factor_cunningham()72else:73F = n.factor()74from sage.groups.generic import discrete_log75if algorithm is None or algorithm == 'Johnston':76g = K.multiplicative_generator()77for r, v in F:78k, h = (q-1).val_unit(r)79z = h * (-h).inverse_mod(r**v)80x = (1 + z) // r**v81if k == 1:82self = self**x83else:84t = discrete_log(self**h, g**(r**v*h), r**(k-v), operation='*')85self = self**x * g**(-z*t)86if all:87nthroot = g**q1overn88L = [self]89for i in range(1,n):90self *= nthroot91L.append(self)92return L93else:94return self95else:96raise ValueError, "unknown algorithm"9798cdef class FinitePolyExtElement(FiniteRingElement):99"""100Elements represented as polynomials modulo a given ideal.101102TESTS::103104sage: k.<a> = GF(64)105sage: TestSuite(a).run()106"""107def _im_gens_(self, codomain, im_gens):108"""109Used for applying homomorphisms of finite fields.110111EXAMPLES::112113sage: k.<a> = FiniteField(73^2, 'a')114sage: K.<b> = FiniteField(73^4, 'b')115sage: phi = k.hom([ b^(73*73+1) ]) # indirect doctest116sage: phi(0)1170118sage: phi(a)1197*b^3 + 13*b^2 + 65*b + 71120121sage: phi(a+3)1227*b^3 + 13*b^2 + 65*b + 1123"""124## NOTE: see the note in sage/rings/number_field_element.pyx,125## in the comments for _im_gens_ there -- something analogous126## applies here.127return codomain(self.polynomial()(im_gens[0]))128129def minpoly(self,var='x'):130"""131Returns the minimal polynomial of this element132(over the corresponding prime subfield).133134EXAMPLES::135136sage: k.<a> = FiniteField(19^2)137sage: parent(a)138Finite Field in a of size 19^2139sage: b=a**20;p=b.charpoly("x");p140x^2 + 15*x + 4141sage: factor(p)142(x + 17)^2143sage: b.minpoly('x')144x + 17145"""146p=self.charpoly(var);147for q in p.factor():148if q[0](self)==0:149return q[0]150# This shouldn't be reached, but you never know!151raise ArithmeticError("Could not find the minimal polynomial")152153## We have two names for the same method154## for compatibility with sage.matrix155def minimal_polynomial(self,var='x'):156"""157Returns the minimal polynomial of this element158(over the corresponding prime subfield).159160EXAMPLES::161162sage: k.<a> = FiniteField(3^4)163sage: parent(a)164Finite Field in a of size 3^4165sage: b=a**20;p=charpoly(b,"y");p166y^4 + 2*y^2 + 1167sage: factor(p)168(y^2 + 1)^2169sage: b.minimal_polynomial('y')170y^2 + 1171"""172return self.minpoly(var)173174def vector(self, reverse=False):175r"""176See :meth:`_vector_`.177178EXAMPLE::179180sage: k.<a> = GF(2^16)181sage: e = a^2 + 1182sage: e.vector() # random-ish error message183doctest:1: DeprecationWarning:The function vector is replaced by _vector_.184(1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)185"""186from sage.misc.misc import deprecation187deprecation("The function vector is replaced by _vector_.")188return self._vector_()189190def _vector_(self, reverse=False):191"""192Return a vector in self.parent().vector_space() matching193self. The most significant bit is to the right.194195INPUT::196197- ``reverse`` -- reverse the order of the bits198from little endian to big endian.199200EXAMPLES::201202sage: k.<a> = GF(2^16)203sage: e = a^2 + 1204sage: v = vector(e)205sage: v206(1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)207sage: k(v)208a^2 + 1209210sage: k.<a> = GF(3^16)211sage: e = 2*a^2 + 1212sage: v = vector(e)213sage: v214(1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)215sage: k(v)2162*a^2 + 1217218You can also compute the vector in the other order::219220sage: e._vector_(reverse=True)221(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1)222"""223#vector(foo) might pass in ZZ224if PY_TYPE_CHECK(reverse, Parent):225raise TypeError, "Base field is fixed to prime subfield."226227k = self.parent()228229v = self.polynomial().list()230231ret = [v[i] for i in range(len(v))]232233for i in range(k.degree() - len(ret)):234ret.append(0)235236if reverse:237ret = list(reversed(ret))238return k.vector_space()(ret)239240def matrix(self, reverse=False):241r"""242See :meth:`_matrix_`.243244EXAMPLE::245246sage: k.<a> = GF(2^16)247sage: e = a^2 + 1248sage: e.matrix() # random-ish error message249doctest:1: DeprecationWarning:The function matrix is replaced by _matrix_.250[1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0]251[0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1]252[1 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0]253[0 1 0 1 0 0 0 0 0 0 0 0 0 0 1 1]254[0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1]255[0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0]256[0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1]257[0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0]258[0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0]259[0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0]260[0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0]261[0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0]262[0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0]263[0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0]264[0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0]265[0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1]266"""267from sage.misc.misc import deprecation268deprecation("The function matrix is replaced by _matrix_.")269return self._matrix_()270271272def _matrix_(self, reverse=False):273"""274Return the matrix of right multiplication by the element on275the power basis `1, x, x^2, \ldots, x^{d-1}` for the field276extension. Thus the \emph{rows} of this matrix give the images277of each of the `x^i`.278279INPUT:280281- ``reverse`` - if True act on vectors in reversed order282283EXAMPLE::284285sage: k.<a> = GF(2^4)286sage: a._vector_(reverse=True), a._matrix_(reverse=True) * a._vector_(reverse=True)287((0, 0, 1, 0), (0, 1, 0, 0))288sage: vector(a), matrix(a) * vector(a)289((0, 1, 0, 0), (0, 0, 1, 0))290"""291import sage.matrix.matrix_space292293K = self.parent()294a = K.gen()295x = K(1)296d = K.degree()297298columns = []299300if not reverse:301l = xrange(d)302else:303l = reversed(range(d))304305for i in l:306columns.append( (self * x)._vector_() )307x *= a308309k = K.base_ring()310M = sage.matrix.matrix_space.MatrixSpace(k, d)311312if reverse:313return M(columns)314else:315return M(columns).transpose()316def _latex_(self):317r"""318Return the latex representation of self, which is just the319latex representation of the polynomial representation of self.320321EXAMPLES::322323sage: k.<b> = GF(5^2); k324Finite Field in b of size 5^2325sage: b._latex_()326'b'327sage: (b^2+1)._latex_()328'b + 4'329"""330if self.parent().degree()>1:331return self.polynomial()._latex_()332else:333return str(self)334335def _pari_init_(self, var=None):336r"""337Return a string that defines this element when evaluated in PARI.338339INPUT:340341- ``var`` - default: ``None`` - a string for a new variable name to use.342343EXAMPLES::344345sage: S.<b> = GF(5^2); S346Finite Field in b of size 5^2347sage: b._pari_init_()348'Mod(Mod(1, 5)*b, Mod(1, 5)*b^2 + Mod(4, 5)*b + Mod(2, 5))'349sage: (2*b+3)._pari_init_()350'Mod(Mod(2, 5)*b + Mod(3, 5), Mod(1, 5)*b^2 + Mod(4, 5)*b + Mod(2, 5))'351352TESTS:353354The following tests against a bug fixed in trac ticket #11530. ::355356sage: F.<d> = GF(3^4)357sage: F.modulus()358x^4 + 2*x^3 + 2359sage: d._pari_init_()360'Mod(Mod(1, 3)*d, Mod(1, 3)*d^4 + Mod(2, 3)*d^3 + Mod(2, 3))'361sage: (d^2+2*d+1)._pari_init_("p")362'Mod(Mod(1, 3)*p^2 + Mod(2, 3)*p + Mod(1, 3), Mod(1, 3)*p^4 + Mod(2, 3)*p^3 + Mod(2, 3))'363sage: d._pari_()364Mod(Mod(1, 3)*d, Mod(1, 3)*d^4 + Mod(2, 3)*d^3 + Mod(2, 3))365366sage: K.<M> = GF(2^8)367sage: K.modulus()368x^8 + x^4 + x^3 + x^2 + 1369sage: (M^3+1)._pari_init_()370'Mod(Mod(1, 2)*M^3 + Mod(1, 2), Mod(1, 2)*M^8 + Mod(1, 2)*M^4 + Mod(1, 2)*M^3 + Mod(1, 2)*M^2 + Mod(1, 2))'371sage: M._pari_init_(var='foo')372'Mod(Mod(1, 2)*foo, Mod(1, 2)*foo^8 + Mod(1, 2)*foo^4 + Mod(1, 2)*foo^3 + Mod(1, 2)*foo^2 + Mod(1, 2))'373"""374if var is None:375var = self.parent().variable_name()376g = self.parent().modulus()._pari_with_name(var)377f = self.polynomial()._pari_with_name(var)378return 'Mod({0}, {1})'.format(f, g)379380def charpoly(self, var='x', algorithm='matrix'):381"""382Return the characteristic polynomial of self as a polynomial with given variable.383384INPUT:385386- ``var`` - string (default: 'x')387388- ``algorithm`` - string (default: 'matrix')389390- 'matrix' - return the charpoly computed from the matrix of391left multiplication by self392393- 'pari' -- use pari's charpoly routine on polymods, which394is not very good except in small cases395396The result is not cached.397398EXAMPLES::399400sage: k.<a> = GF(19^2)401sage: parent(a)402Finite Field in a of size 19^2403sage: a.charpoly('X')404X^2 + 18*X + 2405sage: a^2 + 18*a + 24060407sage: a.charpoly('X', algorithm='pari')408X^2 + 18*X + 2409"""410if algorithm == 'matrix':411return self._matrix_().charpoly(var)412elif algorithm == 'pari':413from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing414R = PolynomialRing(self.parent().prime_subfield(), var)415return R(self._pari_().charpoly('x').lift())416else:417raise ValueError, "unknown algorithm '%s'"%algorithm418419def norm(self):420"""421Return the norm of self down to the prime subfield.422423This is the product of the Galois conjugates of self.424425EXAMPLES::426427sage: S.<b> = GF(5^2); S428Finite Field in b of size 5^2429sage: b.norm()4302431sage: b.charpoly('t')432t^2 + 4*t + 2433434Next we consider a cubic extension::435436sage: S.<a> = GF(5^3); S437Finite Field in a of size 5^3438sage: a.norm()4392440sage: a.charpoly('t')441t^3 + 3*t + 3442sage: a * a^5 * (a^25)4432444"""445f = self.charpoly('x')446n = f[0]447if f.degree() % 2 != 0:448return -n449else:450return n451452def trace(self):453"""454Return the trace of this element, which is the sum of the455Galois conjugates.456457EXAMPLES::458459sage: S.<a> = GF(5^3); S460Finite Field in a of size 5^3461sage: a.trace()4620463sage: a.charpoly('t')464t^3 + 3*t + 3465sage: a + a^5 + a^254660467sage: z = a^2 + a + 1468sage: z.trace()4692470sage: z.charpoly('t')471t^3 + 3*t^2 + 2*t + 2472sage: z + z^5 + z^254732474"""475return self.parent().prime_subfield()(self._pari_().trace().lift())476477def multiplicative_order(self):478r"""479Return the multiplicative order of this field element.480481EXAMPLE::482483sage: S.<a> = GF(5^3); S484Finite Field in a of size 5^3485sage: a.multiplicative_order()486124487sage: (a^8).multiplicative_order()48831489sage: S(0).multiplicative_order()490Traceback (most recent call last):491...492ArithmeticError: Multiplicative order of 0 not defined.493"""494import sage.rings.arith495496if self.is_zero():497raise ArithmeticError("Multiplicative order of 0 not defined.")498n = self._parent.order() - 1499F = self._parent.factored_unit_order()[0]500order = 1501for p, e in F:502# Determine the power of p that divides the order.503a = self**(n//(p**e))504while a != 1:505order = order * p506a = a**p507508return order509510def additive_order(self):511"""512Return the additive order of this finite field element.513514EXAMPLES::515516sage: k.<a> = FiniteField(2^12, 'a')517sage: b = a^3 + a + 1518sage: b.additive_order()5192520sage: k(0).additive_order()5211522"""523if self.is_zero():524from sage.rings.integer import Integer525return Integer(1)526return self.parent().characteristic()527528def nth_root(self, n, extend = False, all = False, algorithm=None, cunningham=False):529r"""530Returns an `n`\th root of ``self``.531532INPUT:533534- ``n`` - integer `\geq 1`535536- ``extend`` - bool (default: ``False``); if ``True``, return an `n`\th537root in an extension ring, if necessary. Otherwise, raise a538ValueError if the root is not in the base ring. Warning:539this option is not implemented!540541- ``all`` - bool (default: ``False``); if ``True``, return all `n`\th542roots of ``self``, instead of just one.543544- ``algorithm`` - string (default: ``None``); 'Johnston' is the only545currently supported option. For IntegerMod elements, the problem546is reduced to the prime modulus case using CRT and `p`-adic logs,547and then this algorithm used.548549OUTPUT:550551If self has an `n`\th root, returns one (if ``all`` is ``False``) or a552list of all of them (if ``all`` is ``True``). Otherwise, raises a553ValueError (if ``extend`` is ``False``) or a ``NotImplementedError`` (if554``extend`` is ``True``).555556.. warning::557558The 'extend' option is not implemented (yet).559560EXAMPLES::561562sage: K = GF(31)563sage: a = K(22)564sage: K(22).nth_root(7)56513566sage: K(25).nth_root(5)5675568sage: K(23).nth_root(3)56929570571sage: K.<a> = GF(625)572sage: (3*a^2+a+1).nth_root(13)**135733*a^2 + a + 1574575sage: k.<a> = GF(29^2)576sage: b = a^2 + 5*a + 1577sage: b.nth_root(11)5783*a + 20579sage: b.nth_root(5)580Traceback (most recent call last):581...582ValueError: no nth root583sage: b.nth_root(5, all = True)584[]585sage: b.nth_root(3, all = True)586[14*a + 18, 10*a + 13, 5*a + 27]587588sage: k.<a> = GF(29^5)589sage: b = a^2 + 5*a + 1590sage: b.nth_root(5)59119*a^4 + 2*a^3 + 2*a^2 + 16*a + 3592sage: b.nth_root(7)593Traceback (most recent call last):594...595ValueError: no nth root596sage: b.nth_root(4, all=True)597[]598599TESTS::600601sage: for p in [2,3,5,7,11]: # long602... for n in [2,5,10]:603... q = p^n604... K.<a> = GF(q)605... for r in (q-1).divisors():606... if r == 1: continue607... x = K.random_element()608... y = x^r609... if y.nth_root(r)**r != y: raise RuntimeError610... if (y^41).nth_root(41*r)**(41*r) != y^41: raise RuntimeError611... if (y^307).nth_root(307*r)**(307*r) != y^307: raise RuntimeError612613sage: k.<a> = GF(4)614sage: a.nth_root(0,all=True)615[]616sage: k(1).nth_root(0,all=True)617[a, a + 1, 1]618619ALGORITHMS:620621- The default is currently an algorithm described in the following paper:622623Johnston, Anna M. A generalized qth root algorithm. Proceedings of the tenth annual ACM-SIAM symposium on Discrete algorithms. Baltimore, 1999: pp 929-930.624625AUTHOR:626627- David Roe (2010-02-13)628"""629if self.is_zero():630if n <= 0:631if all: return []632else: raise ValueError633if all: return [self]634else: return self635if n < 0:636self = ~self637n = -n638elif n == 0:639if self == 1:640if all: return [a for a in self.parent().list() if a != 0]641else: return self642else:643if all: return []644else: raise ValueError645if extend:646raise NotImplementedError647from sage.rings.integer import Integer648n = Integer(n)649return self._nth_root_common(n, all, algorithm, cunningham)650651def pth_power(self, int k = 1):652"""653Return the `(p^k)^{th}` power of self, where `p` is the654characteristic of the field.655656INPUT:657658- ``k`` - integer (default: 1, must fit in C int type)659660Note that if `k` is negative, then this computes the appropriate root.661662EXAMPLES::663664sage: F.<a> = GF(29^2)665sage: z = a^2 + 5*a + 1666sage: z.pth_power()66719*a + 20668sage: z.pth_power(10)66910*a + 28670sage: z.pth_power(-10) == z671True672sage: F.<b> = GF(2^12)673sage: y = b^3 + b + 1674sage: y == (y.pth_power(-3))^(2^3)675True676sage: y.pth_power(2)677b^7 + b^6 + b^5 + b^4 + b^3 + b678"""679p = self.additive_order()680n = self.parent().degree()681return self**(p**(k % n))682683frobenius = pth_power684685def pth_root(self, int k = 1):686"""687Return the `(p^k)^{th}` root of self, where `p` is the characteristic688of the field.689690INPUT:691692- ``k`` - integer (default: 1, must fit in C int type)693694Note that if `k` is negative, then this computes the appropriate power.695696EXAMPLES::697698sage: F.<b> = GF(2^12)699sage: y = b^3 + b + 1700sage: y == (y.pth_root(3))^(2^3)701True702sage: y.pth_root(2)703b^11 + b^10 + b^9 + b^7 + b^5 + b^4 + b^2 + b704"""705return self.pth_power(-k)706707708709