Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow constructing elliptic curve from period lattice basis #38959

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
124 changes: 124 additions & 0 deletions src/sage/schemes/elliptic_curves/constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,130 @@
from .ell_generic import EllipticCurve_generic
return EllipticCurve_generic(R, x)

@staticmethod
def _eisenstein_series_e_eval(weight, tau, prec):
r"""
Private method to evaluate `E_{2k}`.

INPUT:

- prec -- precision in bits

OUTPUT:

Element of ``ComplexField(prec)`` equal to `E_{2k}(\tau)` where ``2k == weight``.

TESTS:

Example values::

sage: tau = CC(2/3*I+4/5)
sage: weight = 6

Evaluating using our method::

sage: EllipticCurve._eisenstein_series_e_eval(weight, tau, 53) # abs tol 1e-10
2.06948373064822 + 9.23822630732235*I

Approximately evaluate using convergent sum::

sage: sum((a+b*tau)^-weight for a in (-50..50) for b in (-50..50) if gcd(a, b)==1)/2 # abs tol 1e-10
2.06948373572619 + 9.23822632418512*I

Higher precision::

sage: EllipticCurve._eisenstein_series_e_eval(weight, tau, 200) # abs tol 1e-60
2.0694837306482189422343628966349567015465461257928410093613 + 9.2382263073223530637169893909058439360384065238856673719976*I
"""
from sage.modular.modform.constructor import EisensteinForms
M = EisensteinForms(1, weight)
f = M.gen(0)
from sage.rings.complex_mpfr import ComplexField
F = ComplexField(prec)
return F(f.eval_at_tau(F(tau))/f.qexp(1)[0])

@staticmethod
def _eisenstein_series_g_eval(weight, tau, prec):
r"""
Similar to :meth:`_eisenstein_series_e_eval`, but evaluates `G_{2k}`.

TESTS::

sage: tau = CC(2/3*I+4/5)
sage: weight = 6
sage: EllipticCurve._eisenstein_series_g_eval(weight, tau, 53) # abs tol 1e-10
4.21074983052932 + 18.7968908775932*I

Higher precision::

sage: EllipticCurve._eisenstein_series_g_eval(weight, tau, 200) # abs tol 1e-60
4.2107498305293201023614384183445982620640708046199904172058 + 18.796890877593226640592176459453734505169430012077274805656*I
"""
from sage.functions.transcendental import zeta
e = EllipticCurve._eisenstein_series_e_eval(weight, tau, prec)
return e.parent()(zeta(weight) * 2 * e)

@staticmethod
def from_period_lattice_basis(w1, w2):
r"""
Construct an elliptic curve from a period lattice basis.

INPUT:

- ``w1``, ``w2`` -- basis elements, must be element of ``ComplexField(prec)`` for some ``prec``

OUTPUT:

``EllipticCurve`` instance with base ring ``ComplexField(prec)``

EXAMPLES::

sage: F = ComplexField(53)
sage: w1 = F(1)
sage: w2 = F(I * sqrt(7))
sage: E = EllipticCurve.from_period_lattice_basis(w1, w2)
sage: E.period_lattice().basis() # abs tol 1e-10
(-2.64575131106483*I, -1.00000000000000)

TESTS::

sage: E = EllipticCurve.from_period_lattice_basis(F(1), F(3*I))
sage: E.period_lattice().basis() # abs tol 1e-10
(-3.00000000000639*I, -1.00000000000000)
sage: E = EllipticCurve.from_period_lattice_basis(F(2), F(3*I))
sage: E.period_lattice().basis() # abs tol 1e-10
(-3.00000000000000*I, -2.00000000000000)
sage: E = EllipticCurve.from_period_lattice_basis(F(1), F(-I))
sage: E.period_lattice().basis() # abs tol 1e-10
(1.00000000000000, -1.00000000000000*I)
sage: E = EllipticCurve.from_period_lattice_basis(F(3+4*I), F(4+3*I))
sage: E.period_lattice().basis() # abs tol 1e-10
(-4.00000000006586 - 3.00000000011837*I, -1.00000000000000 + 1.00000000000000*I)
sage: E = EllipticCurve.from_period_lattice_basis(F(1+I), F(6*I))
sage: E.period_lattice().basis() # abs tol 1e-10
(3.00000000000639 - 3.00000000000639*I, -1.00000000000000 - 1.00000000000000*I)
sage: E = EllipticCurve.from_period_lattice_basis(F(1+2*I), F(-2+3*I))
sage: E.period_lattice().basis() # abs tol 1e-10
(3.00000000000000 - 1.00000000000000*I, -1.00000000000000 - 2.00000000000000*I)

Higher precision::

sage: F = ComplexField(128)
sage: E = EllipticCurve.from_period_lattice_basis(F(1), F(3*I))
sage: E.period_lattice().basis() # abs tol 1e-30
(-2.9999999999999999999999999999999996134*I, -1.0000000000000000000000000000000000000)
"""
F = w1.parent()
if F != w2.parent():
raise ValueError("basis elements must have the same parent")

Check warning on line 642 in src/sage/schemes/elliptic_curves/constructor.py

View check run for this annotation

Codecov / codecov/patch

src/sage/schemes/elliptic_curves/constructor.py#L642

Added line #L642 was not covered by tests
prec = F.precision()
tau = w2/w1
if tau.imag() < 0:
tau = -tau
g2 = -60*EllipticCurve._eisenstein_series_g_eval(4, tau, prec)/w1**4
g3 = -140*EllipticCurve._eisenstein_series_g_eval(6, tau, prec)/w1**6
return EllipticCurve(F, [g2/4, g3/4])


EllipticCurve = EllipticCurveFactory('sage.schemes.elliptic_curves.constructor.EllipticCurve')

Expand Down
Loading