Skip to content

Commit bdce391

Browse files
committed
introduce EllipticCurveHom_composite
1 parent 47db3b1 commit bdce391

File tree

5 files changed

+986
-32
lines changed

5 files changed

+986
-32
lines changed

src/doc/en/reference/arithmetic_curves/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Maps between them
2121
sage/schemes/elliptic_curves/weierstrass_morphism
2222
sage/schemes/elliptic_curves/ell_curve_isogeny
2323
sage/schemes/elliptic_curves/isogeny_small_degree
24+
sage/schemes/elliptic_curves/hom_composite
2425

2526

2627
Elliptic curves over number fields

src/sage/schemes/elliptic_curves/ell_curve_isogeny.py

Lines changed: 68 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@
6565

6666
from copy import copy
6767

68+
from sage.structure.sequence import Sequence
69+
6870
from sage.schemes.elliptic_curves.hom import EllipticCurveHom
6971

7072
from sage.rings.all import PolynomialRing, Integer, LaurentSeriesRing
@@ -74,7 +76,8 @@
7476

7577
from sage.rings.number_field.number_field_base import is_NumberField
7678

77-
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism, isomorphisms
79+
from sage.schemes.elliptic_curves.weierstrass_morphism \
80+
import WeierstrassIsomorphism, isomorphisms, baseWI
7881

7982
from sage.sets.set import Set
8083

@@ -1019,6 +1022,67 @@ def __init__(self, E, kernel, codomain=None, degree=None, model=None, check=True
10191022

10201023
self.__perform_inheritance_housekeeping()
10211024

1025+
def _eval(self, P):
1026+
r"""
1027+
Less strict evaluation method for internal use.
1028+
1029+
In particular, this can be used to evaluate ``self`` at a
1030+
point defined over an extension field.
1031+
1032+
INPUT: a sequence of 3 coordinates defining a point on ``self``
1033+
1034+
OUTPUT: the result of evaluating ``self'' at the given point
1035+
1036+
EXAMPLES::
1037+
1038+
sage: E = EllipticCurve([1,0]); E
1039+
Elliptic Curve defined by y^2 = x^3 + x over Rational Field
1040+
sage: phi = E.isogeny(E(0,0))
1041+
sage: P = E.change_ring(QQbar).lift_x(QQbar.random_element())
1042+
sage: phi._eval(P).curve()
1043+
Elliptic Curve defined by y^2 = x^3 + (-4)*x over Algebraic Field
1044+
1045+
::
1046+
1047+
sage: E = EllipticCurve(j=Mod(0,419))
1048+
sage: K = next(filter(bool, E(0).division_points(5)))
1049+
sage: psi = E.isogeny(K)
1050+
sage: Ps = E.change_ring(GF(419**2))(0).division_points(5)
1051+
sage: {psi._eval(P).curve() for P in Ps}
1052+
{Elliptic Curve defined by y^2 = x^3 + 140*x + 214 over Finite Field in z2 of size 419^2}
1053+
"""
1054+
if self._domain.defining_polynomial()(*P):
1055+
raise ValueError(f'{P} not on {self._domain}')
1056+
1057+
if not P:
1058+
k = Sequence(tuple(P)).universe()
1059+
return self._codomain(0).change_ring(k)
1060+
1061+
Q = P.xy()
1062+
pre_iso = self.get_pre_isomorphism()
1063+
if pre_iso is not None:
1064+
Q = baseWI.__call__(pre_iso, Q)
1065+
1066+
if self.__algorithm == 'velu':
1067+
compute = self.__compute_via_velu
1068+
elif self.__algorithm == 'kohel':
1069+
compute = self.__compute_via_kohel
1070+
else:
1071+
raise NotImplementedError
1072+
1073+
try:
1074+
Q = compute(*Q)
1075+
except ZeroDivisionError:
1076+
Q = (0,1,0)
1077+
1078+
post_iso = self.get_post_isomorphism()
1079+
if post_iso is not None:
1080+
Q = baseWI.__call__(post_iso, Q)
1081+
1082+
k = Sequence(tuple(P) + tuple(Q)).universe()
1083+
return self._codomain.base_extend(k).point(Q)
1084+
1085+
10221086
def _call_(self, P):
10231087
r"""
10241088
Function that implements the call-ability of elliptic curve
@@ -2534,17 +2598,10 @@ def __compute_via_kohel_numeric(self, xP, yP):
25342598
25352599
"""
25362600
# first check if this point is in the kernel:
2537-
25382601
if 0 == self.__inner_kernel_polynomial(x=xP):
25392602
return self.__intermediate_codomain(0)
25402603

2541-
(xP_out, yP_out) = self.__compute_via_kohel(xP, yP)
2542-
2543-
# xP_out and yP_out do not always get evaluated to field
2544-
# elements but rather constant polynomials, so we do some
2545-
# explicit casting
2546-
2547-
return (self.__base_field(xP_out), self.__base_field(yP_out))
2604+
return self.__compute_via_kohel(xP, yP)
25482605

25492606
def __compute_via_kohel(self, xP, yP):
25502607
r"""
@@ -2571,9 +2628,7 @@ def __compute_via_kohel(self, xP, yP):
25712628
a = self.__phi(xP)
25722629
b = self.__omega(xP, yP)
25732630
c = self.__psi(xP)
2574-
cc = self.__mpoly_ring(c)
2575-
2576-
return (a/c**2, b/cc**3)
2631+
return (a/c**2, b/c**3)
25772632

25782633
def __initialize_rational_maps_via_kohel(self):
25792634
r"""
@@ -2595,7 +2650,7 @@ def __initialize_rational_maps_via_kohel(self):
25952650
25962651
"""
25972652
x = self.__poly_ring.gen()
2598-
y = self.__mpoly_ring.gen(1)
2653+
y = self.__xyfield.gen(1)
25992654
return self.__compute_via_kohel(x,y)
26002655

26012656
#

src/sage/schemes/elliptic_curves/hom.py

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
from sage.categories.morphism import Morphism
2626

27+
import sage.schemes.elliptic_curves.weierstrass_morphism as wm
28+
2729

2830
class EllipticCurveHom(Morphism):
2931
"""
@@ -162,9 +164,11 @@ def degree(self):
162164
r"""
163165
Return the degree of this elliptic-curve morphism.
164166
165-
Implemented by child classes. For examples,
166-
see :meth:`EllipticCurveIsogeny.degree` and
167-
:meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.degree`.
167+
Implemented by child classes. For examples, see:
168+
169+
- :meth:`EllipticCurveIsogeny.degree`
170+
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.degree`
171+
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.degree`
168172
169173
TESTS::
170174
@@ -180,9 +184,11 @@ def kernel_polynomial(self):
180184
r"""
181185
Return the kernel polynomial of this elliptic-curve morphism.
182186
183-
Implemented by child classes. For examples,
184-
see :meth:`EllipticCurveIsogeny.kernel_polynomial` and
185-
:meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.kernel_polynomial`.
187+
Implemented by child classes. For examples, see:
188+
189+
- :meth:`EllipticCurveIsogeny.kernel_polynomial`
190+
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.kernel_polynomial`
191+
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.kernel_polynomial`
186192
187193
TESTS::
188194
@@ -198,9 +204,11 @@ def dual(self):
198204
r"""
199205
Return the dual of this elliptic-curve morphism.
200206
201-
Implemented by child classes. For examples,
202-
see :meth:`EllipticCurveIsogeny.dual` and
203-
:meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.dual`.
207+
Implemented by child classes. For examples, see:
208+
209+
- :meth:`EllipticCurveIsogeny.dual`
210+
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.dual`
211+
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.dual`
204212
205213
TESTS::
206214
@@ -218,9 +226,11 @@ def rational_maps(self):
218226
elliptic-curve morphism as fractions of bivariate
219227
polynomials in `x` and `y`.
220228
221-
Implemented by child classes. For examples,
222-
see :meth:`EllipticCurveIsogeny.rational_maps` and
223-
:meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.rational_maps`.
229+
Implemented by child classes. For examples, see:
230+
231+
- :meth:`EllipticCurveIsogeny.rational_maps`
232+
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.rational_maps`
233+
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.rational_maps`
224234
225235
TESTS::
226236
@@ -237,9 +247,11 @@ def x_rational_map(self):
237247
Return the `x`-coordinate rational map of this elliptic-curve
238248
morphism as a univariate rational expression in `x`.
239249
240-
Implemented by child classes. For examples,
241-
see :meth:`EllipticCurveIsogeny.x_rational_map` and
242-
:meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.x_rational_map`.
250+
Implemented by child classes. For examples, see:
251+
252+
- :meth:`EllipticCurveIsogeny.x_rational_map`
253+
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.x_rational_map`
254+
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.x_rational_map`
243255
244256
TESTS::
245257
@@ -448,7 +460,7 @@ def is_surjective(self):
448460
sage: phi.is_surjective()
449461
True
450462
"""
451-
return True
463+
return bool(self.degree())
452464

453465
def is_injective(self):
454466
r"""
@@ -477,9 +489,9 @@ def is_injective(self):
477489
sage: phi.is_injective()
478490
True
479491
"""
480-
# This will become wrong once purely inseparable isogenies
481-
# are implemented. We should probably add something like a
482-
# separable_degree() method then.
492+
if not self.is_separable():
493+
#TODO: should implement .separable_degree() or similar
494+
raise NotImplementedError
483495
return self.degree() == 1
484496

485497
def is_zero(self):
@@ -501,6 +513,25 @@ def is_zero(self):
501513
"""
502514
return not self.degree()
503515

516+
def __neg__(self):
517+
r"""
518+
Return the negative of this elliptic-curve morphism. In other
519+
words, return `[-1]\circ\varphi` where `\varphi` is ``self``
520+
and `[-1]` is the negation automorphism on the codomain curve.
521+
522+
EXAMPLES::
523+
524+
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
525+
sage: E = EllipticCurve(GF(1019), [5,5])
526+
sage: phi = E.isogeny(E.lift_x(73))
527+
sage: f,g = phi.rational_maps()
528+
sage: psi = EllipticCurveHom.__neg__(phi)
529+
sage: psi.rational_maps() == (f, -g)
530+
True
531+
"""
532+
a1,_,a3,_,_ = self.codomain().a_invariants()
533+
return wm.WeierstrassIsomorphism(self.codomain(), (-1,0,-a1,-a3)) * self
534+
504535
@cached_method
505536
def __hash__(self):
506537
"""

0 commit comments

Comments
 (0)