Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve genus method of function fields and curves #37538

Merged
merged 2 commits into from
Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/sage/rings/function_field/function_field_polymod.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from sage.rings.integer import Integer
from sage.categories.homset import Hom
from sage.categories.function_fields import FunctionFields
from sage.categories.number_fields import NumberFields

from .element import FunctionFieldElement
from .element_polymod import FunctionFieldElement_polymod
Expand Down Expand Up @@ -1842,11 +1843,27 @@ def genus(self):
sage: L.genus()
6

sage: # needs sage.rings.number_field
sage: R.<T> = QQ[]
sage: N.<a> = NumberField(T^2 + 1)
sage: K.<x> = FunctionField(N); K
Rational function field in x over Number Field in a with defining polynomial T^2 + 1
sage: K.genus()
0
sage: S.<t> = PolynomialRing(K)
sage: L.<y> = K.extension(t^2 - x^3 + x)
sage: L.genus()
1

The genus is computed by the Hurwitz genus formula.
"""
k, _ = self.exact_constant_field()
if k in NumberFields():
k_degree = k.relative_degree()
else:
k_degree = k.degree()
different_degree = self.different().degree() # must be even
return Integer(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
41 changes: 28 additions & 13 deletions src/sage/rings/polynomial/multi_polynomial_ideal.py
Original file line number Diff line number Diff line change
Expand Up @@ -1569,13 +1569,20 @@ def _groebner_basis_singular_raw(self, algorithm="groebner", singular=singular_d
@handle_AA_and_QQbar
def genus(self):
r"""
Return the genus of the projective curve defined by this ideal,
which must be 1 dimensional.
Return the geometric genus of the projective curve defined by this
ideal.

OUTPUT:

If the ideal is homogeneous and defines a curve in a projective space,
then the genus of the curve is returned. If the ideal is not
homogeneous and defines a curve in an affine space, the genus of the
projective closure of the curve is returned.

EXAMPLES:

Consider the hyperelliptic curve `y^2 = 4x^5 - 30x^3 + 45x -
22` over `\QQ`, it has genus 2::
Consider the hyperelliptic curve `y^2 = 4x^5 - 30x^3 + 45x - 22` over
`\QQ`, it has genus 2::

sage: P.<x> = QQ[]
sage: f = 4*x^5 - 30*x^3 + 45*x - 22
Expand All @@ -1592,28 +1599,36 @@ def genus(self):
sage: I.genus()
2

TESTS:

Check that the answer is correct for reducible curves::
Geometric genus is only defined for geometrically irreducible curves.
You may get a nonsensical answer if the condition is not met. A curve
reducible over a quadratic extension of `\QQ`::

sage: R.<x, y, z> = QQ[]
sage: C = Curve(x^2 - 2*y^2)
sage: C.is_singular()
True
sage: C.genus()
-1
sage: Ideal(x^4+y^2*x+x).genus()

TESTS:

An ideal that does not define a curve but we get a result! ::

sage: R.<x, y, z> = QQ[]
sage: Ideal(x^4 + y^2*x + x).genus()
0

An ideal that defines a geometrically reducible affine curve::

sage: T.<t1,t2,u1,u2> = QQ[]
sage: TJ = Ideal([t1^2 + u1^2 - 1,t2^2 + u2^2 - 1, (t1-t2)^2 + (u1-u2)^2 -1])
sage: TJ.genus()
-1

Check that this method works over QQbar (:trac:`25351`)::

sage: P.<x,y> = QQbar[] # needs sage.rings.number_field
sage: I = ideal(y^3*z + x^3*y + x*z^3) # needs sage.rings.number_field
sage: I.genus() # needs sage.rings.number_field
sage: # needs sage.rings.number_field
sage: P.<x,y> = QQbar[]
sage: I = ideal(y^3*z + x^3*y + x*z^3)
sage: I.genus()
3
"""
from sage.libs.singular.function_factory import ff
Expand Down
16 changes: 12 additions & 4 deletions src/sage/schemes/curves/affine_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -2065,13 +2065,21 @@ def _genus(self):
sage: C = Curve(x^5 + y^5 + x*y + 1)
sage: C.genus() # indirect doctest
1
"""
k = self.base_ring()

TESTS::

sage: # needs sage.rings.number_field
sage: R.<T> = QQ[]
sage: N.<a> = NumberField(T^2 + 1)
sage: A2.<x,y> = AffineSpace(N, 2)
sage: C = Curve(y^2 - x^3 + x, A2)
sage: C.genus()
1
"""
# Singular's genus command is usually much faster than the genus method
# of function fields in Sage. But unfortunately Singular's genus
# command does not yet work over non-prime finite fields.
if k.is_finite() and k.degree() > 1:
# command does not work over extension fields.
if self.base_ring().degree() > 1:
return self._function_field.genus()

# call Singular's genus command
Expand Down
61 changes: 42 additions & 19 deletions src/sage/schemes/curves/constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,20 @@
# ********************************************************************

from sage.categories.fields import Fields
from sage.categories.number_fields import NumberFields

from sage.rings.polynomial.multi_polynomial import MPolynomial
from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing
from sage.rings.finite_rings.finite_field_base import FiniteField

from sage.rings.rational_field import QQ

from sage.structure.all import Sequence

from sage.schemes.affine.affine_space import is_AffineSpace
from sage.schemes.generic.ambient_space import is_AmbientSpace
from sage.schemes.generic.algebraic_scheme import is_AlgebraicScheme
from sage.schemes.projective.projective_space import is_ProjectiveSpace

from sage.schemes.affine.affine_space import AffineSpace

from sage.schemes.projective.projective_space import ProjectiveSpace

from sage.schemes.affine.affine_space import AffineSpace, is_AffineSpace
from sage.schemes.projective.projective_space import ProjectiveSpace, is_ProjectiveSpace
from sage.schemes.plane_conics.constructor import Conic

from .projective_curve import (ProjectiveCurve,
ProjectivePlaneCurve,
Expand All @@ -77,9 +73,6 @@
IntegralAffinePlaneCurve_finite_field)


from sage.schemes.plane_conics.constructor import Conic


def _is_irreducible_and_reduced(F) -> bool:
"""
Check if the polynomial F is irreducible and reduced.
Expand Down Expand Up @@ -113,11 +106,13 @@

INPUT:

- ``F`` -- a multivariate polynomial, or a list or tuple of polynomials, or an algebraic scheme.
- ``F`` -- a multivariate polynomial, or a list or tuple of polynomials, or an algebraic scheme

- ``A`` -- (default: None) an ambient space in which to create the curve

- ``A`` -- (default: None) an ambient space in which to create the curve.
EXAMPLES:

EXAMPLES: A projective plane curve. ::
A projective plane curve::

sage: x,y,z = QQ['x,y,z'].gens()
sage: C = Curve(x^3 + y^3 + z^3); C
Expand Down Expand Up @@ -215,7 +210,7 @@
sage: Curve(P1)
Projective Line over Finite Field of size 5

::
An affine line::

sage: A1.<x> = AffineSpace(1, QQ)
sage: R = A1.coordinate_ring()
Expand All @@ -224,6 +219,18 @@
sage: Curve(A1)
Affine Line over Rational Field

A projective line::

sage: R.<x> = QQ[]
sage: N.<a> = NumberField(x^2 + 1)
sage: P1.<x,y> = ProjectiveSpace(N, 1)
sage: C = Curve(P1)
sage: C
Projective Line over Number Field in a with defining polynomial x^2 + 1
sage: C.geometric_genus()
0
sage: C.arithmetic_genus()
0
"""
if A is None:
if is_AmbientSpace(F) and F.dimension() == 1:
Expand Down Expand Up @@ -298,12 +305,20 @@
k = A.base_ring()

if is_AffineSpace(A):
if n == 1:
if A.coordinate_ring().ideal(F).is_zero():
if isinstance(k, FiniteField):
return IntegralAffineCurve_finite_field(A, F)
if k in Fields():
return IntegralAffineCurve(A, F)
return AffineCurve(A, F)
raise TypeError(f"{F} does not define a curve in one-dimensional affine space")

Check warning on line 315 in src/sage/schemes/curves/constructor.py

View check run for this annotation

Codecov / codecov/patch

src/sage/schemes/curves/constructor.py#L314-L315

Added lines #L314 - L315 were not covered by tests
if n != 2:
if isinstance(k, FiniteField):
if A.coordinate_ring().ideal(F).is_prime():
return IntegralAffineCurve_finite_field(A, F)
if k in Fields():
if k == QQ and A.coordinate_ring().ideal(F).is_prime():
if (k == QQ or k in NumberFields()) and A.coordinate_ring().ideal(F).is_prime():
return IntegralAffineCurve(A, F)
return AffineCurve_field(A, F)
return AffineCurve(A, F)
Expand All @@ -317,20 +332,28 @@
return IntegralAffinePlaneCurve_finite_field(A, F)
return AffinePlaneCurve_finite_field(A, F)
if k in Fields():
if k == QQ and _is_irreducible_and_reduced(F):
if (k == QQ or k in NumberFields()) and _is_irreducible_and_reduced(F):
return IntegralAffinePlaneCurve(A, F)
return AffinePlaneCurve_field(A, F)
return AffinePlaneCurve(A, F)

elif is_ProjectiveSpace(A):
if n == 1:
if A.coordinate_ring().ideal(F).is_zero():
if isinstance(k, FiniteField):
return IntegralProjectiveCurve_finite_field(A, F)
if k in Fields():
return IntegralProjectiveCurve(A, F)
return ProjectiveCurve(A, F)
raise TypeError(f"{F} does not define a curve in one-dimensional projective space")

Check warning on line 348 in src/sage/schemes/curves/constructor.py

View check run for this annotation

Codecov / codecov/patch

src/sage/schemes/curves/constructor.py#L347-L348

Added lines #L347 - L348 were not covered by tests
if n != 2:
if not all(f.is_homogeneous() for f in F):
raise TypeError("polynomials defining a curve in a projective space must be homogeneous")
if isinstance(k, FiniteField):
if A.coordinate_ring().ideal(F).is_prime():
return IntegralProjectiveCurve_finite_field(A, F)
if k in Fields():
if k == QQ and A.coordinate_ring().ideal(F).is_prime():
if (k == QQ or k in NumberFields()) and A.coordinate_ring().ideal(F).is_prime():
return IntegralProjectiveCurve(A, F)
return ProjectiveCurve_field(A, F)
return ProjectiveCurve(A, F)
Expand All @@ -349,7 +372,7 @@
return IntegralProjectivePlaneCurve_finite_field(A, F)
return ProjectivePlaneCurve_finite_field(A, F)
if k in Fields():
if k == QQ and _is_irreducible_and_reduced(F):
if (k == QQ or k in NumberFields()) and _is_irreducible_and_reduced(F):
return IntegralProjectivePlaneCurve(A, F)
return ProjectivePlaneCurve_field(A, F)
return ProjectivePlaneCurve(A, F)
Expand Down
26 changes: 14 additions & 12 deletions src/sage/schemes/curves/curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,17 +209,9 @@
r"""
Return the geometric genus of the curve.

This is by definition the genus of the normalization of the projective
closure of the curve over the algebraic closure of the base field; the
base field must be a prime field.

.. NOTE::

This calls Singular's genus command.

EXAMPLES:

Examples of projective curves. ::
Examples of projective curves::

sage: P2 = ProjectiveSpace(2, GF(5), names=['x','y','z'])
sage: x, y, z = P2.coordinate_ring().gens()
Expand All @@ -233,7 +225,7 @@
sage: C.geometric_genus()
3

Examples of affine curves. ::
Examples of affine curves::

sage: x, y = PolynomialRing(GF(5), 2, 'xy').gens()
sage: C = Curve(y^2 - x^3 - 17*x + y)
Expand All @@ -246,12 +238,22 @@
sage: C.geometric_genus()
3

.. WARNING::

Geometric genus is only defined for `geometrically irreducible curve
<https://stacks.math.columbia.edu/tag/0BYE>`_. This method does not
check the condition. You may get a nonsensical result if the curve is
not geometrically irreducible::

sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2)
sage: C = Curve(x^2 + y^2, P2)
sage: C.geometric_genus() # nonsense!
-1
"""
try:
return self._genus
except AttributeError:
self._genus = self.defining_ideal().genus()
return self._genus
raise NotImplementedError

Check warning on line 256 in src/sage/schemes/curves/curve.py

View check run for this annotation

Codecov / codecov/patch

src/sage/schemes/curves/curve.py#L256

Added line #L256 was not covered by tests

def union(self, other):
"""
Expand Down
Loading
Loading