Hyperelliptic curves (smooth model) over a field

EXAMPLES:

sage: P.<x> = GF(5)[]
sage: f = x^5 - 3*x^4 - 2*x^3 + 6*x^2 + 3*x - 1
sage: C = HyperellipticCurve(f); C
Hyperelliptic Curve over Finite Field of size 5
 defined by y^2 = x^5 + 2*x^4 + 3*x^3 + x^2 + 3*x + 4
>>> from sage.all import *
>>> P = GF(Integer(5))['x']; (x,) = P._first_ngens(1)
>>> f = x**Integer(5) - Integer(3)*x**Integer(4) - Integer(2)*x**Integer(3) + Integer(6)*x**Integer(2) + Integer(3)*x - Integer(1)
>>> C = HyperellipticCurve(f); C
Hyperelliptic Curve over Finite Field of size 5
 defined by y^2 = x^5 + 2*x^4 + 3*x^3 + x^2 + 3*x + 4

sage: P.<x> = QQ[]
sage: f = 4*x^5 - 30*x^3 + 45*x - 22
sage: C = HyperellipticCurve(f); C
Hyperelliptic Curve over Rational Field defined by y^2 = 4*x^5 - 30*x^3 + 45*x - 22
sage: C.genus()
2

# TODO: weighted projective space doesnt have affine_patch
# sage: D = C.affine_patch(0)
# sage: D.defining_polynomials()[0].parent()
# Multivariate Polynomial Ring in x1, x2 over Rational Field
[Python]
>>> from sage.all import *
>>> P = QQ['x']; (x,) = P._first_ngens(1)
>>> f = Integer(4)*x**Integer(5) - Integer(30)*x**Integer(3) + Integer(45)*x - Integer(22)
>>> C = HyperellipticCurve(f); C
Hyperelliptic Curve over Rational Field defined by y^2 = 4*x^5 - 30*x^3 + 45*x - 22
>>> C.genus()
2

# TODO: weighted projective space doesnt have affine_patch
# sage: D = C.affine_patch(0)
# sage: D.defining_polynomials()[0].parent()
# Multivariate Polynomial Ring in x1, x2 over Rational Field

AUTHORS:

  • David Kohel (2006): initial version

  • Sabrina Kunzweiler, Gareth Ma, Giacomo Pope (2024): adapt to smooth model

class sage.schemes.hyperelliptic_curves.hyperelliptic_generic.HyperellipticCurve_generic(defining_polynomial, f, h, genus: Integer, names=['x', 'y'])[source]

Bases: WeightedProjectiveCurve

affine_coordinates(P)[source]

Return the affine coordinates of a point P of self. That is for \(P = [X,Y,Z]\), the output is \(X/Z, Y/Z^{(g+1)}\).

EXAMPLES:

sage: R.<x> = QQ[]
sage: H = HyperellipticCurve(x^6 - 1)
sage: P = H.point([2,0,2])
sage: H.affine_coordinates(P)
(1, 0)
sage: Q = H.point([1,1,0])
sage: H.affine_coordinates(Q)
Traceback (most recent call last):
...
ValueError: The point (1 : 1 : 0) is not an affine point of Hyperelliptic Curve over Rational Field defined by y^2 = x^6 - 1
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(6) - Integer(1))
>>> P = H.point([Integer(2),Integer(0),Integer(2)])
>>> H.affine_coordinates(P)
(1, 0)
>>> Q = H.point([Integer(1),Integer(1),Integer(0)])
>>> H.affine_coordinates(Q)
Traceback (most recent call last):
...
ValueError: The point (1 : 1 : 0) is not an affine point of Hyperelliptic Curve over Rational Field defined by y^2 = x^6 - 1
base_extend(R)[source]

alias of change_ring().

base_ring()[source]

Return the base ring of the hyperelliptic curve.

EXAMPLES:

sage: R.<x> = QQ[]
sage: H = HyperellipticCurve(x^7 + 3*x + 2)
sage: H.base_ring()
Rational Field

sage: S.<x> = FiniteField(19)[]
sage: H = HyperellipticCurve(x^5 - x + 2)
sage: H.base_ring()
Finite Field of size 19
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(7) + Integer(3)*x + Integer(2))
>>> H.base_ring()
Rational Field

>>> S = FiniteField(Integer(19))['x']; (x,) = S._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(5) - x + Integer(2))
>>> H.base_ring()
Finite Field of size 19
change_ring(R)[source]

Return this hyperelliptic curve over a new ring R.

EXAMPLES:

sage: R.<x> = QQ[]
sage: H = HyperellipticCurve(x^5 - 10*x + 9)
sage: K = Qp(3, 5)                                                          # optional - sage.rings.padics
sage: L.<a> = K.extension(x^30 - 3)                                         # optional - sage.rings.padics
sage: HK = H.change_ring(K)                                                 # optional - sage.rings.padics
sage: HL = HK.change_ring(L); HL                                            # optional - sage.rings.padics
Hyperelliptic Curve over 3-adic Eisenstein Extension Field in a defined by x^30 - 3 defined by (1 + O(a^150))*y^2 = (1 + O(a^150))*x^5 + (2 + 2*a^30 + a^60 + 2*a^90 + 2*a^120 + O(a^150))*x + a^60 + O(a^210)

sage: R.<x> = FiniteField(7)[]                                              # optional - sage.rings.finite_rings
sage: H = HyperellipticCurve(x^8 + x + 5)                                   # optional - sage.rings.finite_rings
sage: H.base_extend(FiniteField(7^2, 'a'))                                  # optional - sage.rings.finite_rings
Hyperelliptic Curve over Finite Field in a of size 7^2 defined by y^2 = x^8 + x + 5
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(5) - Integer(10)*x + Integer(9))
>>> K = Qp(Integer(3), Integer(5))                                                          # optional - sage.rings.padics
>>> L = K.extension(x**Integer(30) - Integer(3), names=('a',)); (a,) = L._first_ngens(1)# optional - sage.rings.padics
>>> HK = H.change_ring(K)                                                 # optional - sage.rings.padics
>>> HL = HK.change_ring(L); HL                                            # optional - sage.rings.padics
Hyperelliptic Curve over 3-adic Eisenstein Extension Field in a defined by x^30 - 3 defined by (1 + O(a^150))*y^2 = (1 + O(a^150))*x^5 + (2 + 2*a^30 + a^60 + 2*a^90 + 2*a^120 + O(a^150))*x + a^60 + O(a^210)

>>> R = FiniteField(Integer(7))['x']; (x,) = R._first_ngens(1)# optional - sage.rings.finite_rings
>>> H = HyperellipticCurve(x**Integer(8) + x + Integer(5))                                   # optional - sage.rings.finite_rings
>>> H.base_extend(FiniteField(Integer(7)**Integer(2), 'a'))                                  # optional - sage.rings.finite_rings
Hyperelliptic Curve over Finite Field in a of size 7^2 defined by y^2 = x^8 + x + 5

It is also possible to compute the reduction at a prime by changing the base ring to the residue field:

sage: R.<x> = PolynomialRing(QQ);
sage: H = HyperellipticCurve(R([0, -1, 2, 0, -2]), R([0, 1, 0, 1])); #LMFDB label: 763.a.763.1
sage: H.change_ring(FiniteField(2))
Hyperelliptic Curve over Finite Field of size 2 defined by y^2 + (x^3 + x)*y = x
sage: H.change_ring(FiniteField(3))
Hyperelliptic Curve over Finite Field of size 3 defined by y^2 + (x^3 + x)*y = x^4 + 2*x^2 + 2*x
[Python]
>>> from sage.all import *
>>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1);
>>> H = HyperellipticCurve(R([Integer(0), -Integer(1), Integer(2), Integer(0), -Integer(2)]), R([Integer(0), Integer(1), Integer(0), Integer(1)])); #LMFDB label: 763.a.763.1
>>> H.change_ring(FiniteField(Integer(2)))
Hyperelliptic Curve over Finite Field of size 2 defined by y^2 + (x^3 + x)*y = x
>>> H.change_ring(FiniteField(Integer(3)))
Hyperelliptic Curve over Finite Field of size 3 defined by y^2 + (x^3 + x)*y = x^4 + 2*x^2 + 2*x

Note that this only works when the curve has good reduction at \(p\):

sage: H.change_ring(FiniteField(7))
Traceback (most recent call last):
...
ValueError: singularity in the provided affine patch
>>> from sage.all import *
>>> H.change_ring(FiniteField(Integer(7)))
Traceback (most recent call last):
...
ValueError: singularity in the provided affine patch
discriminant()[source]

Return the discriminant of this curve.

The discriminant of the hyperelliptic curve \(y^2 + hy = f\) is \(\Delta = 2^{-4(g + 1)} \Delta(h^2 + 4f)\). See https://www.math.u-bordeaux.fr/~qliu/Notes/disc.pdf for the derivation.

EXAMPLES:

sage: R.<x> = QQ[]
sage: f = 2*x^6 + x^2 - 3*x + 1
sage: h = x^2 + x + 1
sage: H = HyperellipticCurve(f, h)
sage: H.discriminant()
-1622970410
sage: F = 4*f + h^2
sage: Delta = F.discriminant() / 16^3; Delta
-1622970410
sage: G = f.derivative()^2 - f*h.derivative()^2 + f.derivative()*h.derivative()*h
sage: F.resultant(G) == Delta^2*F.lc()^2
True
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> f = Integer(2)*x**Integer(6) + x**Integer(2) - Integer(3)*x + Integer(1)
>>> h = x**Integer(2) + x + Integer(1)
>>> H = HyperellipticCurve(f, h)
>>> H.discriminant()
-1622970410
>>> F = Integer(4)*f + h**Integer(2)
>>> Delta = F.discriminant() / Integer(16)**Integer(3); Delta
-1622970410
>>> G = f.derivative()**Integer(2) - f*h.derivative()**Integer(2) + f.derivative()*h.derivative()*h
>>> F.resultant(G) == Delta**Integer(2)*F.lc()**Integer(2)
True

sage: # H.affine_patch() is not implemented
sage: H_patch = H.projective_curve().affine_patch(2)
sage: for p in prime_range(3, 50):
....:     Hp = H_patch.change_ring(GF(p))
....:     assert Hp.is_smooth() == (H.discriminant() % p != 0)
[Python]
>>> from sage.all import *
>>> # H.affine_patch() is not implemented
>>> H_patch = H.projective_curve().affine_patch(Integer(2))
>>> for p in prime_range(Integer(3), Integer(50)):
...     Hp = H_patch.change_ring(GF(p))
...     assert Hp.is_smooth() == (H.discriminant() % p != Integer(0))
distinguished_point()[source]

Return the distinguished point of the hyperelliptic curve. By default, this is one of the points at infinity if possible.

See also

set_distinguished_point()

EXAMPLE:

sage: R.<x> = GF(11)[]
sage: H1 = HyperellipticCurve(x^2 + x, x^5 - 3*x + 4)
sage: H1.distinguished_point()
(1 : 0 : 0)
sage: H2 = HyperellipticCurve(x^6 + x^5 + 1, 2*x^3)
sage: H2.points_at_infinity()
[]
sage: H2.distinguished_point()
(0 : 1 : 1)
>>> from sage.all import *
>>> R = GF(Integer(11))['x']; (x,) = R._first_ngens(1)
>>> H1 = HyperellipticCurve(x**Integer(2) + x, x**Integer(5) - Integer(3)*x + Integer(4))
>>> H1.distinguished_point()
(1 : 0 : 0)
>>> H2 = HyperellipticCurve(x**Integer(6) + x**Integer(5) + Integer(1), Integer(2)*x**Integer(3))
>>> H2.points_at_infinity()
[]
>>> H2.distinguished_point()
(0 : 1 : 1)
genus()[source]

Return the genus of the hyperelliptic curve.

EXAMPLES:

sage: R.<x> = QQ[]
sage: H = HyperellipticCurve(x^7 + 3*x + 2)
sage: H.genus()
3
sage: H = HyperellipticCurve(x^3 + 2, x^5 + 1)
sage: H.genus()
4
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(7) + Integer(3)*x + Integer(2))
>>> H.genus()
3
>>> H = HyperellipticCurve(x**Integer(3) + Integer(2), x**Integer(5) + Integer(1))
>>> H.genus()
4
has_odd_degree_model()[source]

Return True if an odd degree model of self exists over the field of definition; False otherwise.

Use odd_degree_model to calculate an odd degree model.

EXAMPLES:

sage: x = QQ['x'].0
sage: HyperellipticCurve(x^5 + x).has_odd_degree_model()
True
sage: HyperellipticCurve(x^6 + x).has_odd_degree_model()
True
sage: HyperellipticCurve(x^6 + x + 1).has_odd_degree_model()
False
>>> from sage.all import *
>>> x = QQ['x'].gen(0)
>>> HyperellipticCurve(x**Integer(5) + x).has_odd_degree_model()
True
>>> HyperellipticCurve(x**Integer(6) + x).has_odd_degree_model()
True
>>> HyperellipticCurve(x**Integer(6) + x + Integer(1)).has_odd_degree_model()
False
hyperelliptic_involution(P)[source]

Return the image of P under the hyperelliptic involution.

EXAMPLES:

sage: R.<x> = FiniteField(17)[]
sage: H = HyperellipticCurve(x^6 + 2, x^2 + 1)
sage: P = H.point([8,12])
sage: P_inv = H.hyperelliptic_involution(P); P_inv
(8 : 8 : 1)
sage: H.hyperelliptic_involution(P_inv) == P
True
sage: Q = H.point([15,6])
sage: H.is_weierstrass_point(Q)
True
sage: H.hyperelliptic_involution(Q) == Q
True
>>> from sage.all import *
>>> R = FiniteField(Integer(17))['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(6) + Integer(2), x**Integer(2) + Integer(1))
>>> P = H.point([Integer(8),Integer(12)])
>>> P_inv = H.hyperelliptic_involution(P); P_inv
(8 : 8 : 1)
>>> H.hyperelliptic_involution(P_inv) == P
True
>>> Q = H.point([Integer(15),Integer(6)])
>>> H.is_weierstrass_point(Q)
True
>>> H.hyperelliptic_involution(Q) == Q
True
hyperelliptic_polynomials()[source]

Return the polynomials \((f, h)\) such that \(C : y^2 + hy = f\).

EXAMPLES:

sage: R.<x> = PolynomialRing(QQ)
sage: H = HyperellipticCurve(R([0, 1, 2, 0, 0, 1]), R([1, 1, 0, 1]))
sage: H.hyperelliptic_polynomials()
(x^5 + 2*x^2 + x, x^3 + x + 1)

sage: H = HyperellipticCurve(x^7 + x + 2)
sage: H.hyperelliptic_polynomials()
(x^7 + x + 2, 0)
>>> from sage.all import *
>>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(R([Integer(0), Integer(1), Integer(2), Integer(0), Integer(0), Integer(1)]), R([Integer(1), Integer(1), Integer(0), Integer(1)]))
>>> H.hyperelliptic_polynomials()
(x^5 + 2*x^2 + x, x^3 + x + 1)

>>> H = HyperellipticCurve(x**Integer(7) + x + Integer(2))
>>> H.hyperelliptic_polynomials()
(x^7 + x + 2, 0)
invariant_differential()[source]

Return \(dx/2y\), as an element of the Monsky-Washnitzer cohomology of self.

EXAMPLES:

sage: R.<x> = QQ['x']
sage: C = HyperellipticCurve(x^5 - 4*x + 4)
sage: C.invariant_differential()
1 dx/2y
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> C = HyperellipticCurve(x**Integer(5) - Integer(4)*x + Integer(4))
>>> C.invariant_differential()
1 dx/2y
is_inert()[source]

Return True if the curve is inert, i.e. there are no rational points at infinity.

EXAMPLES:

sage: R.<x> = PolynomialRing(QQ)
sage: H = HyperellipticCurve(x^6+1,-x^3+1)
sage: H.is_inert()
True

sage: K.<a> = QQ.extension(x^2+x-1)
sage: HK = H.change_ring(K)
sage: HK.is_inert()
False

sage: HF = H.change_ring(FiniteField(29))
sage: HF.is_inert()
False
>>> from sage.all import *
>>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(6)+Integer(1),-x**Integer(3)+Integer(1))
>>> H.is_inert()
True

>>> K = QQ.extension(x**Integer(2)+x-Integer(1), names=('a',)); (a,) = K._first_ngens(1)
>>> HK = H.change_ring(K)
>>> HK.is_inert()
False

>>> HF = H.change_ring(FiniteField(Integer(29)))
>>> HF.is_inert()
False
is_ramified()[source]

Return True if the curve is ramified, i.e. there is exactly one rational point at infinity.

EXAMPLES:

sage: R.<x> = PolynomialRing(QQ)
sage: H = HyperellipticCurve(x^5+1)
sage: H.is_ramified()
True

sage: H = HyperellipticCurve(x^5+1, x^3+1)
sage: H.is_ramified()
False
>>> from sage.all import *
>>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(5)+Integer(1))
>>> H.is_ramified()
True

>>> H = HyperellipticCurve(x**Integer(5)+Integer(1), x**Integer(3)+Integer(1))
>>> H.is_ramified()
False
is_singular()[source]

Return False, because hyperelliptic curves are smooth projective curves, as checked on construction.

EXAMPLES:

sage: R.<x> = QQ[]
sage: H = HyperellipticCurve(x^5 + 1)
sage: H.is_singular()
False
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(5) + Integer(1))
>>> H.is_singular()
False
is_smooth()[source]

Return True, because hyperelliptic curves are smooth projective curves, as checked on construction.

EXAMPLES:

sage: R.<x> = GF(13)[]
sage: H = HyperellipticCurve(x^8 + 1)
sage: H.is_smooth()
True
>>> from sage.all import *
>>> R = GF(Integer(13))['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(8) + Integer(1))
>>> H.is_smooth()
True
is_split()[source]

Return True if the curve is split, i.e. there are two rational points at infinity.

EXAMPLES:

sage: R.<x> = PolynomialRing(QQ)
sage: H = HyperellipticCurve(x^6+1, x^3+1)
sage: H.is_split()
False

sage: HK = H.change_ring(FiniteField(19))
sage: HK.is_split()
True
>>> from sage.all import *
>>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(6)+Integer(1), x**Integer(3)+Integer(1))
>>> H.is_split()
False

>>> HK = H.change_ring(FiniteField(Integer(19)))
>>> HK.is_split()
True
is_weierstrass_point(P)[source]

Return True if P is a Weierstrass point of self.

TODO: It would be better to define this function for points directly.

EXAMPLES:

sage: R.<x> = QQ[]
sage: H = HyperellipticCurve(x^6 - 1)
sage: P = H.point([1,0])
sage: H.is_weierstrass_point(P)
True
sage: Q = H.point([1,1,0])
sage: H.is_weierstrass_point(Q)
False
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(6) - Integer(1))
>>> P = H.point([Integer(1),Integer(0)])
>>> H.is_weierstrass_point(P)
True
>>> Q = H.point([Integer(1),Integer(1),Integer(0)])
>>> H.is_weierstrass_point(Q)
False

This also works for hyperelliptic curves with \(h(x)\) nonzero. Note that in this case the \(y\)-coordinate of a Weierstrass point is not necessarily zero:

sage: R.<x> = FiniteField(17)[]
sage: H = HyperellipticCurve(x^6 + 2, x^2 + 1)
sage: P = H.point([15,6,1])
sage: H.is_weierstrass_point(P)
True
sage: Q = H.point([3,0,1])
sage: H.is_weierstrass_point(Q)
False
[Python]
>>> from sage.all import *
>>> R = FiniteField(Integer(17))['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(6) + Integer(2), x**Integer(2) + Integer(1))
>>> P = H.point([Integer(15),Integer(6),Integer(1)])
>>> H.is_weierstrass_point(P)
True
>>> Q = H.point([Integer(3),Integer(0),Integer(1)])
>>> H.is_weierstrass_point(Q)
False
is_x_coord(x)[source]

Return True if x is the \(x\)-coordinate of a point on this curve.

See also

See also lift_x() to find the point(s) with a given \(x\)-coordinate. This function may be useful in cases where testing an element of the base field for being a square is faster than finding its square root.

INPUT:

  • x – an element of the base ring of the curve

OUTPUT:

A bool stating whether or not x is the \(x\)-coordinate of a point on the curve

EXAMPLES:

When \(x\) is the \(x\)-coordinate of a rational point on the curve, we can request these:

sage: R.<x> = PolynomialRing(QQ)
sage: f = x^5 + x^3 + 1
sage: H = HyperellipticCurve(f)
sage: H.is_x_coord(0)
True
>>> from sage.all import *
>>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1)
>>> f = x**Integer(5) + x**Integer(3) + Integer(1)
>>> H = HyperellipticCurve(f)
>>> H.is_x_coord(Integer(0))
True

There are no rational points with \(x\)-coordinate 3:

sage: H.is_x_coord(3)
False
[Python]
>>> from sage.all import *
>>> H.is_x_coord(Integer(3))
False

The function also handles the case when \(h(x)\) is not zero:

sage: R.<x> = PolynomialRing(QQ)
sage: f = x^5 + x^3 + 1
sage: h = x + 1
sage: H = HyperellipticCurve(f, h)
sage: H.is_x_coord(1)
True
>>> from sage.all import *
>>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1)
>>> f = x**Integer(5) + x**Integer(3) + Integer(1)
>>> h = x + Integer(1)
>>> H = HyperellipticCurve(f, h)
>>> H.is_x_coord(Integer(1))
True

We can perform these operations over finite fields too:

sage: # needs sage.rings.finite_rings
sage: R.<x> = PolynomialRing(GF(163))
sage: f = x^7 + x + 1
sage: H = HyperellipticCurve(f)
sage: H.is_x_coord(13)
True
[Python]
>>> from sage.all import *
>>> # needs sage.rings.finite_rings
>>> R = PolynomialRing(GF(Integer(163)), names=('x',)); (x,) = R._first_ngens(1)
>>> f = x**Integer(7) + x + Integer(1)
>>> H = HyperellipticCurve(f)
>>> H.is_x_coord(Integer(13))
True

Including the case of characteristic two:

sage: # needs sage.rings.finite_rings
sage: F.<z4> = GF(2^4)
sage: R.<x> = PolynomialRing(F)
sage: f = x^7 + x^3 + 1
sage: h = x + 1
sage: H = HyperellipticCurve(f, h)
sage: H.is_x_coord(z4^3 + z4^2 + z4)
True
>>> from sage.all import *
>>> # needs sage.rings.finite_rings
>>> F = GF(Integer(2)**Integer(4), names=('z4',)); (z4,) = F._first_ngens(1)
>>> R = PolynomialRing(F, names=('x',)); (x,) = R._first_ngens(1)
>>> f = x**Integer(7) + x**Integer(3) + Integer(1)
>>> h = x + Integer(1)
>>> H = HyperellipticCurve(f, h)
>>> H.is_x_coord(z4**Integer(3) + z4**Integer(2) + z4)
True

AUTHORS:

  • Giacomo Pope (2024): adapted from lift_x()

jacobian()[source]

Return the Jacobian of the hyperelliptic curve.

Elements of the Jacobian are represented by tuples of the form \((u, v, n)\), where

  • \((u, v)\) is the Mumford representative of a divisor \(P_1 + ... + P_r\),

  • \(n\) is a non-negative integer

This tuple represents the equivalence class

\[[P_1 + ... + P_r + n \cdot \infty_+ + m\cdot \infty_- - D_\infty],\]

where \(m = g - \deg(u) - n\), and \(\infty_+\), \(\infty_-\) are the points at infinity of the hyperelliptic curve,

\[D_\infty = \lceil g/2 \rceil \infty_+ + \lfloor g/2 \rfloor \infty_-.\]

Here, \(\infty_- = \infty_+\), if the hyperelliptic curve is ramified.

Such a representation exists and is unique, unless the genus \(g\) is odd and the curve is inert.

If the hyperelliptic curve is ramified or inert, then \(n\) can be deduced from \(\deg(u)\) and \(g\). In these cases, \(n\) is omitted in the description.

EXAMPLES:

sage: R.<x> = QQ[]
sage: H = HyperellipticCurve(2*x^5 + 4*x^4 + x^3 - x, x^3 + x + 1)
sage: J = H.jacobian(); J
Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 + (x^3 + x + 1)*y = 2*x^5 + 4*x^4 + x^3 - x
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(Integer(2)*x**Integer(5) + Integer(4)*x**Integer(4) + x**Integer(3) - x, x**Integer(3) + x + Integer(1))
>>> J = H.jacobian(); J
Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 + (x^3 + x + 1)*y = 2*x^5 + 4*x^4 + x^3 - x

The points \(P = (0, 0)\) and \(Q = (-1, -1)\) are on \(H\). We construct the element \(D_1 = [P - Q] = [P + (-Q) - D_\infty\)] on the Jacobian:

sage: P = H.point([0, 0])
sage: Q = H.point([-1, -1])
sage: D1 = J(P,Q); D1
(x^2 + x, -2*x : 0)
[Python]
>>> from sage.all import *
>>> P = H.point([Integer(0), Integer(0)])
>>> Q = H.point([-Integer(1), -Integer(1)])
>>> D1 = J(P,Q); D1
(x^2 + x, -2*x : 0)

Elements of the Jacobian can also be constructed by directly providing the Mumford representation:

sage: D1 == J(x^2 + x, -2*x, 0)
True
>>> from sage.all import *
>>> D1 == J(x**Integer(2) + x, -Integer(2)*x, Integer(0))
True

We can also embed single points into the Jacobian. Below we construct \(D_2 = [P - P_0]\), where \(P_0\) is the distinguished point of \(H\) (by default one of the points at infinity):

sage: D2 = J(P); D2
(x, 0 : 0)
sage: P0 = H.distinguished_point(); P0
(1 : 0 : 0)
sage: D2 == J(P, P0)
True
[Python]
>>> from sage.all import *
>>> D2 = J(P); D2
(x, 0 : 0)
>>> P0 = H.distinguished_point(); P0
(1 : 0 : 0)
>>> D2 == J(P, P0)
True

We may add elements, or multiply by integers:

sage: 2*D1
(x, -1 : 1)
sage: D1 + D2
(x^2 + x, -1 : 0)
sage: -D2
(x, -1 : 1)
>>> from sage.all import *
>>> Integer(2)*D1
(x, -1 : 1)
>>> D1 + D2
(x^2 + x, -1 : 0)
>>> -D2
(x, -1 : 1)

Note that the neutral element is given by \([D_\infty - D_\infty]\), in particular \(n = \lceil g/2 \rceil\):

sage: J.zero()
(1, 0 : 1)
[Python]
>>> from sage.all import *
>>> J.zero()
(1, 0 : 1)

There are two more elements of the Jacobian that are only supported at infinity: \([\infty_+ - \infty_-]\) and \([\infty_- - \infty_+]\):

sage: [P_plus, P_minus] = H.points_at_infinity()
sage: P_plus == P0
True
sage: J(P_plus,P_minus)
(1, 0 : 2)
sage: J(P_minus, P_plus)
(1, 0 : 0)
>>> from sage.all import *
>>> [P_plus, P_minus] = H.points_at_infinity()
>>> P_plus == P0
True
>>> J(P_plus,P_minus)
(1, 0 : 2)
>>> J(P_minus, P_plus)
(1, 0 : 0)

Now, we consider the Jacobian of a hyperelliptic curve with only one point at infinity, defined over a finite field:

sage: K = FiniteField(7)
sage: R.<x> = K[]
sage: H = HyperellipticCurve(x^7 + 3*x + 2)
sage: J = H.jacobian(); J
Jacobian of Hyperelliptic Curve over Finite Field of size 7 defined by y^2 = x^7 + 3*x + 2
[Python]
>>> from sage.all import *
>>> K = FiniteField(Integer(7))
>>> R = K['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(7) + Integer(3)*x + Integer(2))
>>> J = H.jacobian(); J
Jacobian of Hyperelliptic Curve over Finite Field of size 7 defined by y^2 = x^7 + 3*x + 2

Elements on the Jacobian can be constructed as before. But the value \(n\) is not used here, since there is exactly one point at infinity:

sage: P = H.point([3, 0])
sage: Q = H.point([5, 1])
sage: D1 = J(P,Q); D1
(x^2 + 6*x + 1, 3*x + 5)
sage: D2 = J(x^3 + 3*x^2 + 4*x + 3, 2*x^2 + 4*x)
sage: D1 + D2
(x^3 + 2, 4)
>>> from sage.all import *
>>> P = H.point([Integer(3), Integer(0)])
>>> Q = H.point([Integer(5), Integer(1)])
>>> D1 = J(P,Q); D1
(x^2 + 6*x + 1, 3*x + 5)
>>> D2 = J(x**Integer(3) + Integer(3)*x**Integer(2) + Integer(4)*x + Integer(3), Integer(2)*x**Integer(2) + Integer(4)*x)
>>> D1 + D2
(x^3 + 2, 4)

Over finite fields, we may also construct random elements and compute the order of the Jacobian:

sage: J.random_element() #random
(x^3 + x^2 + 4*x + 5, 3*x^2 + 3*x)
sage: J.order()
344
[Python]
>>> from sage.all import *
>>> J.random_element() #random
(x^3 + x^2 + 4*x + 5, 3*x^2 + 3*x)
>>> J.order()
344

Note that arithmetic on the Jacobian is not implemented if the underlying hyperelliptic curve is inert (i.e. has no points at infinity) and the genus is odd:

sage: R.<x> = GF(13)[]
sage: H = HyperellipticCurve(x^8+1,x^4+1)
sage: J = H.jacobian()
sage: J.zero()
Traceback (most recent call last):
...
NotImplementedError: unable to perform arithmetic for inert models of odd genus; consider extending the base field to adjoin the points at infinity
>>> from sage.all import *
>>> R = GF(Integer(13))['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(8)+Integer(1),x**Integer(4)+Integer(1))
>>> J = H.jacobian()
>>> J.zero()
Traceback (most recent call last):
...
NotImplementedError: unable to perform arithmetic for inert models of odd genus; consider extending the base field to adjoin the points at infinity
lift_x(x, all=False)[source]

Return one or all finite points with given \(x\)-coordinate.

This method is deterministic: It returns the same data each time when called again with the same \(x\).

INPUT:

  • x – an element of the base ring of the curve

  • all (bool, default False) – if True, return a (possibly empty) list of all points; if False, return just one point, or raise a ValueError if there are none.

OUTPUT:

A point or list of up to two points on this curve.

See also

is_x_coord()

AUTHORS:

  • Giacomo Pope (2024): Allowed for the case of characteristic two

EXAMPLES:

When \(x\) is the \(x\)-coordinate of a rational point on the curve, we can request these:

sage: R.<x> = PolynomialRing(QQ)
sage: f = x^5 + x^3 + 1
sage: H = HyperellipticCurve(f)
sage: H.lift_x(0)
(0 : -1 : 1)
sage: H.lift_x(4, all=True)
[(4 : -33 : 1), (4 : 33 : 1)]
>>> from sage.all import *
>>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1)
>>> f = x**Integer(5) + x**Integer(3) + Integer(1)
>>> H = HyperellipticCurve(f)
>>> H.lift_x(Integer(0))
(0 : -1 : 1)
>>> H.lift_x(Integer(4), all=True)
[(4 : -33 : 1), (4 : 33 : 1)]

There are no rational points with \(x\)-coordinate 3:

sage: H.lift_x(3)
Traceback (most recent call last):
...
ValueError: No point with x-coordinate 3 on Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x^3 + 1
[Python]
>>> from sage.all import *
>>> H.lift_x(Integer(3))
Traceback (most recent call last):
...
ValueError: No point with x-coordinate 3 on Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x^3 + 1

An empty list is returned when there are no points and all=True:

sage: H.lift_x(3, all=True)
[]
>>> from sage.all import *
>>> H.lift_x(Integer(3), all=True)
[]

The function also handles the case when \(h(x)\) is not zero:

sage: R.<x> = PolynomialRing(QQ)
sage: f = x^5 + x^3 + 1
sage: h = x + 1
sage: H = HyperellipticCurve(f, h)
sage: H.lift_x(1)
(1 : -3 : 1)
[Python]
>>> from sage.all import *
>>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1)
>>> f = x**Integer(5) + x**Integer(3) + Integer(1)
>>> h = x + Integer(1)
>>> H = HyperellipticCurve(f, h)
>>> H.lift_x(Integer(1))
(1 : -3 : 1)

We can perform these operations over finite fields too:

sage: # needs sage.rings.finite_rings
sage: R.<x> = PolynomialRing(GF(163))
sage: f = x^7 + x + 1
sage: H = HyperellipticCurve(f)
sage: H.lift_x(13)
(13 : 41 : 1)
>>> from sage.all import *
>>> # needs sage.rings.finite_rings
>>> R = PolynomialRing(GF(Integer(163)), names=('x',)); (x,) = R._first_ngens(1)
>>> f = x**Integer(7) + x + Integer(1)
>>> H = HyperellipticCurve(f)
>>> H.lift_x(Integer(13))
(13 : 41 : 1)

Including the case of characteristic two:

sage: # needs sage.rings.finite_rings
sage: F.<z4> = GF(2^4)
sage: R.<x> = PolynomialRing(F)
sage: f = x^7 + x^3 + 1
sage: h = x + 1
sage: H = HyperellipticCurve(f, h)
sage: H.lift_x(z4^3 + z4^2 + z4, all=True)
[(z4^3 + z4^2 + z4 : z4^2 + z4 + 1 : 1), (z4^3 + z4^2 + z4 : z4^3 : 1)]
[Python]
>>> from sage.all import *
>>> # needs sage.rings.finite_rings
>>> F = GF(Integer(2)**Integer(4), names=('z4',)); (z4,) = F._first_ngens(1)
>>> R = PolynomialRing(F, names=('x',)); (x,) = R._first_ngens(1)
>>> f = x**Integer(7) + x**Integer(3) + Integer(1)
>>> h = x + Integer(1)
>>> H = HyperellipticCurve(f, h)
>>> H.lift_x(z4**Integer(3) + z4**Integer(2) + z4, all=True)
[(z4^3 + z4^2 + z4 : z4^2 + z4 + 1 : 1), (z4^3 + z4^2 + z4 : z4^3 : 1)]

Points at infinity are not included, as they do not have a unique x-coordinate:

sage: R.<x> = QQ[]
sage: H = HyperellipticCurve(x^8 + 1)
sage: H(1, -1, 0)
(1 : -1 : 0)
sage: H.lift_x(1, all=True)
[]
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(8) + Integer(1))
>>> H(Integer(1), -Integer(1), Integer(0))
(1 : -1 : 0)
>>> H.lift_x(Integer(1), all=True)
[]
local_coord(P, prec=20, name='t')[source]

For point P = (a,b) on the hyperelliptic curve \(y^2 + h(x)*y = f(x)\), return \((x(t), y(t))\) such that \((y(t))^2 + h(x(t))*y(t) = f(x(t))\), where \(t\) is the local parameter at that point.

INPUT:

  • P – a point on self

  • prec – desired precision of the local coordinates

  • name – generator of the power series ring (default: t)

OUTPUT:

\((x(t),y(t))\) such that \(y(t)^2 + h(x(t))*y(t) = f(x(t))\), where \(t\) is the local parameter at \(P\)

EXAMPLES:

We compute the local coordinates of several points of the curve with defining equation \(y^2 = x^5 - 23 x^3 + 18 x^2 + 40 x\):

sage: R.<x> = QQ['x']
sage: H = HyperellipticCurve(x^5 - 23*x^3 + 18*x^2 + 40*x)
sage: H.local_coord(H(1 ,6), prec=5)
(1 + t + O(t^5), 6 + t - 7/2*t^2 - 1/2*t^3 - 25/48*t^4 + O(t^5))
sage: H.local_coord(H(4, 0), prec=7)
(4 + 1/360*t^2 - 191/23328000*t^4 + 7579/188956800000*t^6 + O(t^7), t + O(t^7))
sage: H.local_coord(H(1, 0, 0), prec=5)
(t^-2 - 23*t^2 + 18*t^4 - 1018*t^6 + O(t^7),
t^-5 - 69*t^-1 + 54*t - 1467*t^3 + 3726*t^5 + O(t^6))
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(5) - Integer(23)*x**Integer(3) + Integer(18)*x**Integer(2) + Integer(40)*x)
>>> H.local_coord(H(Integer(1) ,Integer(6)), prec=Integer(5))
(1 + t + O(t^5), 6 + t - 7/2*t^2 - 1/2*t^3 - 25/48*t^4 + O(t^5))
>>> H.local_coord(H(Integer(4), Integer(0)), prec=Integer(7))
(4 + 1/360*t^2 - 191/23328000*t^4 + 7579/188956800000*t^6 + O(t^7), t + O(t^7))
>>> H.local_coord(H(Integer(1), Integer(0), Integer(0)), prec=Integer(5))
(t^-2 - 23*t^2 + 18*t^4 - 1018*t^6 + O(t^7),
t^-5 - 69*t^-1 + 54*t - 1467*t^3 + 3726*t^5 + O(t^6))

We compute the local coordinates of several points of the curve with defining equation \(y^2 + (x^3 + 1) y = x^4 + 2 x^3 + x^2 - x\).

sage: H = HyperellipticCurve(x^4+2*x^3+x^2-x,x^3+1)
sage: H.local_coord(H(1,-3,1), prec=5)
(1 + t + O(t^5), -3 - 5*t - 3*t^2 - 3/4*t^3 - 3/16*t^4 + O(t^5))
sage: H.local_coord(H(1,-1,0), prec=5)
(t^-1 + O(t^7), -t^-3 - t^-1 - 3 + 6*t^2 + 6*t^3 - 12*t^4 - 42*t^5 + O(t^6))
[Python]
>>> from sage.all import *
>>> H = HyperellipticCurve(x**Integer(4)+Integer(2)*x**Integer(3)+x**Integer(2)-x,x**Integer(3)+Integer(1))
>>> H.local_coord(H(Integer(1),-Integer(3),Integer(1)), prec=Integer(5))
(1 + t + O(t^5), -3 - 5*t - 3*t^2 - 3/4*t^3 - 3/16*t^4 + O(t^5))
>>> H.local_coord(H(Integer(1),-Integer(1),Integer(0)), prec=Integer(5))
(t^-1 + O(t^7), -t^-3 - t^-1 - 3 + 6*t^2 + 6*t^3 - 12*t^4 - 42*t^5 + O(t^6))

AUTHOR:

  • Jennifer Balakrishnan (2007-12)

  • Sabrina Kunzweiler, Gareth Ma, Giacomo Pope (2024): adapt to smooth model

local_coordinates_at_infinity_ramified(prec=20, name='t')[source]

For a hyperelliptic curve with ramified model \(y^2 + h(x)*y = f(x)\), return \((x(t), y(t))\) such that \((y(t))^2 = f(x(t))\), where \(t = y/x^{g+1}\) is the local parameter at the unique (Weierstrass) point at infinity.

TODO/NOTE: In the previous implementation \(t = x^g/y\) was used. This is not a valid parameter on the smooth model, and the output is necessarily different.

INPUT:

  • prec – desired precision of the local coordinates

  • name – generator of the power series ring (default: t)

OUTPUT:

\((x(t),y(t))\) such that \(y(t)^2 = f(x(t))\) and \(t = y/x^{g+1}\) is the local parameter at infinity

EXAMPLES:

We compute the local coordinates at the point at infinity of the hyperelliptic curve \(y^2 = x^5 - 5 x^2 + 1\):

sage: R.<x> = QQ['x']
sage: H = HyperellipticCurve(x^5 - 5*x^2 + 1)
sage: xt, yt = H.local_coordinates_at_infinity_ramified(prec=10)
sage: (xt,yt)
(t^-2 - 5*t^4 + t^8 - 75*t^10 + O(t^12),
t^-5 - 15*t + 3*t^5 - 150*t^7 + 90*t^11 + O(t^12))
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(5) - Integer(5)*x**Integer(2) + Integer(1))
>>> xt, yt = H.local_coordinates_at_infinity_ramified(prec=Integer(10))
>>> (xt,yt)
(t^-2 - 5*t^4 + t^8 - 75*t^10 + O(t^12),
t^-5 - 15*t + 3*t^5 - 150*t^7 + 90*t^11 + O(t^12))

We verify that \(y(t)^2 = f(x(t))\) and \(t = y(t)/x(t)^3\):

sage: f,_ = H.hyperelliptic_polynomials()
sage: (yt^2 - f(xt)).is_zero()
True
sage: yt/xt^3
t + O(t^15)
[Python]
>>> from sage.all import *
>>> f,_ = H.hyperelliptic_polynomials()
>>> (yt**Integer(2) - f(xt)).is_zero()
True
>>> yt/xt**Integer(3)
t + O(t^15)

The method also works when \(h\) is nonzero. We compute the local coordinates of the point at infinity of the hyperelliptic curve \(y^2 + y = x^5 - 9 x^4 + 14 x^3 - 19 x^2 + 11 x - 6\):

sage: H = HyperellipticCurve(x^5-9*x^4+14*x^3-19*x^2+11*x-6,1)
sage: f,h = H.hyperelliptic_polynomials()
sage: xt,yt = H.local_coordinates_at_infinity_ramified()
sage: (yt^2 + h(xt)*yt - f(xt)).is_zero()
True
>>> from sage.all import *
>>> H = HyperellipticCurve(x**Integer(5)-Integer(9)*x**Integer(4)+Integer(14)*x**Integer(3)-Integer(19)*x**Integer(2)+Integer(11)*x-Integer(6),Integer(1))
>>> f,h = H.hyperelliptic_polynomials()
>>> xt,yt = H.local_coordinates_at_infinity_ramified()
>>> (yt**Integer(2) + h(xt)*yt - f(xt)).is_zero()
True

Note that the point at infinity has to be a Weierstrass point.

AUTHOR:

  • Jennifer Balakrishnan (2007-12)

  • Sabrina Kunzweiler, Gareth Ma, Giacomo Pope (2024): adapt to smooth model

local_coordinates_at_infinity_split(P, prec=20, name='t')[source]

For a point at infinity P = (a:b:0) on a hyperelliptic curve with split model \(y^2 + h(x)*y = f(x)\), return \((x(t), y(t))\) such that \((y(t))^2 = f(x(t))\). Here \(t = a/x\) is the local parameter at P.

INPUT:

  • P – a point at infinity of a self

  • prec – desired precision of the local coordinates

  • name – generator of the power series ring (default: t)

OUTPUT:

\((x(t),y(t))\) such that \(y(t)^2 = f(x(t))\) and \(t = y/x^{g+1}\) is the local parameter at infinity

EXAMPLES:

We compute the local coordinates at the point at infinity of the hyperelliptic curve:

sage: R.<x> = QQ['x']
sage: H = HyperellipticCurve(x^6+4*x^4 + 4*x^2+1)
sage: P1 = H(1,-1,0)
sage: xt1,yt1 = H.local_coordinates_at_infinity_split(P1)
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(6)+Integer(4)*x**Integer(4) + Integer(4)*x**Integer(2)+Integer(1))
>>> P1 = H(Integer(1),-Integer(1),Integer(0))
>>> xt1,yt1 = H.local_coordinates_at_infinity_split(P1)

Note the similarity to the local coordinates of the other point at infinity:

sage: P2 = H(1,1,0)
sage: xt2,yt2 = H.local_coordinates_at_infinity_split(P2)
sage: xt1 == xt2 and yt1 == - yt2
True
[Python]
>>> from sage.all import *
>>> P2 = H(Integer(1),Integer(1),Integer(0))
>>> xt2,yt2 = H.local_coordinates_at_infinity_split(P2)
>>> xt1 == xt2 and yt1 == - yt2
True

Similarly, if \(h\) is nonzero, the relation between the local coordinates at the points at infinity is obtained from the hyperelliptic involution:

sage: H = HyperellipticCurve(-x^5, x^3+x+1)
sage: f,h = H.hyperelliptic_polynomials()
sage: P1 = H(1,0,0)
sage: P2 = H(1,-1,0)
sage: xt1,yt1 = H.local_coordinates_at_infinity_split(P1)
sage: xt2,yt2 = H.local_coordinates_at_infinity_split(P2)
sage: (yt1 + yt2 + h(xt1)).is_zero()
True
>>> from sage.all import *
>>> H = HyperellipticCurve(-x**Integer(5), x**Integer(3)+x+Integer(1))
>>> f,h = H.hyperelliptic_polynomials()
>>> P1 = H(Integer(1),Integer(0),Integer(0))
>>> P2 = H(Integer(1),-Integer(1),Integer(0))
>>> xt1,yt1 = H.local_coordinates_at_infinity_split(P1)
>>> xt2,yt2 = H.local_coordinates_at_infinity_split(P2)
>>> (yt1 + yt2 + h(xt1)).is_zero()
True

AUTHOR:

  • Jennifer Balakrishnan (2007-12)

  • Sabrina Kunzweiler, Gareth Ma, Giacomo Pope (2024): adapt to smooth model

local_coordinates_at_nonweierstrass(P, prec=20, name='t')[source]

For a non-Weierstrass point P = (a, b) on the hyperelliptic curve \(y^2 + h(x) * y = f(x)\), return \((x(t), y(t))\) such that \((y(t))^2 = f(x(t))\), where \(t = x - a\) is the local parameter.

INPUT:

  • P = (a, b) – a non-Weierstrass point on self

  • prec – desired precision of the local coordinates

  • name – gen of the power series ring (default: t)

OUTPUT:

\((x(t),y(t))\) such that \(y(t)^2 + y(t)*h(x(t)) = f(x(t))\) and \(t = x - a\) is the local parameter at \(P\).

EXAMPLES:

We compute the local coordinates of \(H : y^2 = x^5 - 23*x^3 + 18*x^2 + 40*x\) at the point \(P = (1, 6)\):

sage: R.<x> = QQ['x']
sage: H = HyperellipticCurve(x^5 - 23*x^3 + 18*x^2 + 40*x)
sage: P = H(1, 6)
sage: xt, yt = H.local_coordinates_at_nonweierstrass(P, prec=5)
sage: (xt, yt)
(1 + t + O(t^5),  6 + t - 7/2*t^2 - 1/2*t^3 - 25/48*t^4 + O(t^5))
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(5) - Integer(23)*x**Integer(3) + Integer(18)*x**Integer(2) + Integer(40)*x)
>>> P = H(Integer(1), Integer(6))
>>> xt, yt = H.local_coordinates_at_nonweierstrass(P, prec=Integer(5))
>>> (xt, yt)
(1 + t + O(t^5),  6 + t - 7/2*t^2 - 1/2*t^3 - 25/48*t^4 + O(t^5))

We verify that \(y(t) = f(x(t))\):

sage: f,_ = H.hyperelliptic_polynomials()
sage: (yt^2 - f(xt)).is_zero()
True
[Python]
>>> from sage.all import *
>>> f,_ = H.hyperelliptic_polynomials()
>>> (yt**Integer(2) - f(xt)).is_zero()
True

We can also compute the local coordinates of points on a hyperelliptic curve with equation \(y^2 + h(x)*y = f(x)\):

sage: H = HyperellipticCurve(x^6+3*x^5+6*x^4+7*x^3+6*x^2+3*x+1, x^2+x) # 196.a.21952.1
sage: P = H(-1,1)
sage: xt, yt = H.local_coordinates_at_nonweierstrass(P, prec=5)
sage: (xt, yt)
(-1 + t + O(t^5), 1 - t + 3/2*t^2 - 3/4*t^3 + O(t^5))
sage: f,h = H.hyperelliptic_polynomials()
sage: (yt^2 + h(xt)*yt -f(xt)).is_zero()
True
>>> from sage.all import *
>>> H = HyperellipticCurve(x**Integer(6)+Integer(3)*x**Integer(5)+Integer(6)*x**Integer(4)+Integer(7)*x**Integer(3)+Integer(6)*x**Integer(2)+Integer(3)*x+Integer(1), x**Integer(2)+x) # 196.a.21952.1
>>> P = H(-Integer(1),Integer(1))
>>> xt, yt = H.local_coordinates_at_nonweierstrass(P, prec=Integer(5))
>>> (xt, yt)
(-1 + t + O(t^5), 1 - t + 3/2*t^2 - 3/4*t^3 + O(t^5))
>>> f,h = H.hyperelliptic_polynomials()
>>> (yt**Integer(2) + h(xt)*yt -f(xt)).is_zero()
True

AUTHORS:

  • Jennifer Balakrishnan (2007-12)

  • Sabrina Kunzweiler, Gareth Ma, Giacomo Pope (2024): adapt to smooth model

local_coordinates_at_weierstrass(P, prec=20, name='t')[source]

For a finite Weierstrass point P = (a,b) on the hyperelliptic curve \(y^2 + h(x)*y = f(x)\), return \((x(t), y(t))\) such that \(y(t)^2 + h(x(t))*y(t) = f(x(t))\), where \(t = y - b\) is the local parameter.

INPUT:

  • P – a finite Weierstrass point on self

  • prec – desired precision of the local coordinates

  • name – gen of the power series ring (default: \(t\))

OUTPUT:

\((x(t),y(t))\) such that \(y(t)^2 + h(x(t))*y(t) = f(x(t))\) and \(t = y - b\) is the local parameter at \(P = (a,b)\).

EXAMPLES:

We compute the local coordinates of the Weierstrass point \(P = (4,0)\) on the hyperelliptic curve \(y^2 = x^5 - 23 x^3 + 18 x^2 + 40 x\):

sage: R.<x> = QQ['x']
sage: H = HyperellipticCurve(x^5 - 23*x^3 + 18*x^2 + 40*x)
sage: P = H(4, 0)
sage: xt, yt = H.local_coordinates_at_weierstrass(P, prec=7)
sage: xt
4 + 1/360*t^2 - 191/23328000*t^4 + 7579/188956800000*t^6 + O(t^7)
sage: yt
t + O(t^7)
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(5) - Integer(23)*x**Integer(3) + Integer(18)*x**Integer(2) + Integer(40)*x)
>>> P = H(Integer(4), Integer(0))
>>> xt, yt = H.local_coordinates_at_weierstrass(P, prec=Integer(7))
>>> xt
4 + 1/360*t^2 - 191/23328000*t^4 + 7579/188956800000*t^6 + O(t^7)
>>> yt
t + O(t^7)

We verify that \(y(t) = f(x(t))\):

sage: f,_ = H.hyperelliptic_polynomials()
sage: (yt^2 - f(xt)).is_zero()
True
[Python]
>>> from sage.all import *
>>> f,_ = H.hyperelliptic_polynomials()
>>> (yt**Integer(2) - f(xt)).is_zero()
True

We compute the local coordinates at the Weierstrass point \((1,-1)\) of the hyperelliptic curve \(y^2 + (x^3 + 1) y = -x^2\):

sage: H = HyperellipticCurve(-x^2, x^3+1)
sage: P = H(1,-1)
sage: xt,yt = H.local_coordinates_at_weierstrass(P)
sage: f,h = H.hyperelliptic_polynomials()
sage: (yt^2 + h(xt)*yt - f(xt)).is_zero()
True
>>> from sage.all import *
>>> H = HyperellipticCurve(-x**Integer(2), x**Integer(3)+Integer(1))
>>> P = H(Integer(1),-Integer(1))
>>> xt,yt = H.local_coordinates_at_weierstrass(P)
>>> f,h = H.hyperelliptic_polynomials()
>>> (yt**Integer(2) + h(xt)*yt - f(xt)).is_zero()
True

AUTHOR:

  • Jennifer Balakrishnan (2007-12)

  • Francis Clarke (2012-08-26)

  • Sabrina Kunzweiler, Gareth Ma, Giacomo Pope (2024): adapt to smooth model

monsky_washnitzer_gens()[source]

Compute the generators of the special hyperelliptic quotient ring

EXAMPLES:

sage: R.<x> = QQ[]
sage: H = HyperellipticCurve(x^5+1)
sage: [x0, y0] = H.monsky_washnitzer_gens(); x0, y0
(x, y*1)
sage: x0^10
(1-2*y^2+y^4)*1
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(5)+Integer(1))
>>> [x0, y0] = H.monsky_washnitzer_gens(); x0, y0
(x, y*1)
>>> x0**Integer(10)
(1-2*y^2+y^4)*1
odd_degree_model()[source]

Return an odd degree model of self, or raise ValueError if one does not exist over the field of definition. The term odd degree model refers to a model of the form \(y^2 = f(x)\) with \(\deg(f) = 2 g + 1\).

EXAMPLES:

sage: x = QQ['x'].gen()
sage: H = HyperellipticCurve((x^2 + 2)*(x^2 + 3)*(x^2 + 5)); H
Hyperelliptic Curve over Rational Field defined by y^2 = x^6 + 10*x^4 + 31*x^2 + 30
sage: H.odd_degree_model()
Traceback (most recent call last):
...
ValueError: No odd degree model exists over field of definition

sage: K2 = QuadraticField(-2, 'a')                                          # needs sage.rings.number_field
sage: Hp2 = H.change_ring(K2).odd_degree_model(); Hp2                       # needs sage.rings.number_field
Hyperelliptic Curve over Number Field in a
 with defining polynomial x^2 + 2 with a = 1.414213562373095?*I
 defined by y^2 = 6*a*x^5 - 29*x^4 - 20*x^2 + 6*a*x + 1

sage: K3 = QuadraticField(-3, 'b')                                          # needs sage.rings.number_field
sage: Hp3 = H.change_ring(QuadraticField(-3, 'b')).odd_degree_model(); Hp3  # needs sage.rings.number_field
Hyperelliptic Curve over Number Field in b
 with defining polynomial x^2 + 3 with b = 1.732050807568878?*I
 defined by y^2 = -4*b*x^5 - 14*x^4 - 20*b*x^3 - 35*x^2 + 6*b*x + 1
>>> from sage.all import *
>>> x = QQ['x'].gen()
>>> H = HyperellipticCurve((x**Integer(2) + Integer(2))*(x**Integer(2) + Integer(3))*(x**Integer(2) + Integer(5))); H
Hyperelliptic Curve over Rational Field defined by y^2 = x^6 + 10*x^4 + 31*x^2 + 30
>>> H.odd_degree_model()
Traceback (most recent call last):
...
ValueError: No odd degree model exists over field of definition

>>> K2 = QuadraticField(-Integer(2), 'a')                                          # needs sage.rings.number_field
>>> Hp2 = H.change_ring(K2).odd_degree_model(); Hp2                       # needs sage.rings.number_field
Hyperelliptic Curve over Number Field in a
 with defining polynomial x^2 + 2 with a = 1.414213562373095?*I
 defined by y^2 = 6*a*x^5 - 29*x^4 - 20*x^2 + 6*a*x + 1

>>> K3 = QuadraticField(-Integer(3), 'b')                                          # needs sage.rings.number_field
>>> Hp3 = H.change_ring(QuadraticField(-Integer(3), 'b')).odd_degree_model(); Hp3  # needs sage.rings.number_field
Hyperelliptic Curve over Number Field in b
 with defining polynomial x^2 + 3 with b = 1.732050807568878?*I
 defined by y^2 = -4*b*x^5 - 14*x^4 - 20*b*x^3 - 35*x^2 + 6*b*x + 1

Of course, Hp2 and Hp3 are isomorphic over the composite extension. One consequence of this is that odd degree models reduced over “different” fields should have the same number of points on their reductions. 43 and 67 split completely in the compositum, so when we reduce we find:

sage: # needs sage.rings.number_field
sage: P2 = K2.factor(43)[0][0]
sage: P3 = K3.factor(43)[0][0]
sage: Hp2.change_ring(K2.residue_field(P2)).frobenius_polynomial()
x^4 - 16*x^3 + 134*x^2 - 688*x + 1849
sage: Hp3.change_ring(K3.residue_field(P3)).frobenius_polynomial()
x^4 - 16*x^3 + 134*x^2 - 688*x + 1849

sage: H.change_ring(GF(43)).odd_degree_model().frobenius_polynomial()       # needs sage.rings.finite_rings
x^4 - 16*x^3 + 134*x^2 - 688*x + 1849

sage: # needs sage.rings.number_field
sage: P2 = K2.factor(67)[0][0]
sage: P3 = K3.factor(67)[0][0]
sage: Hp2.change_ring(K2.residue_field(P2)).frobenius_polynomial()
x^4 - 8*x^3 + 150*x^2 - 536*x + 4489
sage: Hp3.change_ring(K3.residue_field(P3)).frobenius_polynomial()
x^4 - 8*x^3 + 150*x^2 - 536*x + 4489

sage: H.change_ring(GF(67)).odd_degree_model().frobenius_polynomial()       # needs sage.rings.finite_rings
x^4 - 8*x^3 + 150*x^2 - 536*x + 4489
[Python]
>>> from sage.all import *
>>> # needs sage.rings.number_field
>>> P2 = K2.factor(Integer(43))[Integer(0)][Integer(0)]
>>> P3 = K3.factor(Integer(43))[Integer(0)][Integer(0)]
>>> Hp2.change_ring(K2.residue_field(P2)).frobenius_polynomial()
x^4 - 16*x^3 + 134*x^2 - 688*x + 1849
>>> Hp3.change_ring(K3.residue_field(P3)).frobenius_polynomial()
x^4 - 16*x^3 + 134*x^2 - 688*x + 1849

>>> H.change_ring(GF(Integer(43))).odd_degree_model().frobenius_polynomial()       # needs sage.rings.finite_rings
x^4 - 16*x^3 + 134*x^2 - 688*x + 1849

>>> # needs sage.rings.number_field
>>> P2 = K2.factor(Integer(67))[Integer(0)][Integer(0)]
>>> P3 = K3.factor(Integer(67))[Integer(0)][Integer(0)]
>>> Hp2.change_ring(K2.residue_field(P2)).frobenius_polynomial()
x^4 - 8*x^3 + 150*x^2 - 536*x + 4489
>>> Hp3.change_ring(K3.residue_field(P3)).frobenius_polynomial()
x^4 - 8*x^3 + 150*x^2 - 536*x + 4489

>>> H.change_ring(GF(Integer(67))).odd_degree_model().frobenius_polynomial()       # needs sage.rings.finite_rings
x^4 - 8*x^3 + 150*x^2 - 536*x + 4489

The case where \(h(x)\) is nonzero is also supported:

sage: HyperellipticCurve(x^5 + 1, 1).odd_degree_model()
Hyperelliptic Curve over Rational Field defined by y^2 = 4*x^5 + 5
>>> from sage.all import *
>>> HyperellipticCurve(x**Integer(5) + Integer(1), Integer(1)).odd_degree_model()
Hyperelliptic Curve over Rational Field defined by y^2 = 4*x^5 + 5
points_at_infinity()[source]

Compute the points at infinity on the curve.

EXAMPLES:

sage: R.<x> = PolynomialRing(QQ)
sage: H = HyperellipticCurve(x^6 + 1, x^3 + 1)
sage: H.points_at_infinity()
[]
sage: K.<omega> = QQ.extension(x^2 + x -1)
sage: H.change_ring(K).points_at_infinity()
[(1 : omega : 0), (1 : -omega - 1 : 0)]
>>> from sage.all import *
>>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(6) + Integer(1), x**Integer(3) + Integer(1))
>>> H.points_at_infinity()
[]
>>> K = QQ.extension(x**Integer(2) + x -Integer(1), names=('omega',)); (omega,) = K._first_ngens(1)
>>> H.change_ring(K).points_at_infinity()
[(1 : omega : 0), (1 : -omega - 1 : 0)]

sage: _.<x> = GF(103)[]
sage: H = HyperellipticCurve(x^5 + 1)
sage: H.points_at_infinity()
[(1 : 0 : 0)]
sage: H = HyperellipticCurve(x^6 + 1)
sage: H.points_at_infinity()
[(1 : 1 : 0), (1 : 102 : 0)]
sage: H = HyperellipticCurve(3*x^6 + 1)
sage: H.points_at_infinity()
[]
[Python]
>>> from sage.all import *
>>> _ = GF(Integer(103))['x']; (x,) = _._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(5) + Integer(1))
>>> H.points_at_infinity()
[(1 : 0 : 0)]
>>> H = HyperellipticCurve(x**Integer(6) + Integer(1))
>>> H.points_at_infinity()
[(1 : 1 : 0), (1 : 102 : 0)]
>>> H = HyperellipticCurve(Integer(3)*x**Integer(6) + Integer(1))
>>> H.points_at_infinity()
[]
polynomial_ring()[source]

Return the parent ring of the defining polynomials \(f, h\), of this hyperelliptic curve.

EXAMPLES:

sage: R.<x> = QQ[]
sage: H = HyperellipticCurve(x^7 + 3*x + 2)
sage: H.polynomial_ring()
Univariate Polynomial Ring in x over Rational Field

sage: # optional - sage.rings.padics
sage: K = Qp(7, 10)
sage: HK = H.change_ring(K)
sage: HK.polynomial_ring()
Univariate Polynomial Ring in x over 7-adic Field with capped relative precision 10
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(7) + Integer(3)*x + Integer(2))
>>> H.polynomial_ring()
Univariate Polynomial Ring in x over Rational Field

>>> # optional - sage.rings.padics
>>> K = Qp(Integer(7), Integer(10))
>>> HK = H.change_ring(K)
>>> HK.polynomial_ring()
Univariate Polynomial Ring in x over 7-adic Field with capped relative precision 10
projective_curve()[source]

Return a (singular) plane model of the hyperelliptic curve self.

TODO: renaming to plane_model ?

EXAMPLES:

We consider the hyperelliptic curve with affine equation \(y^2 = x^5 + x\):

sage: R.<x> = FiniteField(11)[]
sage: H = HyperellipticCurve(x^6 + 2)
sage: C = H.projective_curve(); C
Projective Plane Curve over Finite Field of size 11 defined by -x^6 + y^2*z^4 - 2*z^6
>>> from sage.all import *
>>> R = FiniteField(Integer(11))['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(6) + Integer(2))
>>> C = H.projective_curve(); C
Projective Plane Curve over Finite Field of size 11 defined by -x^6 + y^2*z^4 - 2*z^6

Note that the projective coordinates of points on \(H\) and their images in \(C\) are in general not the same:

sage: P = H.point([9,4,2])
sage: Q = C.point([9,4,2])
Traceback (most recent call last):
...
TypeError: Coordinates [10, 2, 1] do not define a point on Projective Plane Curve over Finite Field of size 11 defined by -x^6 + y^2*z^4 - 2*z^6
[Python]
>>> from sage.all import *
>>> P = H.point([Integer(9),Integer(4),Integer(2)])
>>> Q = C.point([Integer(9),Integer(4),Integer(2)])
Traceback (most recent call last):
...
TypeError: Coordinates [10, 2, 1] do not define a point on Projective Plane Curve over Finite Field of size 11 defined by -x^6 + y^2*z^4 - 2*z^6

However, the affine coordinates coincide:

sage: H.affine_coordinates(P)
(10, 6)
sage: Q = C.point([10,6,1])
>>> from sage.all import *
>>> H.affine_coordinates(P)
(10, 6)
>>> Q = C.point([Integer(10),Integer(6),Integer(1)])

The model \(C\) has one singular point at infinity, while \(H\) is non-singular and has two points at infinity.

sage: H.points_at_infinity() [(1 : 1 : 0), (1 : 10 : 0)] sage: [P for P in C.rational_points() if P[2]==0] [(0 : 1 : 0)]

rational_points(**kwds)[source]

Find rational points on the hyperelliptic curve. Arguments are passed on to sage.schemes.generic.algebraic_scheme.rational_points().

ALGORITHM:

We use points_at_infinity() to compute the points at infinity, and sage.schemes.generic.algebraic_scheme.rational_points() on this curve’s projective_curve() for the affine points.

EXAMPLES:

For the LMFDB genus 2 curve 932.a.3728.1:

sage: R.<x> = PolynomialRing(QQ)
sage: C = HyperellipticCurve(R([0, -1, 1, 0, 1, -2, 1]), R([1]))
sage: C.rational_points(bound=8)
[(1 : 1 : 0), (1 : -1 : 0), (-1 : -3 : 1), (-1 : 2 : 1), (0 : -1 : 1),
 (0 : 0 : 1), (1/2 : -5/8 : 1), (1/2 : -3/8 : 1), (1 : -1 : 1), (1 : 0 : 1)]
>>> from sage.all import *
>>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1)
>>> C = HyperellipticCurve(R([Integer(0), -Integer(1), Integer(1), Integer(0), Integer(1), -Integer(2), Integer(1)]), R([Integer(1)]))
>>> C.rational_points(bound=Integer(8))
[(1 : 1 : 0), (1 : -1 : 0), (-1 : -3 : 1), (-1 : 2 : 1), (0 : -1 : 1),
 (0 : 0 : 1), (1/2 : -5/8 : 1), (1/2 : -3/8 : 1), (1 : -1 : 1), (1 : 0 : 1)]

Check that Issue #29509 is fixed for the LMFDB genus 2 curve 169.a.169.1:

   sage: C = HyperellipticCurve(R([0, 0, 0, 0, 1, 1]), R([1, 1, 0, 1]))
   sage: C.rational_points(bound=10) # long time (6s)
   [(1 : 0 : 0), (1 : -1 : 0), (-1 : 0 : 1), (-1 : 1 : 1), (0 : -1 : 1), (0 : 0 : 1)]

An example over a number field::

   sage: R.<x> = PolynomialRing(QuadraticField(2))                             # needs sage.rings.number_field
   sage: C = HyperellipticCurve(R([1, 0, 0, 0, 0, 1]))              # needs sage.rings.number_field
   sage: C.rational_points(bound=2)
   [(1 : 0 : 0), (-1 : 0 : 1), (0 : -1 : 1), (0 : 1 : 1), (1 : -a : 1), (1 : a : 1)]

   sage: R.<x> = QQ[]
   sage: H = HyperellipticCurve(x^8 + 33)
   sage: H.rational_points(bound=20)                                           # long time (6s)
   [(1 : 1 : 0), (1 : -1 : 0), (-2 : -17 : 1), (-2 : 17 : 1), (2 : -17 : 1), (2 : 17 : 1)]
rational_weierstrass_points()[source]

Return the rational Weierstrass points of the hyperelliptic curve. These are the points that are fixed by the hyperelliptic involution.

EXAMPLES:

When \(h(x)\) is zero, then the Weierstrass points are the points with \(y\)-coordinate equal to zero:

sage: R.<x> = QQ[]
sage: H = HyperellipticCurve(x^5 - x)
sage: H.rational_weierstrass_points()
[(1 : 0 : 0), (1 : 0 : 1), (0 : 0 : 1), (-1 : 0 : 1)]
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(5) - x)
>>> H.rational_weierstrass_points()
[(1 : 0 : 0), (1 : 0 : 1), (0 : 0 : 1), (-1 : 0 : 1)]

The function also handles the case with \(h(x)\) nonzero:

sage: R.<x> = FiniteField(17)[]
sage: H = HyperellipticCurve(x^6 + 2, x^2 + 1)
sage: H.rational_weierstrass_points()
[(15 : 6 : 1), (2 : 6 : 1)]
sage: P = H.point([15,6,1])
sage: H.is_weierstrass_point(P)
True
[Python]
>>> from sage.all import *
>>> R = FiniteField(Integer(17))['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(6) + Integer(2), x**Integer(2) + Integer(1))
>>> H.rational_weierstrass_points()
[(15 : 6 : 1), (2 : 6 : 1)]
>>> P = H.point([Integer(15),Integer(6),Integer(1)])
>>> H.is_weierstrass_point(P)
True
roots_at_infinity()[source]

Compute the roots of: \(Y^2 + h_{g+1} Y - f_{2g+2} = 0\).

When the curve is ramified, we expect one root. When the curve is split we expect two roots. When the curve is inert we expect zero roots.

EXAMPLES:

sage: R.<x> = PolynomialRing(QQ)
sage: H = HyperellipticCurve(x^7 + 1)
sage: H.roots_at_infinity()
[0]

sage: H = HyperellipticCurve(x^8 + 1)
sage: H.roots_at_infinity()
[1, -1]

sage: H = HyperellipticCurve(-x^8 + 1)
sage: H.roots_at_infinity()
[]
>>> from sage.all import *
>>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(7) + Integer(1))
>>> H.roots_at_infinity()
[0]

>>> H = HyperellipticCurve(x**Integer(8) + Integer(1))
>>> H.roots_at_infinity()
[1, -1]

>>> H = HyperellipticCurve(-x**Integer(8) + Integer(1))
>>> H.roots_at_infinity()
[]
set_distinguished_point(P0)[source]

Change the distinguished point of the hyperelliptic curve to P0.

EXAMPLES:

sage: R.<x> = PolynomialRing(QQ)
sage: f = x^6 - 6*x^4 + x^2 + 28
sage: H = HyperellipticCurve(f)
sage: H.distinguished_point()
(1 : 1 : 0)
sage: P = H(2,0)
sage: H.set_distinguished_point(P)
sage: H.distinguished_point()
(2 : 0 : 1)
>>> from sage.all import *
>>> R = PolynomialRing(QQ, names=('x',)); (x,) = R._first_ngens(1)
>>> f = x**Integer(6) - Integer(6)*x**Integer(4) + x**Integer(2) + Integer(28)
>>> H = HyperellipticCurve(f)
>>> H.distinguished_point()
(1 : 1 : 0)
>>> P = H(Integer(2),Integer(0))
>>> H.set_distinguished_point(P)
>>> H.distinguished_point()
(2 : 0 : 1)
split_G_plus_minus()[source]

Return \(G^{\pm(x)}\) for curves in the split degree model.

This is used for Cantor composition with points at infinity when performing arithmetic on the Jacobian. See Definition 4 in [GHM2008].

See also

cantor_compose_at_infinity()

EXAMPLES:

sage: R.<x> = QQ[]
sage: H = HyperellipticCurve(x^6 + x^4 + 1)
sage: H.split_G_plus_minus()
(x^3 + 1/2*x, -x^3 - 1/2*x)
sage: H = HyperellipticCurve(4*x^6 + x^4 + 1)
sage: H.split_G_plus_minus()
(2*x^3 + 1/4*x, -2*x^3 - 1/4*x)
>>> from sage.all import *
>>> R = QQ['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(6) + x**Integer(4) + Integer(1))
>>> H.split_G_plus_minus()
(x^3 + 1/2*x, -x^3 - 1/2*x)
>>> H = HyperellipticCurve(Integer(4)*x**Integer(6) + x**Integer(4) + Integer(1))
>>> H.split_G_plus_minus()
(2*x^3 + 1/4*x, -2*x^3 - 1/4*x)

The function is only defined for hyperelliptic curves with two rational points at infinity:

sage: H = HyperellipticCurve(2*x^6 + x^4 + 1)
sage: H.is_split()
False
sage: H.split_G_plus_minus()
Traceback (most recent call last):
...
ValueError: hyperelliptic curve does not have the split model
[Python]
>>> from sage.all import *
>>> H = HyperellipticCurve(Integer(2)*x**Integer(6) + x**Integer(4) + Integer(1))
>>> H.is_split()
False
>>> H.split_G_plus_minus()
Traceback (most recent call last):
...
ValueError: hyperelliptic curve does not have the split model
weights()[source]

Return the weights of the weighted projective space this hyperelliptic curve lives in, i.e. \((1, g + 1, 1)\), where \(g\) is the genus of the curve.

EXAMPLES:

sage: R.<x> = GF(13)[]
sage: H = HyperellipticCurve(x^5 - 1)
sage: H.weights()
(1, 3, 1)

sage: H = HyperellipticCurve(x^9 - 1)
sage: H.weights()
(1, 5, 1)
>>> from sage.all import *
>>> R = GF(Integer(13))['x']; (x,) = R._first_ngens(1)
>>> H = HyperellipticCurve(x**Integer(5) - Integer(1))
>>> H.weights()
(1, 3, 1)

>>> H = HyperellipticCurve(x**Integer(9) - Integer(1))
>>> H.weights()
(1, 5, 1)