The following is a solution that uses the Curve
constructor and the instances of the resulting class as a uniformizer, as a common room to work in.
The EllipticCurve
constructor produces very special instances, all methods are related to the very special structure of an elliptic curve over the one or other field type. There are so many methods! However, i could not find a curve
method passing from the elliptic curve to a "simple" curve. This would still not be enough for our purposes, the isogenies should also have a parallel method, translating them to the level of "simple" curves.
If there are some methods, that i've overlooked, then please adapt the code to make it simpler.
It helps me to have different letters for the polynomials defining different curves, so there will be x,y,z for the "C curve", CC
below, and there will be the upper case letters X,Y,Z for the "E(lliptic) curve", EC
below. These two instances are living in the proletariat of all "simple" curves. In order to get the isogeny, we must instantiate the aristocratic EE
, an elliptic curve with all its decorations. After this presentation of the actors, here's the code:
K = GF(23)
d = K(2)
a = d+2
b = 4*(d^2+d+1) / 3
R.<x,y,z> = PolynomialRing( K, 3 )
S.<X,Y,Z> = PolynomialRing( K, 3 )
def CP( x,y,z ): return x^3 + y^3 + z^3 - 3*d*x*y*z
def EP( X,Y,Z ): return Y^2*Z - X^3 - (a*X+b*Z)^2*Z
CC = Curve( CP( x,y,z ) ) # domain curve
EC = Curve( EP( X,Y,Z ) )
EE = EllipticCurve( EP(x,y,1) ) # codomain curve
m = b
n = 4*(d^3 -1)/3
X1 = m*(x+y+z)
Y1 = n*(z-y)
Z1 = -z-y-d*x
print "A check in the algebraic geometry:"
print ( "EP( X1, Y1, Z1 ) / CP( x,y,z ) = %s"
% ( EP( X1, Y1, Z1 ) / CP( x,y,z ) ) )
print "This defines a morphism f..."
Q = EE( 2, 9, 1 ) # a point on E
G = EE.isogeny( Q ) # isogeny for Q
Gx, Gy = G.rational_maps()
Gx_homogenous = Gx.subs( { x: X/Z, y: Y/Z } )
Gy_homogenous = Gy.subs( { x: X/Z, y: Y/Z } )
Z2 = lcm( Gx_homogenous.denominator() ,
Gy_homogenous.denominator() )
X2 = S( Gx_homogenous*Z2 )
Y2 = S( Gy_homogenous*Z2 )
f = CC.Hom( EC )( [ X1, Y1, Z1 ] ) # map from CC to EC
g = EC.Hom( EC )( [ X2, Y2, Z2 ] ) # map from CC to EC
gf = g*f
# print gf # polynomials of degree 27 are shown, better not here...
print ( "The composition gf has:\n domain = %s\ncodomain = %s\n degree = %s"
% ( gf.domain(), gf.codomain(), gf.degree() ) )
The prints are giving:
A check in the algebraic geometry:
EP( X1, Y1, Z1 ) / CP( x,y,z ) = -2
This defines a morphism f...
(thanks for the morphism!)
and the print confirming the successful composition is...
The composition gf has:
domain = Projective Plane Curve over Finite Field of size 23
defined by x^3 + y^3 - 6*x*y*z + z^3
codomain = Projective Plane Curve over Finite Field of size 23
defined by -X^3 + 7*X^2*Z + Y^2*Z + 2*X*Z^2 + 10*Z^3
degree = 27
(...the message was manually rearranged to fit in the line, not in the margin.)
The print gf
would fill the screen, since there are polynomials of degree $27$ showing up.
Please provide code. (In a simple(r) situation, that still capures the problem.)
This is not only fixing the framework and the problem, but also gives a quick copy+paste starting point for potential helpers.
Thanks for the code! Sometimes, the code not only defines a special situation, but also shows what can be done with the objects, this time i learned to pass in an other way from the cubic equation to the Weierstrass form.