Skip to content

Commit b5c2615

Browse files
author
Release Manager
committed
gh-39212: Refactor period lattice Improvement for #38474 . (previously I didn't know `is_exact()` exists, thus the ugly `isinstance()` check.) Also now it works with RDF and CDF. ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [x] I have updated the documentation and checked the documentation preview. ### ⌛ Dependencies Requires #39137 . URL: #39212 Reported by: user202729 Reviewer(s): Kwankyu Lee, user202729
2 parents d0e72a6 + 8e5ca6a commit b5c2615

File tree

2 files changed

+81
-26
lines changed

2 files changed

+81
-26
lines changed

src/sage/schemes/elliptic_curves/ell_field.py

+4
Original file line numberDiff line numberDiff line change
@@ -1548,10 +1548,14 @@ def period_lattice(self):
15481548
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x + 6 over Rational Field
15491549
sage: EllipticCurve(RR, [1, 6]).period_lattice()
15501550
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 6.00000000000000 over Real Field with 53 bits of precision
1551+
sage: EllipticCurve(RDF, [1, 6]).period_lattice()
1552+
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.0*x + 6.0 over Real Double Field
15511553
sage: EllipticCurve(RealField(100), [1, 6]).period_lattice()
15521554
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.0000000000000000000000000000*x + 6.0000000000000000000000000000 over Real Field with 100 bits of precision
15531555
sage: EllipticCurve(CC, [1, 6]).period_lattice()
15541556
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 6.00000000000000 over Complex Field with 53 bits of precision
1557+
sage: EllipticCurve(CDF, [1, 6]).period_lattice()
1558+
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.0*x + 6.0 over Complex Double Field
15551559
sage: EllipticCurve(ComplexField(100), [1, 6]).period_lattice()
15561560
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.0000000000000000000000000000*x + 6.0000000000000000000000000000 over Complex Field with 100 bits of precision
15571561
sage: EllipticCurve(AA, [1, 6]).period_lattice()

src/sage/schemes/elliptic_curves/period_lattice.py

+77-26
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108

109109
import sage.rings.abc
110110

111+
from sage.categories.morphism import IdentityMorphism
111112
from sage.misc.cachefunc import cached_method
112113
from sage.misc.lazy_import import lazy_import
113114
from sage.modules.free_module import FreeModule_generic_pid
@@ -116,7 +117,7 @@
116117
from sage.rings.integer_ring import ZZ
117118
from sage.rings.qqbar import AA, QQbar
118119
from sage.rings.rational_field import QQ
119-
from sage.rings.real_mpfr import RealField, RealField_class, RealNumber
120+
from sage.rings.real_mpfr import RealField, RealNumber
120121
from sage.schemes.elliptic_curves.constructor import EllipticCurve
121122
from sage.structure.richcmp import richcmp_method, richcmp, richcmp_not_equal
122123

@@ -231,14 +232,14 @@ def __init__(self, E, embedding=None):
231232
# the given embedding:
232233

233234
K = E.base_field()
234-
self.is_approximate = isinstance(K, (RealField_class, ComplexField_class))
235+
self._is_exact = K.is_exact()
235236
if embedding is None:
236237
if K in (AA, QQbar):
237238
embedding = K.hom(QQbar)
238239
real = K == AA
239-
elif self.is_approximate:
240-
embedding = K.hom(K)
241-
real = isinstance(K, RealField_class)
240+
elif not self._is_exact:
241+
embedding = IdentityMorphism(K)
242+
real = isinstance(K, (sage.rings.abc.RealField, sage.rings.abc.RealDoubleField))
242243
else:
243244
embs = K.embeddings(AA)
244245
real = len(embs) > 0
@@ -271,24 +272,24 @@ def __init__(self, E, embedding=None):
271272
# The ei are used both for period computation and elliptic
272273
# logarithms.
273274

274-
if self.is_approximate:
275-
self.f2 = self.E.two_division_polynomial()
276-
else:
275+
if self._is_exact:
277276
self.Ebar = self.E.change_ring(self.embedding)
278277
self.f2 = self.Ebar.two_division_polynomial()
278+
else:
279+
self.f2 = self.E.two_division_polynomial()
279280
if self.real_flag == 1: # positive discriminant
280-
self._ei = self.f2.roots(K if self.is_approximate else AA,multiplicities=False)
281+
self._ei = self.f2.roots(AA if self._is_exact else K, multiplicities=False)
281282
self._ei.sort() # e1 < e2 < e3
282283
e1, e2, e3 = self._ei
283284
elif self.real_flag == -1: # negative discriminant
284-
self._ei = self.f2.roots(ComplexField(K.precision()) if self.is_approximate else QQbar, multiplicities=False)
285+
self._ei = self.f2.roots(QQbar if self._is_exact else ComplexField(K.precision()), multiplicities=False)
285286
self._ei = sorted(self._ei, key=lambda z: z.imag())
286287
e1, e3, e2 = self._ei # so e3 is real
287-
if not self.is_approximate:
288+
if self._is_exact:
288289
e3 = AA(e3)
289290
self._ei = [e1, e2, e3]
290291
else:
291-
self._ei = self.f2.roots(ComplexField(K.precision()) if self.is_approximate else QQbar, multiplicities=False)
292+
self._ei = self.f2.roots(QQbar if self._is_exact else ComplexField(K.precision()), multiplicities=False)
292293
e1, e2, e3 = self._ei
293294

294295
# The quantities sqrt(e_i-e_j) are cached (as elements of
@@ -350,7 +351,7 @@ def __repr__(self):
350351
Defn: a |--> 1.259921049894873?
351352
"""
352353
K = self.E.base_field()
353-
if K in (QQ, AA, QQbar) or isinstance(K, (RealField_class, ComplexField_class)):
354+
if K in (QQ, AA, QQbar) or isinstance(self.embedding, IdentityMorphism):
354355
return "Period lattice associated to %s" % (self.E)
355356
return "Period lattice associated to %s with respect to the embedding %s" % (self.E, self.embedding)
356357

@@ -656,7 +657,7 @@ def _compute_default_prec(self):
656657
r"""
657658
Internal function to compute the default precision to be used if nothing is passed in.
658659
"""
659-
return self.E.base_field().precision() if self.is_approximate else RealField().precision()
660+
return RealField().precision() if self._is_exact else self.E.base_field().precision()
660661

661662
@cached_method
662663
def _compute_periods_real(self, prec=None, algorithm='sage'):
@@ -704,7 +705,7 @@ def _compute_periods_real(self, prec=None, algorithm='sage'):
704705

705706
if algorithm == 'pari':
706707
ainvs = self.E.a_invariants()
707-
if self.E.base_field() is not QQ and not self.is_approximate:
708+
if self.E.base_field() is not QQ and self._is_exact:
708709
ainvs = [C(self.embedding(ai)).real() for ai in ainvs]
709710

710711
# The precision for omega() is determined by ellinit()
@@ -716,7 +717,7 @@ def _compute_periods_real(self, prec=None, algorithm='sage'):
716717
raise ValueError("invalid value of 'algorithm' parameter")
717718

718719
pi = R.pi()
719-
# Up to now everything has been exact in AA or QQbar (unless self.is_approximate),
720+
# Up to now everything has been exact in AA or QQbar (if self._is_exact),
720721
# but now we must go transcendental. Only now is the desired precision used!
721722
if self.real_flag == 1: # positive discriminant
722723
a, b, c = (R(x) for x in self._abc)
@@ -788,7 +789,7 @@ def _compute_periods_complex(self, prec=None, normalise=True):
788789
prec = self._compute_default_prec()
789790
C = ComplexField(prec)
790791

791-
# Up to now everything has been exact in AA or QQbar (unless self.is_approximate),
792+
# Up to now everything has been exact in AA or QQbar (if self._is_exact),
792793
# but now we must go transcendental. Only now is the desired precision used!
793794
pi = C.pi()
794795
a, b, c = (C(x) for x in self._abc)
@@ -1166,6 +1167,38 @@ def curve(self):
11661167
"""
11671168
return self.E
11681169

1170+
@property
1171+
def is_approximate(self):
1172+
"""
1173+
``self.is_approximate`` is deprecated, use ``not self.curve().is_exact()`` instead.
1174+
1175+
TESTS::
1176+
1177+
sage: E = EllipticCurve(ComplexField(100), [I, 3*I+4])
1178+
sage: L = E.period_lattice()
1179+
sage: L.is_approximate
1180+
doctest:...: DeprecationWarning: The attribute is_approximate for period lattice is deprecated,
1181+
use self.curve().is_exact() instead.
1182+
See https://github.com/sagemath/sage/issues/39212 for details.
1183+
True
1184+
sage: L.curve() is E
1185+
True
1186+
sage: E.is_exact()
1187+
False
1188+
sage: E = EllipticCurve(QQ, [0, 2])
1189+
sage: L = E.period_lattice()
1190+
sage: L.is_approximate
1191+
False
1192+
sage: L.curve() is E
1193+
True
1194+
sage: E.is_exact()
1195+
True
1196+
"""
1197+
from sage.misc.superseded import deprecation
1198+
deprecation(39212, "The attribute is_approximate for period lattice is "
1199+
"deprecated, use self.curve().is_exact() instead.")
1200+
return not self._is_exact
1201+
11691202
def ei(self):
11701203
r"""
11711204
Return the x-coordinates of the 2-division points of the elliptic curve associated
@@ -1757,10 +1790,19 @@ def elliptic_logarithm(self, P, prec=None, reduce=True):
17571790
sage: L.real_flag
17581791
-1
17591792
sage: P = E(3, 6)
1760-
sage: L.elliptic_logarithm(P)
1793+
sage: L.elliptic_logarithm(P) # abs tol 1e-26
17611794
2.4593388737550379526023682666
1762-
sage: L.elliptic_exponential(_)
1795+
sage: L.elliptic_exponential(_) # abs tol 1e-26
17631796
(3.0000000000000000000000000000 : 5.9999999999999999999999999999 : 1.0000000000000000000000000000)
1797+
sage: E = EllipticCurve(RDF, [1, 6])
1798+
sage: L = E.period_lattice()
1799+
sage: L.real_flag
1800+
-1
1801+
sage: P = E(3, 6)
1802+
sage: L.elliptic_logarithm(P) # abs tol 1e-13
1803+
2.45933887375504
1804+
sage: L.elliptic_exponential(_) # abs tol 1e-13
1805+
(3.00000000000000 : 6.00000000000001 : 1.00000000000000)
17641806
17651807
Real approximate field, positive discriminant::
17661808
@@ -1769,9 +1811,9 @@ def elliptic_logarithm(self, P, prec=None, reduce=True):
17691811
sage: L.real_flag
17701812
1
17711813
sage: P = E.lift_x(4)
1772-
sage: L.elliptic_logarithm(P)
1814+
sage: L.elliptic_logarithm(P) # abs tol 1e-26
17731815
0.51188849089267627141925354967
1774-
sage: L.elliptic_exponential(_)
1816+
sage: L.elliptic_exponential(_) # abs tol 1e-26
17751817
(4.0000000000000000000000000000 : -7.1414284285428499979993998114 : 1.0000000000000000000000000000)
17761818
17771819
Complex approximate field::
@@ -1781,10 +1823,19 @@ def elliptic_logarithm(self, P, prec=None, reduce=True):
17811823
sage: L.real_flag
17821824
0
17831825
sage: P = E.lift_x(4)
1784-
sage: L.elliptic_logarithm(P)
1826+
sage: L.elliptic_logarithm(P) # abs tol 1e-26
17851827
-1.1447032790074574712147458157 - 0.72429843602171875396186134806*I
1786-
sage: L.elliptic_exponential(_)
1828+
sage: L.elliptic_exponential(_) # abs tol 1e-26
17871829
(4.0000000000000000000000000000 + 1.2025589033682610849950210280e-30*I : -8.2570982991257407680322611854 - 0.42387771989714340809597881586*I : 1.0000000000000000000000000000)
1830+
sage: E = EllipticCurve(CDF, [I, 3*I+4])
1831+
sage: L = E.period_lattice()
1832+
sage: L.real_flag
1833+
0
1834+
sage: P = E.lift_x(4)
1835+
sage: L.elliptic_logarithm(P) # abs tol 1e-13
1836+
-1.14470327900746 - 0.724298436021719*I
1837+
sage: L.elliptic_exponential(_) # abs tol 1e-13
1838+
(4.00000000000000 - 0*I : -8.25709829912574 - 0.423877719897148*I : 1.00000000000000)
17881839
"""
17891840
if P.curve() is not self.E:
17901841
raise ValueError("Point is on the wrong curve")
@@ -2002,10 +2053,10 @@ def elliptic_exponential(self, z, to_curve=True):
20022053

20032054
if to_curve:
20042055
K = x.parent()
2005-
if self.is_approximate:
2006-
v = self.embedding
2007-
else:
2056+
if self._is_exact:
20082057
v = refine_embedding(self.embedding, Infinity)
2058+
else:
2059+
v = self.embedding
20092060
a1, a2, a3, a4, a6 = (K(v(a)) for a in self.E.ainvs())
20102061
b2 = K(v(self.E.b2()))
20112062
x = x - b2 / 12

0 commit comments

Comments
 (0)