diff --git a/src/sage/rings/function_field/function_field_polymod.py b/src/sage/rings/function_field/function_field_polymod.py index 44c1390bc86..ce7aa40ad29 100644 --- a/src/sage/rings/function_field/function_field_polymod.py +++ b/src/sage/rings/function_field/function_field_polymod.py @@ -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 @@ -1842,11 +1843,27 @@ def genus(self): sage: L.genus() 6 + sage: # needs sage.rings.number_field + sage: R. = QQ[] + sage: N. = NumberField(T^2 + 1) + sage: K. = 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. = PolynomialRing(K) + sage: L. = 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): """ diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 2b828fba51b..f4507b813db 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -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. = QQ[] sage: f = 4*x^5 - 30*x^3 + 45*x - 22 @@ -1592,18 +1599,25 @@ 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. = 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. = QQ[] + sage: Ideal(x^4 + y^2*x + x).genus() 0 + + An ideal that defines a geometrically reducible affine curve:: + sage: T. = QQ[] sage: TJ = Ideal([t1^2 + u1^2 - 1,t2^2 + u2^2 - 1, (t1-t2)^2 + (u1-u2)^2 -1]) sage: TJ.genus() @@ -1611,9 +1625,10 @@ def genus(self): Check that this method works over QQbar (:trac:`25351`):: - sage: P. = 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. = 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 diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py index d5ea150f98d..992cd528803 100644 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -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. = QQ[] + sage: N. = NumberField(T^2 + 1) + sage: A2. = 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 diff --git a/src/sage/schemes/curves/constructor.py b/src/sage/schemes/curves/constructor.py index 6fe15a2efc2..3564cfd73cc 100644 --- a/src/sage/schemes/curves/constructor.py +++ b/src/sage/schemes/curves/constructor.py @@ -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, @@ -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. @@ -113,11 +106,13 @@ def Curve(F, A=None): 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 @@ -215,7 +210,7 @@ def Curve(F, A=None): sage: Curve(P1) Projective Line over Finite Field of size 5 - :: + An affine line:: sage: A1. = AffineSpace(1, QQ) sage: R = A1.coordinate_ring() @@ -224,6 +219,18 @@ def Curve(F, A=None): sage: Curve(A1) Affine Line over Rational Field + A projective line:: + + sage: R. = QQ[] + sage: N. = NumberField(x^2 + 1) + sage: P1. = 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: @@ -298,12 +305,20 @@ def Curve(F, A=None): 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") 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) @@ -317,12 +332,20 @@ def Curve(F, A=None): 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") 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") @@ -330,7 +353,7 @@ def Curve(F, A=None): 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) @@ -349,7 +372,7 @@ def Curve(F, A=None): 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) diff --git a/src/sage/schemes/curves/curve.py b/src/sage/schemes/curves/curve.py index 0538db66fee..cacc05f884b 100644 --- a/src/sage/schemes/curves/curve.py +++ b/src/sage/schemes/curves/curve.py @@ -209,17 +209,9 @@ def geometric_genus(self): 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() @@ -233,7 +225,7 @@ def geometric_genus(self): 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) @@ -246,12 +238,22 @@ def geometric_genus(self): sage: C.geometric_genus() 3 + .. WARNING:: + + Geometric genus is only defined for `geometrically irreducible curve + `_. This method does not + check the condition. You may get a nonsensical result if the curve is + not geometrically irreducible:: + + sage: P2. = 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 def union(self, other): """ diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 0b3f311eb62..399b1095ea5 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -1595,13 +1595,30 @@ def __init__(self, A, X, category=None): if not A.base_ring() in Fields(): raise TypeError("curve not defined over a field") + @lazy_attribute + def _genus(self): + """ + The geometric genus of this projective curve. + + TESTS: + + Geometric genus is not defined for geometrically reducible curves. You + may get a nonsensical answer if the condition is not met:: + + sage: P2. = ProjectiveSpace(QQ, 2) + sage: C = Curve(x^2 + y^2) + sage: C.genus() # indirect test + -1 + """ + return self.defining_ideal().genus() + def arithmetic_genus(self): r""" Return the arithmetic genus of this projective curve. - This is the arithmetic genus `g_a(C)` as defined in [Har1977]_. If `P` is the - Hilbert polynomial of the defining ideal of this curve, then the arithmetic genus - of this curve is `1 - P(0)`. This curve must be irreducible. + This is the arithmetic genus `p_a(C)` as defined in [Har1977]_. If `P` + is the Hilbert polynomial of the defining ideal of this curve, then the + arithmetic genus of this curve is `1 - P(0)`. EXAMPLES:: @@ -1617,8 +1634,6 @@ def arithmetic_genus(self): sage: C.arithmetic_genus() 10 """ - if not self.is_irreducible(): - raise TypeError("this curve must be irreducible") return 1 - self.defining_ideal().hilbert_polynomial()(0) def is_complete_intersection(self): @@ -1687,10 +1702,11 @@ def arithmetic_genus(self): r""" Return the arithmetic genus of this projective curve. - This is the arithmetic genus `g_a(C)` as defined in [Har1977]_. For a - projective plane curve of degree `d`, this is simply `(d-1)(d-2)/2`. It - need *not* equal the geometric genus (the genus of the normalization of - the curve). This curve must be irreducible. + This is the arithmetic genus `p_a(C)` as defined in [Har1977]_. + + For an irreducible projective plane curve of degree `d`, this is simply + `(d - 1)(d - 2)/2`. It need *not* equal the geometric genus (the genus + of the normalization of the curve). EXAMPLES:: @@ -1700,7 +1716,7 @@ def arithmetic_genus(self): defined by -x^9 + y^2*z^7 - x*z^8 sage: C.arithmetic_genus() 28 - sage: C.genus() + sage: C.genus() # geometric 4 :: @@ -1710,10 +1726,11 @@ def arithmetic_genus(self): sage: C.arithmetic_genus() 3 """ - if not self.is_irreducible(): - raise TypeError("this curve must be irreducible") - d = self.defining_polynomial().total_degree() - return Integer(d - 1).binomial(2) + if self.is_irreducible(): + # use genus-degree formula + d = self.defining_polynomial().total_degree() + return Integer(d - 1).binomial(2) + return super().arithmetic_genus() def fundamental_group(self): r""" @@ -2290,9 +2307,9 @@ def _genus(self): EXAMPLES:: - sage: P. = ProjectiveSpace(GF(4), 2) # needs sage.rings.finite_rings - sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5) # needs sage.rings.finite_rings - sage: C.genus() # indirect doctest # needs sage.rings.finite_rings + sage: P. = ProjectiveSpace(GF(4), 2) + sage: C = Curve(x^5 + y^5 + x*y*z^3 + z^5) + sage: C.genus() # indirect doctest 1 """ return self._open_affine.genus()