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
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

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
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
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

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

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
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
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)
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)
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
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
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
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)
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
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
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
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
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
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
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

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
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

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

sage: H.is_x_coord(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

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

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

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

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)

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

sage: D1 == J(x^2 + x, -2*x, 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

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)

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)

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)

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

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)

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

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):
...
ValueError: unable to perform arithmetic for inert models of odd genus
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)]

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

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

sage: H.lift_x(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)

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)

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)]

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)
[]
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))

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))

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))

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)

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

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)

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

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

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))

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

sage: f,_ = H.hyperelliptic_polynomials()
sage: (yt^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

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)

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

sage: f,_ = H.hyperelliptic_polynomials()
sage: (yt^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

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
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

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

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
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)]
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()
[]
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
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

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

However, the affine coordinates coincide:

sage: H.affine_coordinates(P)
(10, 6)
sage: Q = C.point([10,6,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)]

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)]

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
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()
[]
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)
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)

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
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)