Skip to content

Commit

Permalink
Trac #33075: Constant field extension of function fields
Browse files Browse the repository at this point in the history
We add constant field extensions of function fields, which can compute
conorms of places and divisors.

Along the way, we

(1) add `is_effective`, `numerator`, `denominator` methods to divisors;

(2) fix some methods to return Integer values rather than `int`;

(3) fix minor inconveniences.

URL: https://trac.sagemath.org/33075
Reported by: klee
Ticket author(s): Kwankyu Lee
Reviewer(s): Travis Scrimshaw
  • Loading branch information
Release Manager committed Mar 8, 2022
2 parents 950ecf8 + 09e3b70 commit 82fba97
Show file tree
Hide file tree
Showing 5 changed files with 364 additions and 38 deletions.
1 change: 1 addition & 0 deletions src/doc/en/reference/function_fields/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ algebraic closure of `\QQ`.
sage/rings/function_field/differential
sage/rings/function_field/valuation_ring
sage/rings/function_field/maps
sage/rings/function_field/extensions
sage/rings/function_field/constructor

A basic reference for the theory of algebraic function fields is [Stich2009]_.
Expand Down
73 changes: 71 additions & 2 deletions src/sage/rings/function_field/divisor.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,11 +457,80 @@ def multiplicity(self, place):
-3
"""
if place not in self._data:
return 0
return Integer(0)
return self._data[place]

valuation = multiplicity

def is_effective(self):
"""
Return ``True`` if this divisor has non-negative multiplicity at all
places.
EXAMPLES::
sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[]
sage: L.<y> = K.extension(Y^3 + x^3*Y + x)
sage: p1, p2 = L.places()[:2]
sage: D = 2*p1 + 3*p2
sage: D.is_effective()
True
sage: E = D - 4*p2
sage: E.is_effective()
False
"""
data = self._data
return all(data[place] >= 0 for place in data)

def numerator(self):
"""
Return the numerator part of the divisor.
The numerator of a divisor is the positive part of the divisor.
EXAMPLES::
sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[]
sage: L.<y> = K.extension(Y^3 + x^3*Y + x)
sage: p1,p2 = L.places()[:2]
sage: D = 2*p1 - 3*p2
sage: D.numerator()
2*Place (1/x, 1/x^3*y^2 + 1/x)
"""
divisor_group = self.parent()
data = self._data
d = {}
for place in data:
m = data[place]
if m > 0:
d[place] = m
return divisor_group.element_class(self.parent(), d)

def denominator(self):
"""
Return the denominator part of the divisor.
The denominator of a divisor is the negative of the negative part of
the divisor.
EXAMPLES::
sage: K.<x> = FunctionField(GF(4)); _.<Y> = K[]
sage: L.<y> = K.extension(Y^3 + x^3*Y + x)
sage: p1,p2 = L.places()[:2]
sage: D = 2*p1 - 3*p2
sage: D.denominator()
3*Place (1/x, 1/x^3*y^2 + 1/x^2*y + 1)
"""
divisor_group = self.parent()
data = self._data
d = {}
for place in data:
m = data[place]
if m < 0:
d[place] = -m
return divisor_group.element_class(self.parent(), d)

def degree(self):
"""
Return the degree of the divisor.
Expand Down Expand Up @@ -966,7 +1035,7 @@ def _element_constructor_(self, x):
"""
if x == 0:
return self.element_class(self, {})
raise ValueError
raise ValueError(f"cannot construct a divisor from {x}")

def _coerce_map_from_(self, S):
"""
Expand Down
217 changes: 217 additions & 0 deletions src/sage/rings/function_field/extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
r"""
Special extensions of function fields
This module currently implements only constant field extension.
Constant field extensions
-------------------------
EXAMPLES:
Constant field extension of the rational function field over rational numbers::
sage: K.<x> = FunctionField(QQ)
sage: N.<a> = QuadraticField(2)
sage: L = K.extension_constant_field(N)
sage: L
Rational function field in x over Number Field in a with defining
polynomial x^2 - 2 with a = 1.4142... over its base
sage: d = (x^2 - 2).divisor()
sage: d
-2*Place (1/x)
+ Place (x^2 - 2)
sage: L.conorm_divisor(d)
-2*Place (1/x)
+ Place (x - a)
+ Place (x + a)
Constant field extension of a function field over a finite field::
sage: K.<x> = FunctionField(GF(2)); R.<Y> = K[]
sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2)
sage: E = F.extension_constant_field(GF(2^3))
sage: E
Function field in y defined by y^3 + x^6 + x^4 + x^2 over its base
sage: p = F.get_place(3)
sage: E.conorm_place(p) # random
Place (x + z3, y + z3^2 + z3)
+ Place (x + z3^2, y + z3)
+ Place (x + z3^2 + z3, y + z3^2)
sage: q = F.get_place(2)
sage: E.conorm_place(q) # random
Place (x + 1, y^2 + y + 1)
sage: E.conorm_divisor(p + q) # random
Place (x + 1, y^2 + y + 1)
+ Place (x + z3, y + z3^2 + z3)
+ Place (x + z3^2, y + z3)
+ Place (x + z3^2 + z3, y + z3^2)
AUTHORS:
- Kwankyu Lee (2021-12-24): added constant field extension
"""

from sage.rings.ring_extension import RingExtension_generic

from .constructor import FunctionField


class FunctionFieldExtension(RingExtension_generic):
"""
Abstract base class of function field extensions.
"""
pass


class ConstantFieldExtension(FunctionFieldExtension):
"""
Constant field extension.
INPUT:
- ``F`` -- a function field whose constant field is `k`
- ``k_ext`` -- an extension of `k`
"""
def __init__(self, F, k_ext):
"""
Initialize.
TESTS::
sage: K.<x> = FunctionField(GF(2)); R.<Y> = K[]
sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2)
sage: E = F.extension_constant_field(GF(2^3))
sage: TestSuite(E).run(skip=['_test_elements', '_test_pickling'])
"""
k = F.constant_base_field()
F_base = F.base_field()

F_ext_base = FunctionField(k_ext, F_base.variable_name())

if F.degree() > 1:
# construct constant field extension F_ext of F
def_poly = F.polynomial().base_extend(F_ext_base)
F_ext = F_ext_base.extension(def_poly, names=def_poly.variable_name())
else: # rational function field
F_ext = F_ext_base

# embedding of F into F_ext
embedk = k_ext.coerce_map_from(k)
embedF_base = F_base.hom(F_ext_base.gen(), embedk)

if F.degree() > 1:
embedF = F.hom(F_ext.gen(), embedF_base)
else:
embedF = embedF_base

self._embedk = embedk
self._embedF = embedF
self._F_ext = F_ext
self._k = k

super().__init__(embedF, is_backend_exposed=True)

def top(self):
"""
Return the top function field of this extension.
EXAMPLES::
sage: K.<x> = FunctionField(GF(2)); R.<Y> = K[]
sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2)
sage: E = F.extension_constant_field(GF(2^3))
sage: E.top()
Function field in y defined by y^3 + x^6 + x^4 + x^2
"""
return self._F_ext

def defining_morphism(self):
"""
Return the defining morphism of this extension.
This is the morphism from the base to the top.
EXAMPLES::
sage: K.<x> = FunctionField(GF(2)); R.<Y> = K[]
sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2)
sage: E = F.extension_constant_field(GF(2^3))
sage: E.defining_morphism()
Function Field morphism:
From: Function field in y defined by y^3 + x^6 + x^4 + x^2
To: Function field in y defined by y^3 + x^6 + x^4 + x^2
Defn: y |--> y
x |--> x
1 |--> 1
"""
return self._embedF

def conorm_place(self, p):
"""
Return the conorm of the place `p` in this extension.
INPUT:
- ``p`` -- place of the base function field
OUTPUT: divisor of the top function field
EXAMPLES::
sage: K.<x> = FunctionField(GF(2)); R.<Y> = K[]
sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2)
sage: E = F.extension_constant_field(GF(2^3))
sage: p = F.get_place(3)
sage: d = E.conorm_place(p)
sage: [pl.degree() for pl in d.support()]
[1, 1, 1]
sage: p = F.get_place(2)
sage: d = E.conorm_place(p)
sage: [pl.degree() for pl in d.support()]
[2]
"""
embedF = self.defining_morphism()

O_ext = self.maximal_order()
Oinf_ext = self.maximal_order_infinite()

if p.is_infinite_place():
ideal = Oinf_ext.ideal([embedF(g) for g in p.prime_ideal().gens()])
else:
ideal = O_ext.ideal([embedF(g) for g in p.prime_ideal().gens()])

return ideal.divisor()

def conorm_divisor(self, d):
"""
Return the conorm of the divisor ``d`` in this extension.
INPUT:
- ``d`` -- divisor of the base function field
OUTPUT: a divisor of the top function field
EXAMPLES::
sage: K.<x> = FunctionField(GF(2)); R.<Y> = K[]
sage: F.<y> = K.extension(Y^3 - x^2*(x^2 + x + 1)^2)
sage: E = F.extension_constant_field(GF(2^3))
sage: p1 = F.get_place(3)
sage: p2 = F.get_place(2)
sage: c = E.conorm_divisor(2*p1+ 3*p2)
sage: c1 = E.conorm_place(p1)
sage: c2 = E.conorm_place(p2)
sage: c == 2*c1 + 3*c2
True
"""
div_top = self.divisor_group()

c = div_top.zero()
for pl, mul in d.list():
c += mul * self.conorm_place(pl)
return c

27 changes: 24 additions & 3 deletions src/sage/rings/function_field/function_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@

from sage.arith.all import lcm

from sage.rings.integer import Integer
from sage.rings.ring import Field
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.rings.qqbar_decorators import handle_AA_and_QQbar
Expand Down Expand Up @@ -1130,6 +1131,27 @@ def completion(self, place, name=None, prec=None, gen_name=None):
from .maps import FunctionFieldCompletion
return FunctionFieldCompletion(self, place, name=name, prec=prec, gen_name=gen_name)

def extension_constant_field(self, k):
"""
Return the constant field extension with constant field `k`.
INPUT:
- ``k`` -- an extension field of the constant field of this function field
EXAMPLES::
sage: K.<x> = FunctionField(GF(2)); _.<Y> = K[]
sage: F.<y> = K.extension(Y^2 + Y + x + 1/x)
sage: E = F.extension_constant_field(GF(2^4))
sage: E
Function field in y defined by y^2 + y + (x^2 + 1)/x over its base
sage: E.constant_base_field()
Finite Field in z4 of size 2^4
"""
from .extensions import ConstantFieldExtension
return ConstantFieldExtension(self, k)


class FunctionField_polymod(FunctionField):
"""
Expand Down Expand Up @@ -2910,7 +2932,7 @@ def genus(self):
"""
k, _ = self.exact_constant_field()
different_degree = self.different().degree() # must be even
return different_degree // 2 - self.degree() / k.degree() + 1
return Integer(different_degree // 2 - self.degree() / k.degree()) + 1

def residue_field(self, place, name=None):
"""
Expand Down Expand Up @@ -3178,7 +3200,6 @@ def _places_finite(self, degree):
O = self.maximal_order()
K = self.base_field()

from sage.rings.integer import Integer
degree = Integer(degree)

for d in degree.divisors():
Expand Down Expand Up @@ -4381,7 +4402,7 @@ def genus(self):
sage: K.genus()
0
"""
return 0
return Integer(0)

def change_variable_name(self, name):
r"""
Expand Down
Loading

0 comments on commit 82fba97

Please sign in to comment.