r"""
Function fields
EXAMPLES::
We create an extension of a rational function fields, and do some
simple arithmetic in it::
sage: K.<x> = FunctionField(GF(5^2,'a')); K
Rational function field in x over Finite Field in a of size 5^2
sage: R.<y> = K[]
sage: L.<y> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L
Function field in y defined by y^5 + 3*x*y + (4*x^4 + 4)/x
sage: y^4
y^4
sage: y^5
2*x*y + (x^4 + 1)/x
sage: a = 1/y; a
(4*x/(4*x^4 + 4))*y^4 + 2*x^2/(4*x^4 + 4)
sage: a * y
1
We next make an extension of the above function field, illustrating
that arithmetic with a tower of 3 fields is fully supported::
sage: S.<t> = L[]
sage: M.<t> = L.extension(t^2 - x*y)
sage: M
Function field in t defined by t^2 + 4*x*y
sage: t^2
x*y
sage: 1/t
((1/(x^4 + 1))*y^4 + 2*x/(4*x^4 + 4))*t
sage: M.base_field()
Function field in y defined by y^5 + 3*x*y + (4*x^4 + 4)/x
sage: M.base_field().base_field()
Rational function field in x over Finite Field in a of size 5^2
"""
from sage.structure.category_object import CategoryObject
from sage.rings.ring import Field
from sage.rings.integer_ring import ZZ
from sage.structure.parent_gens import ParentWithGens
import function_field_element
from category import FunctionFields
CAT = FunctionFields()
import maps
def is_FunctionField(x):
"""
Return True if x is of function field type.
EXAMPLES::
sage: from sage.rings.function_field.all import is_FunctionField
sage: is_FunctionField(QQ)
False
sage: is_FunctionField(FunctionField(QQ,'t'))
True
"""
return isinstance(x, FunctionField)
class FunctionField(Field):
"""
The abstract base class for all function fields.
EXAMPLES::
sage: K.<x> = FunctionField(QQ)
sage: isinstance(K, sage.rings.function_field.function_field.FunctionField)
True
"""
def characteristic(self):
"""
Return the characteristic of this function field.
EXAMPLES::
sage: R.<t> = FunctionField(QQ)
sage: R.characteristic()
0
sage: R.<t> = FunctionField(GF(7))
sage: R.characteristic()
7
"""
return self.constant_field().characteristic()
def is_finite(self):
"""
Return whether this function field is finite, which it is not.
EXAMPLES::
sage: R.<t> = FunctionField(QQ)
sage: R.is_finite()
False
sage: R.<t> = FunctionField(GF(7))
sage: R.is_finite()
False
"""
return False
def extension(self, f, names=None):
"""
Create an extension L = K[y]/(f(y)) of a function field,
defined by a univariate polynomial in one variable over this
function field K.
INPUT:
- `f` -- a univariate polynomial over self
- ``names`` -- None or string or length-1 tuple
OUTPUT:
- a function field
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: K.extension(y^5 - x^3 - 3*x + x*y)
Function field in y defined by y^5 + x*y - x^3 - 3*x
A nonintegral defining polynomial::
sage: K.<t> = FunctionField(QQ); R.<y> = K[]
sage: K.extension(y^3 + (1/t)*y + t^3/(t+1))
Function field in y defined by y^3 + 1/t*y + t^3/(t + 1)
The defining polynomial need not be monic or integral::
sage: K.extension(t*y^3 + (1/t)*y + t^3/(t+1))
Function field in y defined by t*y^3 + 1/t*y + t^3/(t + 1)
"""
if names is None:
names = f.variable_name()
return FunctionField_polymod(f, names)
def order_with_basis(self, basis, check=True):
"""
Return the order with given basis over the maximal order of
the base field.
INPUT:
- ``basis`` -- a list of elements of self
- ``check`` -- bool (default: True); if True, check that
the basis is really linearly independent
OUTPUT:
- an order in this function field
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]; L.<Y> = K.extension(y^3 + x^3 + 4*x + 1)
sage: O = L.order_with_basis([1, Y, Y^2]); O
Order in Function field in Y defined by y^3 + x^3 + 4*x + 1
sage: O.basis()
(1, Y, Y^2)
sage: O = L.order_with_basis([x, x^2 + x*Y, (2/3)*Y^2]); O
Order in Function field in Y defined by y^3 + x^3 + 4*x + 1
sage: O.basis()
(x, x*Y + x^2, 2/3*Y^2)
"""
from function_field_order import FunctionFieldOrder_basis
return FunctionFieldOrder_basis([self(a) for a in basis], check=check)
def order(self, x, check=True):
"""
Return the order in this function field generated over the
maximal order by x or the elements of x if x is a list.
INPUT:
- ``x`` -- element of self, or a list of elements of self
- ``check`` -- bool (default: True); if True, check that
x really generates an order
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]; L.<Y> = K.extension(y^3 + x^3 + 4*x + 1)
sage: O = L.order(Y); O
Order in Function field in Y defined by y^3 + x^3 + 4*x + 1
sage: O.basis()
(1, Y, Y^2)
sage: Z = K.order(x); Z
Order in Rational function field in x over Rational Field
sage: Z.basis()
(1,)
Orders with multiple generators, not yet supported::
sage: Z = K.order([x,x^2]); Z
Traceback (most recent call last):
...
NotImplementedError
"""
if not isinstance(x, (list, tuple)):
x = [x]
if len(x) == 1:
g = x[0]
basis = [self(1)]
for i in range(self.degree()-1):
basis.append(basis[-1]*g)
else:
raise NotImplementedError
return self.order_with_basis(basis, check=check)
def _coerce_map_from_(self, R):
"""
Return True if there is a coerce map from R to self.
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]; L.<Y> = K.extension(y^3 + x^3 + 4*x + 1)
sage: L.equation_order()
Order in Function field in Y defined by y^3 + x^3 + 4*x + 1
sage: L._coerce_map_from_(L.equation_order())
True
sage: L._coerce_map_from_(GF(7))
False
"""
from function_field_order import FunctionFieldOrder
if isinstance(R, FunctionFieldOrder) and R.fraction_field() == self:
return True
return False
def hom(self, im_gens, base_morphism=None):
"""
Create a homomorphism from self to another function field.
INPUT:
- ``im_gens`` -- a list of images of the generators of self
and of successive base rings.
- ``base_morphism`` -- (default: None) a homomorphism of
the base ring, after the im_gens are used. Thus if
im_gens has length 2, then base_morphism should be a morphism
from self.base_ring().base_ring().
EXAMPLES::
We create a rational function field, and a quadratic extension of it::
sage: R.<x> = FunctionField(QQ); S.<y> = R[]
sage: L.<y> = R.extension(y^2 - x^3 - 1)
We make the field automorphism that sends y to -y::
sage: f = L.hom(-y); f
Morphism of function fields defined by y |--> -y
Evaluation works::
sage: f(y*x - 1/x)
-x*y - 1/x
We try to define an invalid morphism::
sage: f = L.hom(y+1); f
Traceback (most recent call last):
...
ValueError: invalid morphism
We make a morphism of the base rational function field::
sage: phi = R.hom(x+1); phi
Morphism of function fields defined by x |--> x + 1
sage: phi(x^3 - 3)
x^3 + 3*x^2 + 3*x - 2
sage: (x+1)^3-3
x^3 + 3*x^2 + 3*x - 2
We make a morphism by specifying where the generators and the
base generators go::
sage: L.hom([-y, x])
Morphism of function fields defined by y |--> -y, x |--> x
We make another extension of a rational function field::
sage: R2.<t> = FunctionField(QQ); S2.<w> = R2[]
sage: L2.<w> = R.extension((4*w)^2 - (t+1)^3 - 1)
We define a morphism, by givin the images of generators::
sage: f = L.hom([4*w, t+1]); f
Morphism of function fields defined by y |--> 4*w, x |--> t + 1
Evaluation works, as expected::
sage: f(y+x)
4*w + t + 1
sage: f(x*y + x/(x^2+1))
(4*t + 4)*w + (t + 1)/(t^2 + 2*t + 2)
"""
if not isinstance(im_gens, (list,tuple)):
im_gens = [im_gens]
if len(im_gens) > 1:
base_morphism = self.base_field().hom(im_gens[1:], base_morphism)
return maps.FunctionFieldMorphism(self.Hom(im_gens[0].parent()), im_gens[0], base_morphism)
class FunctionField_polymod(FunctionField):
"""
A function field defined by a univariate polynomial, as an
extension of the base field.
EXAMPLES::
We make a function field defined by a degree 5 polynomial over the
rational function field over the rational numbers::
sage: K.<x> = FunctionField(QQ)
sage: R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L
Function field in w defined by y^5 - 2*x*y + (-x^4 - 1)/x
We next make a function field over the above nontrivial function
field L::
sage: S.<T> = L[]
sage: M.<alpha> = L.extension(T^2 + w*T + y); M
Function field in alpha defined by T^2 + w*T + w
sage: 1/alpha
((x/(-x^4 - 1))*w^4 - 2*x^2/(-x^4 - 1))*alpha - 1
sage: alpha * (1/alpha)
1
We drill down the tower of function fields::
sage: M.base_field()
Function field in w defined by y^5 - 2*x*y + (-x^4 - 1)/x
sage: M.base_field().base_field()
Rational function field in x over Rational Field
sage: M.base_field().base_field().constant_field()
Rational Field
sage: M.constant_base_field()
Rational Field
"""
def __init__(self, polynomial, names, category=CAT):
"""
Create a function field defined as an extension of another
function field by adjoining a root of a univariate polynomial.
INPUT:
- ``polynomial`` -- a univariate polynomial over a function field
- ``names`` -- variable names (as a tuple of length 1 or string)
- ``category`` -- a category (defaults to category of function fields)
EXAMPLES::
We create an extension of function fields::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L = K.extension(y^5 - x^3 - 3*x + x*y); L
Function field in y defined by y^5 + x*y - x^3 - 3*x
Note the type::
sage: type(L)
<class 'sage.rings.function_field.function_field.FunctionField_polymod_with_category'>
We can set the variable name, which doesn't have to be y::
sage: L.<w> = K.extension(y^5 - x^3 - 3*x + x*y); L
Function field in w defined by y^5 + x*y - x^3 - 3*x
"""
from sage.rings.polynomial.all import is_Polynomial
if names is None:
names = (polynomial.variable_name(), )
if not is_Polynomial(polynomial):
raise TypeError, "polynomial must be a polynomial"
if polynomial.degree() <= 0:
raise ValueError, "polynomial must have positive degree"
base_field = polynomial.base_ring()
if not isinstance(base_field, FunctionField):
raise TypeError, "polynomial must be over a function"
self._base_field = base_field
self._polynomial = polynomial
ParentWithGens.__init__(self, base_field,
names=names, category = category)
self._hash = hash(polynomial)
self._ring = self._polynomial.parent()
self._populate_coercion_lists_(coerce_list=[base_field, self._ring])
self._gen = self(self._ring.gen())
def __hash__(self):
"""
Return hash of this function field.
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L = K.extension(y^5 - x^3 - 3*x + x*y); hash(L)
3183366741743088279 # 64-bit
? # 32-bit
"""
return self._hash
def monic_integral_model(self, names):
"""
Return a function field isomorphic to self, but with defining
polynomial that is monic and integral over the base field.
INPUT::
- ``names`` -- name of the generator of the new field this function constructs
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<alpha> = K.extension(x^2*y^5 - 1/x); L
Function field in alpha defined by x^2*y^5 - 1/x
sage: A, from_A, to_A = L.monic_integral_model('beta')
sage: A
Function field in beta defined by y^5 - x^12
sage: from_A
Morphism of function fields defined by beta |--> x^3*alpha
sage: to_A
Morphism of function fields defined by alpha |--> 1/x^3*beta
sage: to_A(alpha)
1/x^3*beta
sage: from_A(to_A(alpha))
alpha
sage: from_A(to_A(1/alpha))
x^3*alpha^4
sage: from_A(to_A(1/alpha)) == 1/alpha
True
"""
g, d = self._make_monic(self.polynomial())
R = self.base_field()
K = R.extension(g, names=names)
to_K = self.hom(K.gen() / d)
from_K = K.hom(self.gen() * d)
return K, from_K, to_K
def _make_monic(self, f):
r"""
Let alpha be a root of f. This function returns a monic
integral polynomial g and an element d of the base field such
that g(alpha*d) = 0.
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[];
sage: L.<alpha> = K.extension(x^2*y^5 - 1/x)
sage: g, d = L._make_monic(L.polynomial()); g,d
(y^5 - x^12, x^3)
sage: g(alpha*d)
0
"""
R = f.base_ring()
if not isinstance(R, RationalFunctionField):
raise NotImplementedError
n = f.degree()
c = f.leading_coefficient()
if c != 1:
f = f / c
from sage.rings.arith import lcm
d = lcm([b.denominator() for b in f.list() if b])
if d != 1:
x = f.parent().gen()
g = (d**n) * f(x/d)
else:
g = f
return g, d
def constant_field(self):
"""
Return the algebraic closure of the constant field of the base
field in this function field.
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x))
sage: L.constant_field()
Traceback (most recent call last):
...
NotImplementedError
"""
raise NotImplementedError
def constant_base_field(self):
"""
Return the constant field of the base rational function field.
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L
Function field in w defined by y^5 - 2*x*y + (-x^4 - 1)/x
sage: L.constant_base_field()
Rational Field
"""
return self.base_field().constant_base_field()
def degree(self):
"""
Return the degree of this function field over its base
function field.
EXAMPLES::
sage: K.<x> = FunctionField(QQ)
sage: R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L
Function field in w defined by y^5 - 2*x*y + (-x^4 - 1)/x
sage: L.degree()
5
"""
return self._polynomial.degree()
def _repr_(self):
"""
Return string representation of this function field.
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x))
sage: L._repr_()
'Function field in w defined by y^5 - 2*x*y + (-x^4 - 1)/x'
"""
return "Function field in %s defined by %s"%(self.variable_name(), self._polynomial)
def base_field(self):
"""
Return the base field of this function field. This function
field is presented as L = K[y]/(f(y)), and the base field is
by definition the field K.
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x))
sage: L.base_field()
Rational function field in x over Rational Field
"""
return self._base_field
def random_element(self, *args, **kwds):
"""
Create a random element of this function field. Parameters
are passed onto the random_element method of the base_field.
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<w> = K.extension(y^2 - (x^2 + x))
sage: L.random_element()
((x^2 - x + 2/3)/(x^2 + 1/3*x - 1))*w^2 + ((-1/4*x^2 + 1/2*x - 1)/(-5/2*x + 2/3))*w + (-1/2*x^2 - 4)/(-12*x^2 + 1/2*x - 1/95)
"""
return self(self._ring.random_element(degree=self.degree(), *args, **kwds))
def polynomial(self):
"""
Return the univariate polynomial that defines this function
field, i.e., the polynomial f(y) so that this function field
is of the form K[y]/(f(y)).
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x))
sage: L.polynomial()
y^5 - 2*x*y + (-x^4 - 1)/x
"""
return self._polynomial
def polynomial_ring(self):
"""
Return the polynomial ring used to represents elements of this
function field. If we view this function field as being presented
as K[y]/(f(y)), then this function returns the ring K[y].
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x))
sage: L.polynomial_ring()
Univariate Polynomial Ring in y over Rational function field in x over Rational Field
"""
return self._ring
def vector_space(self):
"""
Return a vector space V and isomorphisms self --> V and V --> self.
This function allows us to identify the elements of self with
elements of a vector space over the base field, which is
useful for representation and arithmetic with orders, ideals,
etc.
OUTPUT:
- ``V`` - a vector space over the rational numbers
- ``from_V`` - an isomorphism from V to self
- ``to_V`` - an isomorphism from self to V
EXAMPLES::
We define a function field::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x)); L
Function field in w defined by y^5 - 2*x*y + (-x^4 - 1)/x
We get the vector spaces, and maps back and forth::
sage: V, from_V, to_V = L.vector_space()
sage: V
Vector space of dimension 5 over Rational function field in x over Rational Field
sage: from_V
Isomorphism map:
From: Vector space of dimension 5 over Rational function field in x over Rational Field
To: Function field in w defined by y^5 - 2*x*y + (-x^4 - 1)/x
sage: to_V
Isomorphism map:
From: Function field in w defined by y^5 - 2*x*y + (-x^4 - 1)/x
To: Vector space of dimension 5 over Rational function field in x over Rational Field
We convert an element of the vector space back to the function field::
sage: from_V(V.1)
w
We define an interesting element of the function field::
sage: a = 1/L.0; a
(-x/(-x^4 - 1))*w^4 + 2*x^2/(-x^4 - 1)
We convert it to the vector space, and get a vector over the base field::
sage: to_V(a)
(2*x^2/(-x^4 - 1), 0, 0, 0, -x/(-x^4 - 1))
We convert to and back, and get the same element::
sage: from_V(to_V(a)) == a
True
In the other direction::
sage: v = x*V.0 + (1/x)*V.1
sage: to_V(from_V(v)) == v
True
"""
try: return self._vector_space
except AttributeError:
V = self.base_field()**self.degree()
from_V = maps.MapVectorSpaceToFunctionField(V, self)
to_V = maps.MapFunctionFieldToVectorSpace(self, V)
self._vector_space = (V, from_V, to_V)
return self._vector_space
def maximal_order(self):
"""
Return the maximal_order of self. If we view self as L =
K[y]/(f(y)), then this is the ring of elements of L that are
integral over K.
EXAMPLES::
This is not yet implemented...::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x))
sage: L.maximal_order()
Traceback (most recent call last):
...
NotImplementedError
"""
raise NotImplementedError
def _element_constructor_(self, x):
r"""
Make x into an element of this function field, possibly not canonically.
INPUT:
- ``x`` - the element
OUTPUT:
``x``, as an element of this function field
TESTS::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x))
sage: L._element_constructor_(L.polynomial_ring().gen())
w
"""
if x.parent() is self._ring:
return function_field_element.FunctionFieldElement_polymod(self, x)
if isinstance(x, function_field_element.FunctionFieldElement):
return function_field_element.FunctionFieldElement_polymod(self, self._ring(x.element()))
return function_field_element.FunctionFieldElement_polymod(self, self._ring(x))
def gen(self, n=0):
"""
Return the n-th generator of this function field. By default n=0; any other
value of n leads to an error. The generator is the class of y, if we view
self as being presented as K[y]/(f(y)).
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x))
sage: L.gen()
w
sage: L.gen(1)
Traceback (most recent call last):
...
IndexError: Only one generator.
"""
if n != 0: raise IndexError, "Only one generator."
return self._gen
def ngens(self):
"""
Return the number of generators of this function field over
its base field. This is by definition 1.
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x))
sage: L.ngens()
1
"""
return 1
def equation_order(self):
"""
If we view self as being presented as K[y]/(f(y)), then this
function returns the order generated by the class of y. If f
is not monic, then self._make_monic is called, and instead we
get the order generated by some integral multiple of a root of
alpha.
EXAMPLES::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<w> = K.extension(y^5 - (x^3 + 2*x*y + 1/x))
sage: L.equation_order()
Order in Function field in w defined by y^5 - 2*x*y + (-x^4 - 1)/x
We try an example, in which the defining polynomial is not
monic and is not integral::
sage: K.<x> = FunctionField(QQ); R.<y> = K[]
sage: L.<alpha> = K.extension(x^2*y^5 - 1/x); L
Function field in alpha defined by x^2*y^5 - 1/x
sage: O = L.equation_order(); O
Order in Function field in alpha defined by x^2*y^5 - 1/x
sage: O.basis()
(1, x^3*alpha, x^6*alpha^2, x^9*alpha^3, x^12*alpha^4)
"""
d = self._make_monic(self.polynomial())[1]
return self.order(d*self.gen(), check=False)
class RationalFunctionField(FunctionField):
"""
A rational function field K(t) in one variable, over an arbitrary
base field.
EXAMPLES::
sage: K.<t> = FunctionField(GF(3)); K
Rational function field in t over Finite Field of size 3
sage: K.gen()
t
sage: 1/t + t^3 + 5
(t^4 + 2*t + 1)/t
There are various ways to get at the underlying fields and rings
associated to a rational function field::
sage: K.<t> = FunctionField(GF(7))
sage: K.base_field()
Rational function field in t over Finite Field of size 7
sage: K.field()
Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7
sage: K.constant_field()
Finite Field of size 7
sage: K.maximal_order()
Maximal order in Rational function field in t over Finite Field of size 7
We define a morphism::
sage: K.<W> = FunctionField(QQ)
sage: L = FunctionField(QQ, 'tbar') # give var name as second input
sage: K.hom(L.gen())
Morphism of function fields defined by W |--> tbar
"""
def __init__(self, constant_field, names, category=CAT):
"""
Create a rational function field in one variable.
INPUT:
- ``constant_field`` -- an arbitrary field
- ``names`` -- a string or tuple of length 1
- ``category`` -- default: FunctionFields()
EXAMPLES::
sage: K.<t> = FunctionField(CC); K
Rational function field in t over Complex Field with 53 bits of precision
sage: K.category()
Category of function fields
sage: FunctionField(QQ[I], 'alpha')
Rational function field in alpha over Number Field in I with defining polynomial x^2 + 1
Must be over a field::
sage: FunctionField(ZZ, 't')
Traceback (most recent call last):
...
TypeError: constant_field must be a field
"""
if names is None:
raise ValueError, "variable name must be specified"
elif not isinstance(names, tuple):
names = (names, )
if not constant_field.is_field():
raise TypeError, "constant_field must be a field"
ParentWithGens.__init__(self, self, names=names, category = category)
R = constant_field[names[0]]
self._hash = hash((constant_field, names))
self._constant_field = constant_field
self._ring = R
self._field = R.fraction_field()
self._populate_coercion_lists_(coerce_list=[self._field])
self._gen = self(R.gen())
def __hash__(self):
"""
Return hash of this function field.
EXAMPLES::
sage: K.<t> = FunctionField(QQ)
sage: hash(K)
502145503910697533 # 64-bit
? # 32-bit
"""
return self._hash
def _repr_(self):
"""
Return string representation of this function field.
EXAMPLES::
sage: K.<t> = FunctionField(QQ)
sage: K._repr_()
'Rational function field in t over Rational Field'
"""
return "Rational function field in %s over %s"%(
self.variable_name(), self._constant_field)
def _element_constructor_(self, x):
r"""
Coerce x into an element of this function field, possibly not canonically.
INPUT:
- ``x`` - the element
OUTPUT:
``x``, as an element of this function field
EXAMPLES::
sage: K.<t> = FunctionField(QQ)
sage: a = K._element_constructor_(K.maximal_order().gen()); a
t
sage: a.parent()
Rational function field in t over Rational Field
"""
if x.parent() is self._field:
return function_field_element.FunctionFieldElement_rational(self, x)
if isinstance(x, function_field_element.FunctionFieldElement):
return function_field_element.FunctionFieldElement_rational(self, self._field(x.element()))
if x.parent() is self.polynomial_ring():
return x[0]
return function_field_element.FunctionFieldElement_rational(self, self._field(x))
def _to_bivariate_polynomial(self, f):
"""
Convert f from a univariate polynomial over the rational function
field into a bivariate polynomial and a denominator.
INPUT:
- f -- a univariate polynomial over self.
OUTPUT:
- 2-variate polynomial, denominator
EXAMPLES::
sage: R.<t> = FunctionField(GF(7))
sage: S.<X> = R[]
sage: f = (1/t)*(X^4 - 1/t^2)*(X^3 - t^3)
sage: R._to_bivariate_polynomial(f)
(x^7*t^2 - x^4*t^5 - x^3 + t^3, t^3)
"""
v = f.list()
from sage.rings.arith import LCM
denom = LCM([a.denominator() for a in v])
S = denom.parent()
x,t = S.base_ring()['x,t'].gens()
phi = S.hom([t])
return sum([phi((denom * v[i]).numerator()) * x**i for i in range(len(v))]), denom
def _factor_univariate_polynomial(self, f, proof=True):
"""
Factor the univariate polynomial f over self.
EXAMPLES::
We do a factorization over the function field over the rationals::
sage: R.<t> = FunctionField(QQ)
sage: S.<X> = R[]
sage: f = (1/t)*(X^4 - 1/t^2)*(X^3 - t^3)
sage: f.factor() # indirect doctest
(1/t) * (X - t) * (X^2 - 1/t) * (X^2 + 1/t) * (X^2 + t*X + t^2)
sage: f.factor().prod() == f
True
You must pass in proof=False over finite fields, due to
Singular's factoring algorithm being incomplete::
sage: R.<t> = FunctionField(GF(7))
sage: S.<X> = R[]
sage: f = (1/t)*(X^4 - 1/t^2)*(X^3 - t^3)
sage: f.factor()
Traceback (most recent call last):
...
NotImplementedError: proof = True factorization not implemented. Call factor with proof=False.
sage: f.factor(proof=False)
(1/t) * (X + 3*t) * (X + 5*t) * (X + 6*t) * (X^2 + 1/t) * (X^2 + 6/t)
sage: f.factor(proof=False).prod() == f
True
Factoring over a function field over a non-prime finite field::
sage: k.<a> = GF(9)
sage: R.<t> = FunctionField(k)
sage: S.<X> = R[]
sage: f = (1/t)*(X^3 - a*t^3)
sage: f.factor(proof=False)
(1/t) * (X + (a + 2)*t)^3
sage: f.factor(proof=False).prod() == f
True
"""
F, d = self._to_bivariate_polynomial(f)
fac = F.factor(proof=proof)
x = f.parent().gen()
t = f.parent().base_ring().gen()
phi = F.parent().hom([x, t])
v = [(phi(P),e) for P, e in fac]
unit = phi(fac.unit())/d
w = []
for a, e in v:
c = a.leading_coefficient()
a = a/c
unit *= (c**e)
w.append((a,e))
from sage.structure.factorization import Factorization
return Factorization(w, unit=unit)
def polynomial_ring(self, var='x'):
"""
Return polynomial ring K[var] that could be used to represent
elements of self, if self were viewed as K[var]/(var).
EXAMPLES::
sage: K.<x> = FunctionField(QQ)
sage: K.polynomial_ring()
Univariate Polynomial Ring in x over Rational function field in x over Rational Field
sage: K.polynomial_ring('T')
Univariate Polynomial Ring in T over Rational function field in x over Rational Field
"""
if var != 'x': return self[var]
try: return self._polynomial_ring
except AttributeError:
self._polynomial_ring = self[var]
return self._polynomial_ring
def vector_space(self):
"""
Return a vector space V and isomorphisms self --> V and V --> self.
OUTPUT:
- ``V`` - a vector space over the rational numbers
- ``from_V`` - an isomorphism from V to self
- ``to_V`` - an isomorphism from self to V
EXAMPLES::
sage: K.<x> = FunctionField(QQ)
sage: K.vector_space()
(Vector space of dimension 1 over Rational function field in x over Rational Field, Isomorphism map:
From: Vector space of dimension 1 over Rational function field in x over Rational Field
To: Rational function field in x over Rational Field, Isomorphism map:
From: Rational function field in x over Rational Field
To: Vector space of dimension 1 over Rational function field in x over Rational Field)
"""
try: return self._vector_space
except AttributeError:
V = self.base_field()**1
from_V = maps.MapVectorSpaceToFunctionField(V, self)
to_V = maps.MapFunctionFieldToVectorSpace(self, V)
self._vector_space = (V, from_V, to_V)
return self._vector_space
def random_element(self, *args, **kwds):
"""
Create a random element of this rational function field.
Parameters are passed onto the random_element method of the
underlying fraction field.
EXAMPLES::
sage: FunctionField(QQ,'alpha').random_element()
(-1/2*alpha^2 - 4)/(-12*alpha^2 + 1/2*alpha - 1/95)
"""
return self(self._field.random_element(*args, **kwds))
def degree(self):
"""
Return the degree over the base field of this rational
function field, which is 1.
EXAMPLES::
sage: K.<t> = FunctionField(QQ)
sage: K.degree()
1
"""
return ZZ(1)
def gen(self, n=0):
"""
Return the n-th generator of this function field. If n is not
0, then an IndexError is raised.
EXAMPLES::
sage: K.<t> = FunctionField(QQ); K.gen()
t
sage: K.gen().parent()
Rational function field in t over Rational Field
sage: K.gen(1)
Traceback (most recent call last):
...
IndexError: Only one generator.
"""
if n != 0:
raise IndexError, "Only one generator."
return self._gen
def ngens(self):
"""
Return the number of generators, which is 1.
EXAMPLES::
sage: K.<t> = FunctionField(QQ)
sage: K.ngens()
1
"""
return 1
def base_field(self):
"""
Return the base field of this rational function field, which is just
this function field itself.
EXAMPLES::
sage: K.<t> = FunctionField(GF(7))
sage: K.base_field()
Rational function field in t over Finite Field of size 7
"""
return self
def hom(self, im_gens, base_morphism=None):
"""
Create a homomorphism from self to another function field.
INPUT:
- ``im_gens`` -- exactly one element of some function field
- ``base_morphism`` -- ignored
OUTPUT:
- a map between function fields
EXAMPLES::
We make a map from a rational function field to itself::
sage: R.<x> = FunctionField(GF(7))
sage: R.hom( (x^4 + 2)/x)
Morphism of function fields defined by x |--> (x^4 + 2)/x
We construct a map from a rational function field into a
non-rational extension field::
sage: R.<x> = FunctionField(GF(7)); S.<y> = R[]
sage: L.<y> = R.extension(y^3 + 6*x^3 + x)
sage: f = R.hom(y^2 + y + 2); f
Morphism of function fields defined by x |--> y^2 + y + 2
sage: f(x)
y^2 + y + 2
sage: f(x^2)
5*y^2 + (x^3 + 6*x + 4)*y + 2*x^3 + 5*x + 4
"""
if isinstance(im_gens, CategoryObject):
return self.Hom(im_gens).natural_map()
if not isinstance(im_gens, (list,tuple)):
im_gens = [im_gens]
if len(im_gens) != 1:
raise ValueError, "there must be exactly one generator"
x = im_gens[0]
return maps.FunctionFieldMorphism_rational(self.Hom(x.parent()), x)
def field(self):
"""
Return the underlying field, forgetting the function field
structure.
EXAMPLES::
sage: K.<t> = FunctionField(GF(7))
sage: K.field()
Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7
"""
return self._field
def maximal_order(self):
"""
Return the maximal order of this function field. Since this
is a rational function field it is of the form K(t), and the
maximal order is by definition K[t].
EXAMPLES::
sage: K.<t> = FunctionField(QQ)
sage: K.maximal_order()
Maximal order in Rational function field in t over Rational Field
sage: K.equation_order()
Maximal order in Rational function field in t over Rational Field
"""
try: return self._maximal_order
except AttributeError:
from function_field_order import FunctionFieldOrder_rational
self._maximal_order = FunctionFieldOrder_rational(self)
return self._maximal_order
equation_order = maximal_order
def constant_base_field(self):
"""
Return the field that this rational function field is a
transcendental extension of.
EXAMPLES::
sage: K.<t> = FunctionField(QQ)
sage: K.constant_field()
Rational Field
"""
return self._constant_field
constant_field = constant_base_field