# change of variables from quartic to weierstrass

Hi. I have been sitting down for the past 1 week trying to get this code to work with no hope. Can someone help me with the change of variables here please. I have the quartic curve v^2 = u^4-2*u^3+5*u^2+8*u+4 which I transform to an elliptic curve of the form y^2 + a1*x*y + a3*y = x^3 + a2*x^2 + a4*x + a6. The code is given by :

var( 'u,v,a,b,c,q,x,y,d' );
f = a*u^4 + b*u^3 + c*u^2 + d*u + q^2
# we want to find an algebraic passage from u, v and the quartic
# v^2 = f
# to a Weierstass equation in two new variables x, y
x = (2*q*(v+q) + d*u)/u^2
y = ((2*q)^3*(v+q) + (2*q)^2*( d*u + c*u^2 ) - d^2*u^2)/((2*q)*u^3)
# inverse transformation:
u = ((2*q)*(x+c)-d^2/q)/y
v = -q + (u*(u*x-d))/(2*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/(2*q)))^2
a3 = b*(2*q)
a4 = -a*(2*q)^2
a6 = a2*a4
((y^2 + a1*x*y + a3*y) - (x^3 + a2*x^2 + a4*x + a6)).factor()
def passageQuarticToWeierstrass( a, b, c, d, q, field=QQ ):
"""implement the standard formulas
"""
a1, a2, a3, a4 = d/q, c - ((d/(2*q)))^2, b*(2*q), -a*(2*q)^2
a6 = a2 * a4
print ( a1, a2, a3, a4, a6 )
return EllipticCurve(field,(a1, a2, a3, a4, a6))
a, b, c, d, q = 1,-2,5,8,2
E = passageQuarticToWeierstrass( a, b, c, d, q );E


The output yield :

Elliptic Curve defined by E : y^2 + 4*x*y - 8*y = x^3 + x^2 - 16*x - 16 over Rational Field.


Then I transform E into a short Weierstrass equation which should yield : E' : y^2 = x^3 -3267*x +45630 with the corresponding change of variable. This is what I tried, but did not quite worked. (slightly different numerator expression but correct denominators for u and v).

reset('x')
reset('y')
var('x,y,Y')
a, b, c, d, q = 1,-2,5,8,2 #coefficients of quartic v^2
a1, a2, a3, a4, a6 = 4, 1, -8, -16, -16 #coefficients of elliptic curve E
E=y^2 + 4*x*y - 8*y -(x^3 + x^2 - 16*x - 16)
F=E.subs({y:y-(a1*x+a3)/2}) #eliminates xy and y term on the LHS of E
eq3=eq2.subs({x:x-((a2+1/4*(a1)^2)/3)}) #eliminates the x^2 term from the RHS to give E of the form y^2 = x^3 +Ax +B
eq5=eq4.subs({x:(1/3^2)*x})
eq6=eq5*729;eq6
u=((2*q)*(x+c)-(d^2/q))/y #the inverse transformation from from E to quartic
eq7=u.subs({y:y-(a1*x+a3)/2}).subs({x:x-((a2+1/4*(a1)^2)/3)})
eq8=eq7.subs({x : (x/3^2)}).subs({y:y/(3^3)});eq8
v = -q + (u*(u*x-d))/(2*q) #the inverse transformation from from E to quartic
eq9=v.subs({y:y-(a1*x+a3)/2}).subs({x:x-((a2+1/4*(a1)^2)/3)})
eq10=eq9.subs({x : (x/3^2)}).subs({y:y/(3^3)})
eq11=eq10.simplify_full()
eq12=eq11.subs({y^2:(x^3-3267*x+45630)});eq12


The output yield :

 -x^3 + 729*y^2 + 3267*x - 45630 #wrote this in the form:Y^2 = x^3 - 3267*x +45630  where Y=3^3*y
u = -12*(x - 42)/(6*x - y - 198)
v =  2*(x^3 - 162*x^2 + 6291*x + 108*y - 37962)/(x^3 + 36*x^2 - 12*(x - 33)*y - 5643*x + 84834)


The problem lies in the change of variable for u and v obtained. I tried substituting them back into the curves and they do not satisfy the equations. I suspect the glitch is in eq6 that is giving me the incorrect change of variable for u and v. Can someone help me throw in some suggestions. The reason why I am doing all this step by step is because I need to find the change of variable for u and v.

edit retag close merge delete

Sort by » oldest newest most voted

This post seems to be related to

Please always mention the source, when there is almost a copy+pasted version of existing code.

The following code tries to catch all needed ad-hoc passages in a homogenous structure.

For this, i have introduced the class W, where we can bind all needed coefficients.

First of all the code, than the comments:

class W( object ):
def __init__( self, a,b,c,d,q, Q, a1,a2,a3,a4,a6, A4,A6 ):
self.a, self.b, self.c, self.d, self.q = a, b, c, d, q
self.Q = Q
self.a1, self.a2, self.a3, self.a4, self.a6 = a1, a2, a3, a4, a6
self.A4, self.A6 = A4,A6
self.f = lambda x, y : y^2 - ( a*x^4 + b*x^3 + c*x^2 + d*x + q^2 )
self.g = lambda x, y : y^2 + a1*x*y + a3*y - ( x^3 + a2*x^2 + a4*x + a6 )
self.h = lambda x, y : y^2 - ( x^3 + A4*x + A6 )

# var( 'a,b,c,d,q' )
def getData( a,b,c,d,q ):
Q = 2*q

a1, a2, a3, a4 = d/q, c - ((d/(2*q)))^2, b*(2*q), -a*(2*q)^2
a6 = a2 * a4

A4 = a4 + a1*a3/2 - a1^4/48 - a1^2*a2/6 - a2^2/3
A6 = a1^6/864 + a1^4*a2/72 + a1^2*a2^2/18 - a1^3*a3/24 + 2/27*a2^3 - a1*a2*a3/6 - a1^2*a4/12 + a3^2/4 - a2*a4/3 + a6

w = W( a,b,c,d,q, Q, a1,a2,a3,a4,a6, A4,A6 )
return w

def Passage_uv_to_xy( uv, data ):
u, v = uv
c,d, q,Q = data.c, data.d, data.q, data.Q

x = ( Q*(v+q) + d*u ) / u^2
y = ( Q^2*(v+q) + Q*( d*u + c*u^2 ) - d^2*u^2/Q ) / u^3
return x,y

def Passage_xy_to_uv( xy, data ):
x, y = xy
c,d, q,Q = data.c, data.d, data.q, data.Q

U = ( Q*(x+c) - d^2/Q ) / y
V = -q + U*(U*x-d) / Q
return U,V

# var( 'a1,a2,a3,a4,a6' )
# use the above to test Y^2 - (X^3+A4*X+A6) == y^2+a1*x*y+a3*y - (x^3+a2*x^2+a4*x+a6) ...
# where var( 'x,y' ); X,Y = Passage_xy_to_XY( (x,y) )
# A4 = a4 + a1*a3/2 - a1^4/48 - a1^2*a2/6 - a2^2/3
# A6 = a1^6/864 + a1^4*a2/72 + a1^2*a2^2/18 - a1^3*a3/24 + 2/27*a2^3 - a1*a2*a3/6 - a1^2*a4/12 + a3^2/4 - a2*a4/3 + a6
# and associate a corresponding data...

def Passage_xy_to_XY( xy, data ):
x,y = xy
a1, a2, a3 = data.a1, data.a2, data.a3

X = x + (a2+a1^2/4)/3
Y = y + a1*x/2 + a3/2
return X,Y

def Passage_XY_to_xy( XY, data ):
X, Y = XY
a1, a2, a3 = data.a1, data.a2, data.a3

x = X - (a2+a1^2/4)/3
y = Y - a1*x/2 - a3/2
return x,y

# # # =================================================
# # # TESTS AND APPLICATION TO THE GIVEN CASE
var( 'u,v' )
var( 'a,b,c,d,q' )
data = getData( a,b,c,d,q )

u1, v1 = Passage_xy_to_uv( Passage_uv_to_xy( (u,v), data ), data )
print "Is u1=u ? %s" % bool( u1==u )
print "Is v1=v ? %s" % bool( v1==v )
print

var( 'x,y' )
x1, y1 = Passage_XY_to_xy( Passage_xy_to_XY( (x,y), data ), data )
print "Is x1=x ? %s" % bool( x1==x )
print "Is y1=y ? %s" % bool( y1==y )
print

var( 'u,v' )
X,Y = Passage_xy_to_XY( Passage_uv_to_xy( (u,v), data ), data )
print "YY - (XXX +A4*X + A6)  is %s" % ( (Y^2 - (X^3+A4*X+A6) ).factor() )
print

var( 'X,Y' )
U,V = Passage_xy_to_uv( Passage_XY_to_xy( (X,Y), data ), data )
print "U = %s" % U
print "V = %s" % V
print

# in the concrete case given:
data = getData( 1,-2,5,8,2 )
var( 'X,Y' )
U,V = Passage_xy_to_uv( Passage_XY_to_xy( (X,Y), data ), data )
print "U = %s" % U
print "V = %s" % V
print "f(U,V) = %s" % ( data.f(U,V).factor() )


This gives:

(u, v)
(a, b, c, d, q)
Is u1=u ? True
Is v1=v ? True

(x, y)
Is x1=x ? True
Is y1=y ? True

(u, v)
YY - (XXX +A4*X + A6)  is (4*c*q^2*u^2 + 8*q^4 + 4*d*q^2*u - d^2*u^2 + 8*q^3*v)*(a*u^4 + b*u^3 + c*u^2 + q^2 + d*u - v^2)/u^6

(X, Y)
U = -(4*(3*X + 2*c)*q - 3*d^2/q)/(6*b*q - 6*Y + (3*X - c)*d/q)
V = -q + 1/6*(4*(3*X + 2*c)*q - 3*d^2/q)*((4*(3*X + 2*c)*q - 3*d^2/q)*(3*X - c)/(6*b*q - 6*Y + (3*X - c)*d/q) + 3*d)/((6*b*q - 6*Y + (3*X - c)*d/q)*q)

(X, Y)
U = -4*(3*X - 2)/(6*X - 3*Y - 22)
V = 4/3*((3*X - 2)*(3*X - 5)/(6*X - 3*Y - 22) + 6)*(3*X - 2)/(6*X - 3*Y - 22) - 2
f(U,V) = 16/9*(27*X^3 - 27*Y^2 - 1089*X + 1690)*(3*X - 2)^3/(6*X - 3*Y - 22)^4


• The equalities u1==u and v1==v shows that the passages Passage_xy_to_uv and Passage_uv_to_xy are inverse to each other.
• The equalities x1==x and y1==y shows that the passages Passage_xy_to_XY and Passage_XY_to_xy are inverse to each other.
• The factor (a*u^4 + b*u^3 + c*u^2 + q^2 + d*u - v^2) in YY - (XXX +A4*X + A6) shows that if the pair $(u,v)$ satisfies "the quartic", than $(X,Y)$ satisfies $$Y^2 =X^3 +A_4X+A_6$$, with $A_4,A_6$ also captured in the instance data.
• Let now data be the "special data", obtained as data = getData( 1,-2,5,8,2 ). Then if we start with $(X,Y)$ on the curve with the equation

sage: data.h(X,Y)
-X^3 + Y^2 + 121/3*X - 1690/27
sage: data.h(X,Y)*27
-27*X^3 + 27*Y^2 + 1089*X - 1690

• then building $(U,V)$ from $(X,Y)$ satisfying $h=0$, we get the point $(U,V)$ satisfying $f(U,V)=0$, because of the factor (27*X^3 - 27*Y^2 - 1089*X + 1690).

• So for $(U,V)$ satisfying the equation of the elliptic curve $$Y^2 = X^3 - \frac{121}3X + \frac{1690}{27}\qquad(*)$$ the corresponding $(U,V)$ point has:

sage: U.factor()
-4*(3*X - 2)/(6*X - 3*Y - 22)
sage: V.factor()
2/3*(54*X^3 - 54*X^2 - 27*Y^2 - 324*Y - 964)/(6*X - 3*Y - 22)^2


I hope this helps to finally dissolve the puzzle. (In the given situation we have only to rescale $X,Y$ using corresponding powers of $3$, i.e. formally multiply $(*)$ with $3^6$ and group the new variables $3^3Y$ and $3^2X$, for the new equation.)

A final note: As in mathematics, it is always simpler to catch the idea when the shape of the text / of the code comes in a pleasant way. Please try to use (for the own sake) a better spacing and a more structural approach. In the posted code it was quite hard to find a Leitfaden, a red line...

more

@Dan fulea Thank you for your help explaining this to me. This is so useful in my calculation. After scaling, I manage to get the correct change of variable for u and v. And the best part is I see where I made a mistake. Thank you again.