Skip to content

Commit 6202836

Browse files
committed
Implement construction of hyperelliptic curves from defining equation
1 parent 94fe540 commit 6202836

File tree

2 files changed

+77
-35
lines changed

2 files changed

+77
-35
lines changed

src/sage/schemes/elliptic_curves/constructor.py

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ class EllipticCurveFactory(UniqueFactory):
161161
162162
sage: R.<x,y> = GF(5)[]
163163
sage: EllipticCurve(x^3 + x^2 + 2 - y^2 - y*x)
164-
Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 2 over Finite Field of size 5
164+
Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 2 over Finite Field of size 5
165165
166166
We can also create elliptic curves by giving a smooth plane cubic with a rational point::
167167
@@ -579,41 +579,19 @@ def coefficients_from_Weierstrass_polynomial(f):
579579
sage: R.<w,z> = QQ[]
580580
sage: coefficients_from_Weierstrass_polynomial(-w^2 + z^3 + 1)
581581
[0, 0, 0, 0, 1]
582+
sage: R.<u,v> = GF(13)[]
583+
sage: EllipticCurve(u^2 + 2*v*u + 3*u - (v^3 + 4*v^2 + 5*v + 6)) # indirect doctest
584+
Elliptic Curve defined by y^2 + 2*x*y + 3*y = x^3 + 4*x^2 + 5*x + 6 over Finite Field of size 13
582585
"""
583-
R = f.parent()
584-
cubic_variables = [ x for x in R.gens() if f.degree(x) == 3 ]
585-
quadratic_variables = [ y for y in R.gens() if f.degree(y) == 2 ]
586-
try:
587-
x = cubic_variables[0]
588-
y = quadratic_variables[0]
589-
except IndexError:
586+
from sage.schemes.hyperelliptic_curves.constructor import _parse_multivariate_defining_equation
587+
f, h = _parse_multivariate_defining_equation(f)
588+
# OUTPUT: tuple (f, h), each of them given as a list of coefficients.
589+
if len(f) != 4 or len(h) > 2:
590590
raise ValueError('polynomial is not in long Weierstrass form')
591-
592-
a1 = a2 = a3 = a4 = a6 = 0
593-
x3 = y2 = None
594-
for coeff, mon in f:
595-
if mon == x**3:
596-
x3 = coeff
597-
elif mon == x**2:
598-
a2 = coeff
599-
elif mon == x:
600-
a4 = coeff
601-
elif mon == 1:
602-
a6 = coeff
603-
elif mon == y**2:
604-
y2 = -coeff
605-
elif mon == x*y:
606-
a1 = -coeff
607-
elif mon == y:
608-
a3 = -coeff
609-
else:
610-
raise ValueError('polynomial is not in long Weierstrass form')
611-
612-
if x3 != y2:
591+
if not f[3].is_one():
613592
raise ValueError('the coefficient of x^3 and -y^2 must be the same')
614-
elif x3 != 1:
615-
a1, a2, a3, a4, a6 = a1/x3, a2/x3, a3/x3, a4/x3, a6/x3
616-
return [a1, a2, a3, a4, a6]
593+
h += [0] * (2 - len(h))
594+
return [h[1], f[2], h[0], f[1], f[0]]
617595

618596

619597
def EllipticCurve_from_c4c6(c4, c6):
@@ -625,7 +603,7 @@ def EllipticCurve_from_c4c6(c4, c6):
625603
626604
sage: E = EllipticCurve_from_c4c6(17, -2005)
627605
sage: E
628-
Elliptic Curve defined by y^2 = x^3 - 17/48*x + 2005/864 over Rational Field
606+
Elliptic Curve defined by y^2 = x^3 - 17/48*x + 2005/864 over Rational Field
629607
sage: E.c_invariants()
630608
(17, -2005)
631609
"""

src/sage/schemes/hyperelliptic_curves/constructor.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,54 @@
2929
from sage.structure.dynamic_class import dynamic_class
3030

3131

32-
def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True):
32+
def _parse_multivariate_defining_equation(g):
33+
"""
34+
Parse a defining equation for a hyperelliptic curve.
35+
The input `g` should have the form `g(x, y) = y^2 + h(x) y - f(x)`,
36+
or a constant multiple of that.
37+
38+
OUTPUT: tuple (f, h), each of them given as a list of coefficients.
39+
"""
40+
from sage.rings.polynomial.multi_polynomial import MPolynomial
41+
if not isinstance(g, MPolynomial):
42+
raise ValueError("must be a multivariate polynomial")
43+
44+
variables = g.variables()
45+
if len(variables) != 2:
46+
raise ValueError("must be a polynomial in two variables")
47+
48+
y, x = sorted(variables, key=g.degree)
49+
if g.degree(y) != 2:
50+
raise ValueError("must be a polynomial of degree 2 in a variable")
51+
52+
f = []
53+
h = []
54+
for k, v in g:
55+
dx = v.degree(x)
56+
dy = v.degree(y)
57+
if dy == 2:
58+
if dx != 0:
59+
raise ValueError(f"cannot have a term y*x^{dx}")
60+
y2 = k
61+
elif dy == 1:
62+
while len(h) <= dx:
63+
h.append(0)
64+
h[dx] = k
65+
else:
66+
assert dy == 0
67+
while len(f) <= dx:
68+
f.append(0)
69+
f[dx] = -k
70+
71+
if not y2.is_one():
72+
y2_inv = y2.inverse_of_unit()
73+
f = [c * y2_inv for c in f]
74+
h = [c * y2_inv for c in h]
75+
76+
return f, h
77+
78+
79+
def HyperellipticCurve(f, h=None, names=None, PP=None, check_squarefree=True):
3380
r"""
3481
Return the hyperelliptic curve `y^2 + h y = f`, for
3582
univariate polynomials `h` and `f`. If `h`
@@ -76,6 +123,12 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True):
76123
Hyperelliptic Curve over Finite Field in a of size 3^2
77124
defined by y^2 + (x + a)*y = x^3 + x + 2
78125
126+
Construct from defining polynomial::
127+
128+
sage: R.<x,y> = QQ[]
129+
sage: HyperellipticCurve(y^2 + 3*x^2*y - (x^5 + x + 1))
130+
Hyperelliptic Curve over Rational Field defined by y^2 + 3*x^2*y = x^5 + x + 1
131+
79132
Characteristic two::
80133
81134
sage: # needs sage.rings.finite_rings
@@ -200,6 +253,17 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True):
200253
"""
201254
# F is the discriminant; use this for the type check
202255
# rather than f and h, one of which might be constant.
256+
if h is None:
257+
from sage.rings.polynomial.multi_polynomial import MPolynomial
258+
if isinstance(f, MPolynomial) and len(f.parent().gens()) == 2:
259+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
260+
from sage.structure.element import get_coercion_model
261+
P = PolynomialRing(f.base_ring(), 'x')
262+
f, h = _parse_multivariate_defining_equation(f)
263+
f, h = P(f), P(h)
264+
else:
265+
h = 0
266+
203267
F = h**2 + 4 * f
204268
if not isinstance(F, Polynomial):
205269
raise TypeError(f"arguments f = {f} and h = {h} must be polynomials")

0 commit comments

Comments
 (0)