To use the sage libraries, we bring the quartic into the Weierstraß form.
First of all, we need a rational point at least on the curve. (I suppose we are working over Q.)
Let us search for a "simple integer" that makes the R.H.S. of the given equation, here using variables ξ,v
E(ξ,v) : y2=−2500ξ4+451976ξ2−2500
sage: [xi for xi in [0..200] if (-2500*xi^4 + 451976*xi^2 - 2500).is_square()]
[5]
OK, we are lucky, and take the 5, then slightly change the equation for (E) using the substitution ξ=u+5, u=ξ−5, so that u=0 is leading to a point (0,3120)=(0,q) on the transformed curve:
$$
E(u,v)\ :\ v^2 = -2500u^4 + 50000u^3 + 76976u^2 - 3269760u + \underbrace{9734400}_{q^2}\ .
$$
Code finding this equation:
sage: var('u');
sage: def f(xi):
....: return -2500*xi^4 + 451976*xi^2 - 2500
....:
sage: f(u+5).factor()
-4*(25*u^2 + 588*u + 2340)*(25*u^2 - 88*u - 1040)
sage: f(u+5).expand()
-2500*u^4 - 50000*u^3 + 76976*u^2 + 3269760*u + 9734400
sage: sqrt(9734400)
3120
Now we proceed as in
[Ian Conell, Elliptic Curves Hanbook, page 105, Quartic to Weierstrass] . (Wonderful exposition.)
Consider the substitutions that apply in the general situation of a quartic with a rational point (without loss of generality moved in the position (0,q)), given by v2=au4+bu3+cu2+du+q2:
x=(Q(v+q)+du)/u2 ,
y=(Q2(v+q)+Q(cu2+du)−d2u2/Q)/u3 .
See also
https://ask.sagemath.org/question/36637/change-of-variable-from-hyperellictic-curve-to-weierstrass-form/
https://ask.sagemath.org/question/37478/transform-quartic-to-weierstrass/
for other examples.
Then the following code finds the cubic:
var( 'u,v' );
a, b, c, d, q = -2500, -50000, 76976, 3269760, 3120
Q = 2*q
def f(u):
return a*u^4 + b*u^3 + c*u^2 + d*u + q^2
x = ( Q*(v+q) + d*u ) / u^2
y = ( Q^3*(v+q) + Q^2*( d*u + c*u^2 ) - d^2*u^2 ) / Q / u^3
# inverse transformation:
# u = ( Q*(x+c) - d^2/Q ) / y
# v = -q + u*(u*x-d)/Q
# one can easily define rational functions (u,v) -> (x,y) and (x,y) -> (u,v)
# to be used in the concrete situation
a1 = d/q
a2 = c - (d/Q)^2
a3 = b*Q
a4 = -a*Q^2
a6 = a2*a4
( ( y^2 + a1*x*y + a3*y ) - ( x^3 + a2*x^2 + a4*x + a6 ) ) . factor()
The above gives:
80990208000
*(2500*u^4 + 50000*u^3 - 76976*u^2 + v^2 - 3269760*u - 9734400)
*(95*u^2 - 1572*u - 3*v - 9360)/u^6
(The result was manually broken to fit somehow in shorter lines.) One factor corresponds to the equation of E(u,v) after using the birational transformations mentioned in the code. Now we consider the corresponding curve, and ask for rank, and generator(s).
E = EllipticCurve(QQ, [a1, a2, a3, a4, a6])
print(f"E is the elliptic curve:\n{E}")
print(f"E has rank {E.rank()}")
P = E.gens()[0]
print(f"Generator: P = {P.xy()}")
We obtain (result manually broken again):
E is the elliptic curve:
Elliptic Curve defined by
y^2 + 1048*x*y - 312000000*y = x^3 - 197600*x^2 + 97344000000*x - 19235174400000000
over Rational Field
E has rank 1
Generator: P = (4798560, 8222323200)
It remains to bring this generator back in the (u,v) then (ξ,v) word.
x, y = P.xy()
u = ( Q*(x+c) - d^2/Q ) / y
v = -q + u*(u*x-d)/Q
xi = u + 5
print(f"(xi, v) = ({xi}, {v})")
We get:
(xi, v) = (1537/181, 145001328/32761)
Well, this is an "ugly" point... To get simpler points, we many try...
points = []
for n in [-5..-1] + [1..5]:
for T in E.torsion_points():
R = n*P + T
x, y = R.xy()
u = ( Q*(x+c) - d^2/Q ) / y
v = -q + u*(u*x-d)/Q
xi = u + 5
points.append((xi, v))
points.sort(key=lambda point: len(str(point)))
for point in points[:8]:
print(point)
But in the list there are no really simpler points. Here is the list, reminding us that the given equation was reciprocal on the R.H.S. :
(1537/181, 145001328/32761)
(-1537/181, 145001328/32761)
(1537/181, -145001328/32761)
(181/1537, 145001328/2362369)
(-1537/181, -145001328/32761)
(-181/1537, 145001328/2362369)
(181/1537, -145001328/2362369)
(3281/9125, 787407504/3330625)
Let us check that the first point is on the given curve:
def p(xi, v):
return v^2 - ( -2500*xi^4 + 451976*xi^2 - 2500 )
print(p(1537/181, 145001328/32761))
Yes, we obtain a clean zero.