def sigma(self, prec=10): """ EXAMPLES:: sage: E = EllipticCurve('14a') sage: F = E.formal_group() sage: F.sigma(5) t + 1/2*t^2 + (1/2*c + 1/3)*t^3 + (3/4*c + 3/4)*t^4 + O(t^5) """ a1,a2,a3,a4,a6 = self.curve().ainvs() k = self.curve().base_ring() fl = self.log(prec) R = rings.PolynomialRing(k,'c'); c = R.gen() F = fl.reverse() S = rings.LaurentSeriesRing(R,'z') c = S(c) z = S.gen() F = F(z + O(z**prec)) wp = self.x()(F) e2 = 12*c - a1**2 - 4*a2 g = (1/z**2 - wp + e2/12).power_series() h = g.integral().integral() sigma_of_z = z.power_series() * h.exp() T = rings.PowerSeriesRing(R,'t') fl = fl(T.gen()+O(T.gen()**prec)) sigma_of_t = sigma_of_z(fl) return sigma_of_t
def EllipticCurve_from_cubic(F, P, morphism=True): r""" Construct an elliptic curve from a ternary cubic with a rational point. If you just want the Weierstrass form and are not interested in the morphism then it is easier to use :func:`~sage.schemes.elliptic_curves.jacobian.Jacobian` instead. This will construct the same elliptic curve but you don't have to supply the point ``P``. INPUT: - ``F`` -- a homogeneous cubic in three variables with rational coefficients, as a polynomial ring element, defining a smooth plane cubic curve. - ``P`` -- a 3-tuple `(x,y,z)` defining a projective point on the curve `F=0`. Need not be a flex, but see caveat on output. - ``morphism`` -- boolean (default: ``True``). Whether to return the morphism or just the elliptic curve. OUTPUT: An elliptic curve in long Weierstrass form isomorphic to the curve `F=0`. If ``morphism=True`` is passed, then a birational equivalence between F and the Weierstrass curve is returned. If the point happens to be a flex, then this is an isomorphism. EXAMPLES: First we find that the Fermat cubic is isomorphic to the curve with Cremona label 27a1:: sage: R.<x,y,z> = QQ[] sage: cubic = x^3+y^3+z^3 sage: P = [1,-1,0] sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 + 2*x*y + 1/3*y = x^3 - x^2 - 1/3*x - 1/27 over Rational Field sage: E.cremona_label() '27a1' sage: EllipticCurve_from_cubic(cubic, [0,1,-1], morphism=False).cremona_label() '27a1' sage: EllipticCurve_from_cubic(cubic, [1,0,-1], morphism=False).cremona_label() '27a1' Next we find the minimal model and conductor of the Jacobian of the Selmer curve:: sage: R.<a,b,c> = QQ[] sage: cubic = a^3+b^3+60*c^3 sage: P = [1,-1,0] sage: E = EllipticCurve_from_cubic(cubic, P, morphism=False); E Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field sage: E.minimal_model() Elliptic Curve defined by y^2 = x^3 - 24300 over Rational Field sage: E.conductor() 24300 We can also get the birational equivalence to and from the Weierstrass form. We start with an example where ``P`` is a flex and the equivalence is an isomorphism:: sage: f = EllipticCurve_from_cubic(cubic, P, morphism=True) sage: f Scheme morphism: From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + b^3 + 60*c^3 To: Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field Defn: Defined on coordinates by sending (a : b : c) to (-c : -b + c : 1/20*a + 1/20*b) sage: finv = f.inverse(); finv Scheme morphism: From: Elliptic Curve defined by y^2 + 2*x*y + 20*y = x^3 - x^2 - 20*x - 400/3 over Rational Field To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + b^3 + 60*c^3 Defn: Defined on coordinates by sending (x : y : z) to (x + y + 20*z : -x - y : -x) We verify that `f` maps the chosen point `P=(1,-1,0)` on the cubic to the origin of the elliptic curve:: sage: f([1,-1,0]) (0 : 1 : 0) sage: finv([0,1,0]) (-1 : 1 : 0) To verify the output, we plug in the polynomials to check that this indeed transforms the cubic into Weierstrass form:: sage: cubic(finv.defining_polynomials()) * finv.post_rescaling() -x^3 + x^2*z + 2*x*y*z + y^2*z + 20*x*z^2 + 20*y*z^2 + 400/3*z^3 sage: E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling() a^3 + b^3 + 60*c^3 If the point is not a flex then the cubic can not be transformed to a Weierstrass equation by a linear transformation. The general birational transformation is quadratic:: sage: cubic = a^3+7*b^3+64*c^3 sage: P = [2,2,-1] sage: f = EllipticCurve_from_cubic(cubic, P, morphism=True) sage: E = f.codomain(); E Elliptic Curve defined by y^2 - 722*x*y - 21870000*y = x^3 + 23579*x^2 over Rational Field sage: E.minimal_model() Elliptic Curve defined by y^2 + y = x^3 - 331 over Rational Field sage: f Scheme morphism: From: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + 7*b^3 + 64*c^3 To: Elliptic Curve defined by y^2 - 722*x*y - 21870000*y = x^3 + 23579*x^2 over Rational Field Defn: Defined on coordinates by sending (a : b : c) to (-5/112896*a^2 - 17/40320*a*b - 1/1280*b^2 - 29/35280*a*c - 13/5040*b*c - 4/2205*c^2 : -4055/112896*a^2 - 4787/40320*a*b - 91/1280*b^2 - 7769/35280*a*c - 1993/5040*b*c - 724/2205*c^2 : 1/4572288000*a^2 + 1/326592000*a*b + 1/93312000*b^2 + 1/142884000*a*c + 1/20412000*b*c + 1/17860500*c^2) sage: finv = f.inverse(); finv Scheme morphism: From: Elliptic Curve defined by y^2 - 722*x*y - 21870000*y = x^3 + 23579*x^2 over Rational Field To: Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: a^3 + 7*b^3 + 64*c^3 Defn: Defined on coordinates by sending (x : y : z) to (2*x^2 + 227700*x*z - 900*y*z : 2*x^2 - 32940*x*z + 540*y*z : -x^2 - 56520*x*z - 180*y*z) sage: cubic(finv.defining_polynomials()) * finv.post_rescaling() -x^3 - 23579*x^2*z - 722*x*y*z + y^2*z - 21870000*y*z^2 sage: E.defining_polynomial()(f.defining_polynomials()) * f.post_rescaling() a^3 + 7*b^3 + 64*c^3 TESTS:: sage: R.<x,y,z> = QQ[] sage: cubic = x^2*y + 4*x*y^2 + x^2*z + 8*x*y*z + 4*y^2*z + 9*x*z^2 + 9*y*z^2 sage: EllipticCurve_from_cubic(cubic, [1,-1,1], morphism=False) Elliptic Curve defined by y^2 - 882*x*y - 2560000*y = x^3 - 127281*x^2 over Rational Field """ import sage.matrix.all as matrix # check the input R = F.parent() if not is_MPolynomialRing(R): raise TypeError('equation must be a polynomial') if R.ngens() != 3: raise TypeError('equation must be a polynomial in three variables') if not F.is_homogeneous(): raise TypeError('equation must be a homogeneous polynomial') K = F.parent().base_ring() try: P = [K(c) for c in P] except TypeError: raise TypeError('cannot convert %s into %s' % (P, K)) if F(P) != 0: raise ValueError('%s is not a point on %s' % (P, F)) if len(P) != 3: raise TypeError('%s is not a projective point' % P) x, y, z = R.gens() # First case: if P = P2 then P is a flex P2 = chord_and_tangent(F, P) if are_projectively_equivalent(P, P2, base_ring=K): # find the tangent to F in P dx = K(F.derivative(x)(P)) dy = K(F.derivative(y)(P)) dz = K(F.derivative(z)(P)) # find a second point Q on the tangent line but not on the cubic for tangent in [[dy, -dx, K.zero()], [dz, K.zero(), -dx], [K.zero(), -dz, dx]]: tangent = projective_point(tangent) Q = [tangent[0] + P[0], tangent[1] + P[1], tangent[2] + P[2]] F_Q = F(Q) if F_Q != 0: # At most one further point may accidentally be on the cubic break assert F_Q != 0 # pick linearly independent third point for third_point in [(1, 0, 0), (0, 1, 0), (0, 0, 1)]: M = matrix.matrix(K, [Q, P, third_point]).transpose() if M.is_invertible(): break F2 = R(M.act_on_polynomial(F)) # scale and dehomogenise a = K(F2.coefficient(x**3)) F3 = F2 / a b = K(F3.coefficient(y * y * z)) S = rings.PolynomialRing(K, 'x,y,z') # elliptic curve coordinates X, Y, Z = S.gen(0), S.gen(1), S(-1 / b) * S.gen(2) F4 = F3(X, Y, Z) E = EllipticCurve(F4.subs(z=1)) if not morphism: return E inv_defining_poly = [ M[i, 0] * X + M[i, 1] * Y + M[i, 2] * Z for i in range(3) ] inv_post = -1 / a M = M.inverse() trans_x, trans_y, trans_z = [ M[i, 0] * x + M[i, 1] * y + M[i, 2] * z for i in range(3) ] fwd_defining_poly = [trans_x, trans_y, -b * trans_z] fwd_post = -a # Second case: P is not a flex, then P, P2, P3 are different else: P3 = chord_and_tangent(F, P2) # send P, P2, P3 to (1:0:0), (0:1:0), (0:0:1) respectively M = matrix.matrix(K, [P, P2, P3]).transpose() F2 = M.act_on_polynomial(F) # substitute x = U^2, y = V*W, z = U*W, and rename (x,y,z)=(U,V,W) F3 = F2.substitute({x: x**2, y: y * z, z: x * z}) // (x**2 * z) # scale and dehomogenise a = K(F3.coefficient(x**3)) F4 = F3 / a b = K(F4.coefficient(y * y * z)) # change to a polynomial in only two variables S = rings.PolynomialRing(K, 'x,y,z') # elliptic curve coordinates X, Y, Z = S.gen(0), S.gen(1), S(-1 / b) * S.gen(2) F5 = F4(X, Y, Z) E = EllipticCurve(F5.subs(z=1)) if not morphism: return E inv_defining_poly = [ M[i, 0] * X * X + M[i, 1] * Y * Z + M[i, 2] * X * Z for i in range(3) ] inv_post = -1 / a / (X**2) / Z M = M.inverse() trans_x, trans_y, trans_z = [(M[i, 0] * x + M[i, 1] * y + M[i, 2] * z) for i in range(3)] fwd_defining_poly = [ trans_x * trans_z, trans_x * trans_y, -b * trans_z * trans_z ] fwd_post = -a / (trans_x * trans_z * trans_z) # Construct the morphism from sage.schemes.projective.projective_space import ProjectiveSpace P2 = ProjectiveSpace(2, K, names=[str(_) for _ in R.gens()]) cubic = P2.subscheme(F) from sage.schemes.elliptic_curves.weierstrass_transform import \ WeierstrassTransformationWithInverse return WeierstrassTransformationWithInverse(cubic, E, fwd_defining_poly, fwd_post, inv_defining_poly, inv_post)
def chord_and_tangent(F, P): """ Use the chord and tangent method to get another point on a cubic. INPUT: - ``F`` -- a homogeneous cubic in three variables with rational coefficients, as a polynomial ring element, defining a smooth plane cubic curve. - ``P`` -- a 3-tuple `(x,y,z)` defining a projective point on the curve `F=0`. OUTPUT: Another point satisfying the equation ``F``. EXAMPLES:: sage: R.<x,y,z> = QQ[] sage: from sage.schemes.elliptic_curves.constructor import chord_and_tangent sage: F = x^3+y^3+60*z^3 sage: chord_and_tangent(F, [1,-1,0]) [1, -1, 0] sage: F = x^3+7*y^3+64*z^3 sage: p0 = [2,2,-1] sage: p1 = chord_and_tangent(F, p0); p1 [-5, 3, -1] sage: p2 = chord_and_tangent(F, p1); p2 [1265, -183, -314] TESTS:: sage: F(p2) 0 sage: list(map(type, p2)) [<type 'sage.rings.rational.Rational'>, <type 'sage.rings.rational.Rational'>, <type 'sage.rings.rational.Rational'>] See :trac:`16068`:: sage: F = x**3 - 4*x**2*y - 65*x*y**2 + 3*x*y*z - 76*y*z**2 sage: chord_and_tangent(F, [0, 1, 0]) [0, 0, -1] """ # check the input R = F.parent() if not is_MPolynomialRing(R): raise TypeError('equation must be a polynomial') if R.ngens() != 3: raise TypeError('%s is not a polynomial in three variables' % F) if not F.is_homogeneous(): raise TypeError('%s is not a homogeneous polynomial' % F) x, y, z = R.gens() if len(P) != 3: raise TypeError('%s is not a projective point' % P) K = R.base_ring() try: P = [K(c) for c in P] except TypeError: raise TypeError('cannot coerce %s into %s' % (P, K)) if F(P) != 0: raise ValueError('%s is not a point on %s' % (P, F)) # find the tangent to F in P dx = K(F.derivative(x)(P)) dy = K(F.derivative(y)(P)) dz = K(F.derivative(z)(P)) # if dF/dy(P) = 0, change variables so that dF/dy != 0 if dy == 0: if dx != 0: g = F.substitute({x: y, y: x}) Q = [P[1], P[0], P[2]] R = chord_and_tangent(g, Q) return [R[1], R[0], R[2]] elif dz != 0: g = F.substitute({y: z, z: y}) Q = [P[0], P[2], P[1]] R = chord_and_tangent(g, Q) return [R[0], R[2], R[1]] else: raise ValueError('%s is singular at %s' % (F, P)) # t will be our choice of parmeter of the tangent plane # dx*(x-P[0]) + dy*(y-P[1]) + dz*(z-P[2]) # through the point P t = rings.PolynomialRing(K, 't').gen(0) Ft = F(dy * t + P[0], -dx * t + P[1], P[2]) if Ft == 0: # (dy, -dx, 0) is projectively equivalent to P # then (0, -dz, dy) is not projectively equivalent to P g = F.substitute({x: z, z: x}) Q = [P[2], P[1], P[0]] R = chord_and_tangent(g, Q) return [R[2], R[1], R[0]] # Ft has a double zero at t=0 by construction, which we now remove Ft = Ft // t**2 # first case: the third point is at t=infinity if Ft.is_constant(): return projective_point([dy, -dx, K(0)]) # second case: the third point is at finite t else: assert Ft.degree() == 1 t0 = Ft.roots()[0][0] return projective_point([dy * t0 + P[0], -dx * t0 + P[1], P[2]])
# the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** import math import sage.modular.hecke.all as hecke import sage.rings.all as rings from sage.arith.all import kronecker, next_prime from sage.matrix.matrix_space import MatrixSpace from sage.modular.arithgroup.all import Gamma0 from sage.libs.pari.all import pari from sage.misc.misc import verbose ZZy = rings.PolynomialRing(rings.ZZ, 'y') def Phi2_quad(J3, ssJ1, ssJ2): r""" This function returns a certain quadratic polynomial over a finite field in indeterminate J3. The roots of the polynomial along with ssJ1 are the neighboring/2-isogenous supersingular j-invariants of ssJ2. INPUT: - ``J3`` -- indeterminate of a univariate polynomial ring defined over a finite field with p^2 elements where p is a prime number