Path: blob/master/sage/rings/function_field/function_field_element.pyx
4036 views
r"""1Function Field Elements23AUTHORS:45- William Stein: initial version67- Robert Bradshaw (2010-05-27): cythonize function field elements89- Julian Rueth (2011-06-28): treat zero correctly1011- Maarten Derickx (2011-09-11): added doctests, fixed pickling12"""13#*****************************************************************************14# Copyright (C) 2010 William Stein <[email protected]>15# Copyright (C) 2010 Robert Bradshaw <[email protected]>16# Copyright (C) 2011 Julian Rueth <[email protected]>17# Copyright (C) 2011 Maarten Derickx <[email protected]>18#19# Distributed under the terms of the GNU General Public License (GPL)20# as published by the Free Software Foundation; either version 2 of21# the License, or (at your option) any later version.22# http://www.gnu.org/licenses/23#*****************************************************************************2425include "../../ext/stdsage.pxi"2627from sage.structure.element cimport FieldElement, RingElement, ModuleElement, Element2829def is_FunctionFieldElement(x):30"""31Return True if x is any type of function field element.3233EXAMPLES::3435sage: t = FunctionField(QQ,'t').gen()36sage: sage.rings.function_field.function_field_element.is_FunctionFieldElement(t)37True38sage: sage.rings.function_field.function_field_element.is_FunctionFieldElement(0)39False40"""41if isinstance(x, FunctionFieldElement): return True42from function_field import is_FunctionField43return is_FunctionField(x.parent())4445def make_FunctionFieldElement(parent, element_class, representing_element):46"""47Used for unpickling FunctionFieldElement objects (and subclasses).4849EXAMPLES::5051sage: from sage.rings.function_field.function_field_element import make_FunctionFieldElement52sage: K.<x> = FunctionField(QQ)53sage: make_FunctionFieldElement(K, K._element_class, (x+1)/x)54(x + 1)/x55"""56return element_class(parent, representing_element, reduce=False)5758cdef class FunctionFieldElement(FieldElement):59"""60The abstract base class for function field elements.6162EXAMPLES::6364sage: t = FunctionField(QQ,'t').gen()65sage: isinstance(t, sage.rings.function_field.function_field_element.FunctionFieldElement)66True67"""6869cdef readonly object _x70cdef readonly object _matrix7172def __reduce__(self):73"""74EXAMPLES::7576sage: K = FunctionField(QQ,'x')77sage: f = K.random_element()78sage: loads(f.dumps()) == f79True80"""81return (make_FunctionFieldElement,82(self._parent, type(self), self._x))8384cdef FunctionFieldElement _new_c(self):85cdef FunctionFieldElement x = <FunctionFieldElement>PY_NEW_SAME_TYPE(self)86x._parent = self._parent87return x8889def _latex_(self):90"""91EXAMPLES::9293sage: K.<t> = FunctionField(QQ)94sage: latex((t+1)/t)95\frac{t + 1}{t}96sage: latex((t+1)/t^67)97\frac{t + 1}{t^{67}}98sage: latex((t+1/2)/t^67)99\frac{t + \frac{1}{2}}{t^{67}}100"""101return self._x._latex_()102103def matrix(self):104r"""105Return the matrix of multiplication by self, interpreting self as an element106of a vector space over its base field.107108EXAMPLES:109110A rational function field::111112sage: K.<t> = FunctionField(QQ)113sage: t.matrix()114[t]115sage: (1/(t+1)).matrix()116[1/(t + 1)]117118Now an example in a nontrivial extension of a rational function field::119120sage: K.<x> = FunctionField(QQ); R.<y> = K[]121sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)122sage: y.matrix()123[ 0 1]124[-4*x^3 x]125sage: y.matrix().charpoly('Z')126Z^2 - x*Z + 4*x^3127128An example in a relative extension, where neither function129field is rational::130131sage: K.<x> = FunctionField(QQ); R.<y> = K[]132sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)133sage: M.<T> = L[]; Z.<alpha> = L.extension(T^3 - y^2*T + x)134sage: alpha.matrix()135[ 0 1 0]136[ 0 0 1]137[ -x x*y - 4*x^3 0]138139We show that this matrix does indeed work as expected when making a140vector space from a function field::141142sage: K.<x>=FunctionField(QQ)143sage: R.<y> = K[]144sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x))145sage: V, from_V, to_V = L.vector_space()146sage: y5 = to_V(y^5); y5147((x^4 + 1)/x, 2*x, 0, 0, 0)148sage: y4y = to_V(y^4) * y.matrix(); y4y149((x^4 + 1)/x, 2*x, 0, 0, 0)150sage: y5 == y4y151True152"""153if self._matrix is None:154# Multiply each power of field generator on the left by this155# element; make matrix whose rows are the coefficients of the156# result, and transpose.157K = self.parent()158v = []159x = K.gen()160a = K(1)161d = K.degree()162for n in range(d):163v += (a*self).list()164a *= x165k = K.base_ring()166import sage.matrix.matrix_space167M = sage.matrix.matrix_space.MatrixSpace(k, d)168self._matrix = M(v)169return self._matrix170171def trace(self):172"""173Return the trace of this function field element.174175EXAMPLES::176177sage: K.<x> = FunctionField(QQ); R.<y> = K[]178sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)179sage: y.trace()180x181"""182return self.matrix().trace()183184def norm(self):185"""186Return the norm of this function field element.187188EXAMPLES::189190sage: K.<x> = FunctionField(QQ); R.<y> = K[]191sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)192sage: y.norm()1934*x^3194195The norm is relative::196197sage: K.<x> = FunctionField(QQ); R.<y> = K[]198sage: L.<y> = K.extension(y^2 - x*y + 4*x^3); R.<z> = L[]199sage: M.<z> = L.extension(z^3 - y^2*z + x)200sage: z.norm()201-x202sage: z.norm().parent()203Function field in y defined by y^2 - x*y + 4*x^3204"""205return self.matrix().determinant()206207def characteristic_polynomial(self, *args, **kwds):208"""209Return the characteristic polynomial of this function field210element. Give an optional input string to name the variable211in the characteristic polynomial.212213EXAMPLES::214215sage: K.<x> = FunctionField(QQ); R.<y> = K[]216sage: L.<y> = K.extension(y^2 - x*y + 4*x^3); R.<z> = L[]217sage: M.<z> = L.extension(z^3 - y^2*z + x)218sage: x.characteristic_polynomial('W')219W - x220sage: y.characteristic_polynomial('W')221W^2 - x*W + 4*x^3222sage: z.characteristic_polynomial('W')223W^3 + (-x*y + 4*x^3)*W + x224"""225return self.matrix().characteristic_polynomial(*args, **kwds)226227charpoly = characteristic_polynomial228229def minimal_polynomial(self, *args, **kwds):230"""231Return the minimal polynomial of this function field element.232Give an optional input string to name the variable in the233characteristic polynomial.234235EXAMPLES::236237sage: K.<x> = FunctionField(QQ); R.<y> = K[]238sage: L.<y> = K.extension(y^2 - x*y + 4*x^3); R.<z> = L[]239sage: M.<z> = L.extension(z^3 - y^2*z + x)240sage: x.minimal_polynomial('W')241W - x242sage: y.minimal_polynomial('W')243W^2 - x*W + 4*x^3244sage: z.minimal_polynomial('W')245W^3 + (-x*y + 4*x^3)*W + x246"""247return self.matrix().minimal_polynomial(*args, **kwds)248249minpoly = minimal_polynomial250251def is_integral(self):252r"""253Determine if self is integral over the maximal order of the base field.254255EXAMPLES::256257sage: K.<x> = FunctionField(QQ); R.<y> = K[]258sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)259sage: y.is_integral()260True261sage: (y/x).is_integral()262True263sage: (y/x)^2 - (y/x) + 4*x2640265sage: (y/x^2).is_integral()266False267sage: (y/x).minimal_polynomial('W')268W^2 - W + 4*x269"""270R = self.parent().base_field().maximal_order()271return all([a in R for a in self.minimal_polynomial()])272273cdef class FunctionFieldElement_polymod(FunctionFieldElement):274"""275Elements of a finite extension of a function field.276277EXAMPLES::278279sage: K.<x> = FunctionField(QQ); R.<y> = K[]280sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)281sage: x*y + 1/x^3282x*y + 1/x^3283"""284def __init__(self, parent, x, reduce=True):285"""286EXAMPLES::287288sage: K.<x> = FunctionField(QQ); R.<y> = K[]289sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)290sage: type(y)291<type 'sage.rings.function_field.function_field_element.FunctionFieldElement_polymod'>292"""293FieldElement.__init__(self, parent)294if reduce:295self._x = x % self._parent.polynomial()296else:297self._x = x298299def element(self):300"""301Return the underlying polynomial that represents this element.302303EXAMPLES::304sage: K.<x> = FunctionField(QQ); R.<T> = K[]305sage: L.<y> = K.extension(T^2 - x*T + 4*x^3)306sage: f = y/x^2 + x/(x^2+1); f3071/x^2*y + x/(x^2 + 1)308sage: f.element()3091/x^2*T + x/(x^2 + 1)310sage: type(f.element())311<class 'sage.rings.polynomial.polynomial_element_generic.Polynomial_generic_dense_field'>312"""313return self._x314315def _repr_(self):316"""317EXAMPLES::318319sage: K.<x> = FunctionField(QQ); R.<y> = K[]320sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)321sage: y._repr_()322'y'323"""324return self._x._repr(name=self.parent().variable_name())325326def __nonzero__(self):327"""328EXAMPLES::329330sage: K.<x> = FunctionField(QQ); R.<y> = K[]331sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)332sage: bool(y)333True334sage: bool(L(0))335False336sage: bool(L.coerce(L.polynomial()))337False338"""339return not not self._x340341cdef int _cmp_c_impl(self, Element other) except -2:342"""343EXAMPLES::344345sage: K.<x> = FunctionField(QQ); R.<y> = K[]346sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)347sage: cmp(L(0), 0)3480349sage: cmp(y, L(2)) != 0350True351"""352cdef FunctionFieldElement left = <FunctionFieldElement>self353cdef FunctionFieldElement right = <FunctionFieldElement>other354return cmp(left._x, right._x)355356cpdef ModuleElement _add_(self, ModuleElement right):357"""358EXAMPLES::359360sage: K.<x> = FunctionField(QQ); R.<y> = K[]361sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)362sage: (2*y + x/(1+x^3)) + (3*y + 5*x*y) # indirect doctest363(5*x + 5)*y + x/(x^3 + 1)364sage: (y^2 - x*y + 4*x^3)==0 # indirect doctest365True366sage: -y+y3670368"""369cdef FunctionFieldElement res = self._new_c()370res._x = self._x + (<FunctionFieldElement>right)._x371return res372373cpdef ModuleElement _sub_(self, ModuleElement right):374"""375EXAMPLES::376377sage: K.<x> = FunctionField(QQ); R.<y> = K[]378sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)379sage: (2*y + x/(1+x^3)) - (3*y + 5*x*y) # indirect doctest380(-5*x - 1)*y + x/(x^3 + 1)381sage: y-y3820383"""384cdef FunctionFieldElement res = self._new_c()385res._x = self._x - (<FunctionFieldElement>right)._x386return res387388cpdef RingElement _mul_(self, RingElement right):389"""390EXAMPLES::391392sage: K.<x> = FunctionField(QQ); R.<y> = K[]393sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)394sage: y * (3*y + 5*x*y) # indirect doctest395(5*x^2 + 3*x)*y - 20*x^4 - 12*x^3396"""397cdef FunctionFieldElement res = self._new_c()398res._x = (self._x * (<FunctionFieldElement>right)._x) % self._parent.polynomial()399return res400401cpdef RingElement _div_(self, RingElement right):402"""403EXAMPLES::404405sage: K.<x> = FunctionField(QQ); R.<y> = K[]406sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)407sage: (2*y + x/(1+x^3)) / (2*y + x/(1+x^3)) # indirect doctest4081409sage: 1 / (y^2 - x*y + 4*x^3) # indirect doctest410Traceback (most recent call last):411...412ZeroDivisionError: Cannot invert 0413"""414return self * ~right415416def __invert__(self):417"""418EXAMPLES::419420sage: K.<x> = FunctionField(QQ); R.<y> = K[]421sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)422sage: a = ~(2*y + 1/x); a # indirect doctest423(-x^2/(8*x^5 + x^2 + 1/2))*y + (2*x^3 + x)/(16*x^5 + 2*x^2 + 1)424sage: a*(2*y + 1/x)4251426"""427if self.is_zero():428raise ZeroDivisionError, "Cannot invert 0"429P = self._parent430return P(self._x.xgcd(P._polynomial)[1])431432def list(self):433"""434Return a list of coefficients of self, i.e., if self is an element of435a function field K[y]/(f(y)), then return the coefficients of the436reduced presentation as a polynomial in K[y].437438EXAMPLES::439440sage: K.<x> = FunctionField(QQ); R.<y> = K[]441sage: L.<y> = K.extension(y^2 - x*y + 4*x^3)442sage: a = ~(2*y + 1/x); a443(-x^2/(8*x^5 + x^2 + 1/2))*y + (2*x^3 + x)/(16*x^5 + 2*x^2 + 1)444sage: a.list()445[(2*x^3 + x)/(16*x^5 + 2*x^2 + 1), -x^2/(8*x^5 + x^2 + 1/2)]446sage: (x*y).list()447[0, x]448"""449return self._x.padded_list(self.parent().degree())450451cdef class FunctionFieldElement_rational(FunctionFieldElement):452"""453Elements of a rational function field.454455EXAMPLES::456457sage: K.<t> = FunctionField(QQ); K458Rational function field in t over Rational Field459"""460def __init__(self, parent, x, reduce=True):461"""462EXAMPLES::463464sage: FunctionField(QQ,'t').gen()^3465t^3466"""467FieldElement.__init__(self, parent)468self._x = x469470def element(self):471"""472Return the underlying fraction field element that represents this element.473474EXAMPLES::475476sage: K.<t> = FunctionField(GF(7))477sage: t.element()478t479sage: type(t.element())480<type 'sage.rings.fraction_field_FpT.FpTElement'>481482sage: K.<t> = FunctionField(GF(131101))483sage: t.element()484t485sage: type(t.element())486<class 'sage.rings.fraction_field_element.FractionFieldElement_1poly_field'>487"""488return self._x489490def list(self):491"""492Return a list of coefficients of self, i.e., if self is an element of493a function field K[y]/(f(y)), then return the coefficients of the494reduced presentation as a polynomial in K[y].495Since self is a member of a rational function field, this simply returns496the list `[self]`497498EXAMPLES::499500sage: K.<t> = FunctionField(QQ)501sage: t.list()502[t]503"""504return [self]505506def _repr_(self):507"""508EXAMPLES::509510sage: K.<t> = FunctionField(QQ)511sage: t._repr_()512't'513"""514return repr(self._x)515516def __nonzero__(self):517"""518EXAMPLES::519520sage: K.<t> = FunctionField(QQ)521sage: bool(t)522True523sage: bool(K(0))524False525sage: bool(K(1))526True527"""528return not not self._x529530cdef int _cmp_c_impl(self, Element other) except -2:531"""532EXAMPLES::533534sage: K.<t> = FunctionField(QQ)535sage: cmp(t, 0)5361537sage: cmp(t, t^2)538-1539"""540cdef int c = cmp(type(self), type(other))541if c: return c542cdef FunctionFieldElement left = <FunctionFieldElement>self543cdef FunctionFieldElement right = <FunctionFieldElement>other544c = cmp(left._parent, right._parent)545return c or cmp(left._x, right._x)546547cpdef ModuleElement _add_(self, ModuleElement right):548"""549EXAMPLES::550551sage: K.<t> = FunctionField(QQ)552sage: t + (3*t^3) # indirect doctest5533*t^3 + t554"""555cdef FunctionFieldElement res = self._new_c()556res._x = self._x + (<FunctionFieldElement>right)._x557return res558559cpdef ModuleElement _sub_(self, ModuleElement right):560"""561EXAMPLES::562563sage: K.<t> = FunctionField(QQ)564sage: t - (3*t^3) # indirect doctest565-3*t^3 + t566"""567cdef FunctionFieldElement res = self._new_c()568res._x = self._x - (<FunctionFieldElement>right)._x569return res570571cpdef RingElement _mul_(self, RingElement right):572"""573EXAMPLES::574575sage: K.<t> = FunctionField(QQ)576sage: (t+1) * (t^2-1) # indirect doctest577t^3 + t^2 - t - 1578"""579cdef FunctionFieldElement res = self._new_c()580res._x = self._x * (<FunctionFieldElement>right)._x581return res582583cpdef RingElement _div_(self, RingElement right):584"""585EXAMPLES::586587sage: K.<t> = FunctionField(QQ)588sage: (t+1) / (t^2 - 1) # indirect doctest5891/(t - 1)590"""591cdef FunctionFieldElement res = self._new_c()592res._parent = self._parent.fraction_field()593res._x = self._x / (<FunctionFieldElement>right)._x594return res595596def numerator(self):597"""598EXAMPLES::599600sage: K.<t> = FunctionField(QQ)601sage: f = (t+1) / (t^2 - 1/3); f602(t + 1)/(t^2 - 1/3)603sage: f.numerator()604t + 1605"""606return self._x.numerator()607608def denominator(self):609"""610EXAMPLES::611612sage: K.<t> = FunctionField(QQ)613sage: f = (t+1) / (t^2 - 1/3); f614(t + 1)/(t^2 - 1/3)615sage: f.denominator()616t^2 - 1/3617"""618return self._x.denominator()619620def valuation(self, v):621"""622EXAMPLES::623624sage: K.<t> = FunctionField(QQ)625sage: f = (t-1)^2 * (t+1) / (t^2 - 1/3)^3626sage: f.valuation(t-1)6272628sage: f.valuation(t)6290630sage: f.valuation(t^2 - 1/3)631-3632"""633R = self._parent._ring634return self._x.valuation(R(self._parent(v)._x))635636def is_square(self):637"""638Returns whether self is a square.639640EXAMPLES::641642sage: K.<t> = FunctionField(QQ)643sage: t.is_square()644False645sage: (t^2/4).is_square()646True647sage: f = 9 * (t+1)^6 / (t^2 - 2*t + 1); f.is_square()648True649650sage: K.<t> = FunctionField(GF(5))651sage: (-t^2).is_square()652True653sage: (-t^2).sqrt()6542*t655"""656return self._x.is_square()657658def sqrt(self, all=False):659"""660Returns the square root of self.661662EXAMPLES::663664sage: K.<t> = FunctionField(QQ)665sage: f = t^2 - 2 + 1/t^2; f.sqrt()666(t^2 - 1)/t667sage: f = t^2; f.sqrt(all=True)668[t, -t]669670TESTS::671672sage: K(4/9).sqrt()6732/3674sage: K(0).sqrt(all=True)675[0]676"""677if all:678return [self._parent(r) for r in self._x.sqrt(all=True)]679else:680return self._parent(self._x.sqrt())681682def factor(self):683"""684Factor this rational function.685686EXAMPLES::687688sage: K.<t> = FunctionField(QQ)689sage: f = (t+1) / (t^2 - 1/3)690sage: f.factor()691(t + 1) * (t^2 - 1/3)^-1692sage: (7*f).factor()693(7) * (t + 1) * (t^2 - 1/3)^-1694sage: ((7*f).factor()).unit()6957696sage: (f^3).factor()697(t + 1)^3 * (t^2 - 1/3)^-3698"""699P = self.parent()700F = self._x.factor()701from sage.structure.factorization import Factorization702return Factorization([(P(a),e) for a,e in F], unit=F.unit())703704def inverse_mod(self, I):705r"""706Return an inverse of self modulo the integral ideal `I`, if707defined, i.e., if `I` and self together generate the unit708ideal.709710EXAMPLES::711712sage: K.<x> = FunctionField(QQ)713sage: O = K.maximal_order(); I = O.ideal(x^2+1)714sage: t = O(x+1).inverse_mod(I); t715-1/2*x + 1/2716sage: (t*(x+1) - 1) in I717True718"""719assert len(I.gens()) == 1720f = I.gens()[0]._x721assert f.denominator() == 1722assert self._x.denominator() == 1723return self.parent()(self._x.numerator().inverse_mod(f.numerator()))724725726