Path: blob/master/sage/schemes/elliptic_curves/modular_parametrization.py
4108 views
# -*- coding: utf-8 -*-1r"""2Modular parametrization of elliptic curves over `\QQ`34By the work of Taylor--Wiles et al. it is known that there5is a surjective morphism67.. math::89\phi_E: X_0(N) \rightarrow E.1011from the modular curve `X_0(N)`, where `N` is the conductor of `E`.12The map sends the cusp `\infty` to the origin of `E`.1314EXMAPLES::1516sage: phi = EllipticCurve('11a1').modular_parametrization()17sage: phi18Modular parameterization from the upper half plane to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field19sage: phi(0.5+CDF(I))20(285684.320516... + 7.0...e-11*I : 1.526964169...e8 + 5.6...e-8*I : 1.00000000000000)21sage: phi.power_series(prec = 7)22(q^-2 + 2*q^-1 + 4 + 5*q + 8*q^2 + q^3 + 7*q^4 + O(q^5), -q^-3 - 3*q^-2 - 7*q^-1 - 13 - 17*q - 26*q^2 - 19*q^3 + O(q^4))2324AUTHORS:2526- chris wuthrich (02/10) - moved from ell_rational_field.py.2728"""2930######################################################################31# Copyright (C) 2010 William Stein <[email protected]>32#33# Distributed under the terms of the GNU General Public License (GPL)34#35# This code is distributed in the hope that it will be useful,36# but WITHOUT ANY WARRANTY; without even the implied warranty of37# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU38# General Public License for more details.39#40# The full text of the GPL is available at:41#42# http://www.gnu.org/licenses/43######################################################################4445import heegner4647from sage.rings.all import (LaurentSeriesRing, RationalField, ComplexField, QQ)48import sage.misc.misc as misc4950class ModularParameterization:51r"""52This class represents the modular parametrization of an elliptic curve5354.. math::5556\phi_E: X_0(N) \rightarrow E.5758Evaluation is done by passing through the lattice representation of `E`.5960EXAMPLES::6162sage: phi = EllipticCurve('11a1').modular_parametrization()63sage: phi64Modular parameterization from the upper half plane to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field6566"""67def __init__(self, E):68r"""69EXAMPLES::70s71sage: from sage.schemes.elliptic_curves.ell_rational_field import ModularParameterization72sage: phi = ModularParameterization(EllipticCurve('389a'))73sage: phi(CC.0/5)74(27.1965586309057 : -144.727322178982 : 1.00000000000000)7576sage: phi == loads(dumps(phi))77True7879"""80self._E = E8182def curve(self):83"""84Returns the curve associated to this modular parametrization.8586EXAMPLES::8788sage: E = EllipticCurve('15a')89sage: phi = E.modular_parametrization()90sage: phi.curve() is E91True92"""93return self._E9495def __repr__(self):96"""97TESTS::9899sage: E = EllipticCurve('37a')100sage: phi = E.modular_parametrization()101sage: phi102Modular parameterization from the upper half plane to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field103sage: phi.__repr__()104'Modular parameterization from the upper half plane to Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field'105"""106return "Modular parameterization from the upper half plane to %s" % self._E107108def __cmp__(self,other):109r"""110Compares two modular parametrizations by simply comparing the elliptic curves.111112EXAMPLES::113114sage: E = EllipticCurve('37a1')115sage: phi = E.modular_parametrization()116sage: phi == phi117True118"""119c = cmp(type(self), type(other))120if c:121return c122return cmp(self._E, other._E)123124def __call__(self, z, prec=None):125r"""126Evaluate self at a point `z \in X_0(N)` where `z` is given by a127representative in the upper half plane. All computations done with ``prec``128bits of precision. If ``prec`` is not given, use the precision of `z`.129130EXAMPLES::131132sage: E = EllipticCurve('37a')133sage: phi = E.modular_parametrization()134sage: phi((sqrt(7)*I - 17)/74, 53)135(...e-16 - ...e-16*I : ...e-16 + ...e-16*I : 1.00000000000000)136137Verify that the mapping is invariant under the action of `\Gamma_0(N)`138on the upper half plane::139140sage: E = EllipticCurve('11a')141sage: phi = E.modular_parametrization()142sage: tau = CC((1+1j)/5)143sage: phi(tau)144(-3.92181329652811 - 12.2578555525366*I : 44.9649874434872 + 14.3257120944681*I : 1.00000000000000)145sage: phi(tau+1)146(-3.92181329652810 - 12.2578555525366*I : 44.9649874434872 + 14.3257120944681*I : 1.00000000000000)147sage: phi((6*tau+1) / (11*tau+2))148(-3.9218132965285... - 12.2578555525369*I : 44.964987443489... + 14.325712094467...*I : 1.00000000000000)149150We can also apply the modular parametrization to a Heegner point on `X_0(N)`::151152sage: H = heegner_points(389,-7,5); H153All Heegner points of conductor 5 on X_0(389) associated to QQ[sqrt(-7)]154sage: x = H[0]; x155Heegner point 5/778*sqrt(-7) - 147/778 of discriminant -7 and conductor 5 on X_0(389)156sage: E = EllipticCurve('389a'); phi = E.modular_parametrization()157sage: phi(x)158Heegner point of discriminant -7 and conductor 5 on elliptic curve of conductor 389159sage: phi(x).quadratic_form()160389*x^2 + 147*x*y + 14*y^2161162163ALGORITHM:164165Integrate the modular form attached to this elliptic curve from166`z` to `\infty` to get a point on the lattice representation of167`E`, then use the Weierstrass `\wp` function to map it to the168curve itself.169"""170if isinstance(z, heegner.HeegnerPointOnX0N):171return z.map_to_curve(self.curve())172# Map to the CC of CC/PeriodLattice.173tm = misc.verbose("Evaluating modular parameterization to precision %s bits"%prec)174w = self.map_to_complex_numbers(z, prec=prec)175# Map to E via Weierstrass P176z = self._E.elliptic_exponential(w)177misc.verbose("Finished evaluating modular parameterization", tm)178return z179180def map_to_complex_numbers(self, z, prec=None):181"""182Evaluate self at a point `z \in X_0(N)` where `z` is given by183a representative in the upper half plane, returning a point in184the complex numbers. All computations done with ``prec`` bits185of precision. If ``prec`` is not given, use the precision of `z`.186Use self(z) to compute the image of z on the Weierstrass equation187of the curve.188189EXAMPLES::190191sage: E = EllipticCurve('37a'); phi = E.modular_parametrization()192sage: tau = (sqrt(7)*I - 17)/74193sage: z = phi.map_to_complex_numbers(tau); z1940.929592715285395 - 1.22569469099340*I195sage: E.elliptic_exponential(z)196(...e-16 - ...e-16*I : ...e-16 + ...e-16*I : 1.00000000000000)197sage: phi(tau)198(...e-16 - ...e-16*I : ...e-16 + ...e-16*I : 1.00000000000000)199"""200if prec is None:201try:202prec = z.parent().prec()203except AttributeError:204prec = 53205CC = ComplexField(prec)206if z in QQ:207raise NotImplementedError208z = CC(z)209if z.imag() <= 0:210raise ValueError, "Point must be in the upper half plane"211# TODO: for very small imaginary part, maybe try to transform under212# \Gamma_0(N) to a better representative?213q = (2*CC.gen()*CC.pi()*z).exp()214# nterms'th term is less than 2**-(prec+10) (c.f. eclib code)215nterms = (-(prec+10)/q.abs().log2()).ceil()216# Use Horner's rule to sum the integral of the form217enumerated_an = list(enumerate(self._E.anlist(nterms)))[1:]218lattice_point = 0219for n, an in reversed(enumerated_an):220lattice_point += an/n221lattice_point *= q222return lattice_point223224def power_series(self, prec=20):225r"""226Computes and returns the power series of this modular parametrization.227228The curve must be a a minimal model. The prec parameter determines229the number of significant terms. This means that X will be given up230to O(q^(prec-2)) and Y will be given up to O(q^(prec-3)).231232OUTPUT: A list of two Laurent series ``[X(x),Y(x)]`` of degrees -2, -3233respectively, which satisfy the equation of the elliptic curve.234There are modular functions on `\Gamma_0(N)` where `N` is the235conductor.236237The series should satisfy the differential equation238239.. math::240241\frac{\mathrm{d}X}{2Y + a_1 X + a_3} = \frac{f(q)\, \mathrm{d}q}{q}242243where `f` is ``self.curve().q_expansion()``.244245EXAMPLES::246247sage: E=EllipticCurve('389a1')248sage: phi = E.modular_parametrization()249sage: X,Y = phi.power_series(prec = 10)250sage: X251q^-2 + 2*q^-1 + 4 + 7*q + 13*q^2 + 18*q^3 + 31*q^4 + 49*q^5 + 74*q^6 + 111*q^7 + O(q^8)252sage: Y253-q^-3 - 3*q^-2 - 8*q^-1 - 17 - 33*q - 61*q^2 - 110*q^3 - 186*q^4 - 320*q^5 - 528*q^6 + O(q^7)254sage: X,Y = phi.power_series()255sage: X256q^-2 + 2*q^-1 + 4 + 7*q + 13*q^2 + 18*q^3 + 31*q^4 + 49*q^5 + 74*q^6 + 111*q^7 + 173*q^8 + 251*q^9 + 379*q^10 + 560*q^11 + 824*q^12 + 1199*q^13 + 1773*q^14 + 2548*q^15 + 3722*q^16 + 5374*q^17 + O(q^18)257sage: Y258-q^-3 - 3*q^-2 - 8*q^-1 - 17 - 33*q - 61*q^2 - 110*q^3 - 186*q^4 - 320*q^5 - 528*q^6 - 861*q^7 - 1383*q^8 - 2218*q^9 - 3472*q^10 - 5451*q^11 - 8447*q^12 - 13020*q^13 - 19923*q^14 - 30403*q^15 - 46003*q^16 + O(q^17)259260The following should give 0, but only approximately::261262sage: q = X.parent().gen()263sage: E.defining_polynomial()(X,Y,1) + O(q^11) == 0264True265266Note that below we have to change variable from x to q::267268sage: a1,_,a3,_,_=E.a_invariants()269sage: f=E.q_expansion(17)270sage: q=f.parent().gen()271sage: f/q == (X.derivative()/(2*Y+a1*X+a3))272True273"""274R = LaurentSeriesRing(RationalField(),'q')275if not self._E.is_minimal():276raise NotImplementedError, "Only implemented for minimal curves."277from sage.libs.all import pari278old_prec = pari.get_series_precision()279pari.set_series_precision(prec-1)280XY = self._E.pari_mincurve().elltaniyama()281pari.set_series_precision(old_prec)282return R(XY[0]),R(XY[1])283284285286