Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
introduce EllipticCurveHom_composite
Browse files Browse the repository at this point in the history
  • Loading branch information
yyyyx4 committed Oct 23, 2021
1 parent 47db3b1 commit bdce391
Show file tree
Hide file tree
Showing 5 changed files with 986 additions and 32 deletions.
1 change: 1 addition & 0 deletions src/doc/en/reference/arithmetic_curves/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Maps between them
sage/schemes/elliptic_curves/weierstrass_morphism
sage/schemes/elliptic_curves/ell_curve_isogeny
sage/schemes/elliptic_curves/isogeny_small_degree
sage/schemes/elliptic_curves/hom_composite


Elliptic curves over number fields
Expand Down
81 changes: 68 additions & 13 deletions src/sage/schemes/elliptic_curves/ell_curve_isogeny.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@

from copy import copy

from sage.structure.sequence import Sequence

from sage.schemes.elliptic_curves.hom import EllipticCurveHom

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

from sage.rings.number_field.number_field_base import is_NumberField

from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism, isomorphisms
from sage.schemes.elliptic_curves.weierstrass_morphism \
import WeierstrassIsomorphism, isomorphisms, baseWI

from sage.sets.set import Set

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

self.__perform_inheritance_housekeeping()

def _eval(self, P):
r"""
Less strict evaluation method for internal use.
In particular, this can be used to evaluate ``self`` at a
point defined over an extension field.
INPUT: a sequence of 3 coordinates defining a point on ``self``
OUTPUT: the result of evaluating ``self'' at the given point
EXAMPLES::
sage: E = EllipticCurve([1,0]); E
Elliptic Curve defined by y^2 = x^3 + x over Rational Field
sage: phi = E.isogeny(E(0,0))
sage: P = E.change_ring(QQbar).lift_x(QQbar.random_element())
sage: phi._eval(P).curve()
Elliptic Curve defined by y^2 = x^3 + (-4)*x over Algebraic Field
::
sage: E = EllipticCurve(j=Mod(0,419))
sage: K = next(filter(bool, E(0).division_points(5)))
sage: psi = E.isogeny(K)
sage: Ps = E.change_ring(GF(419**2))(0).division_points(5)
sage: {psi._eval(P).curve() for P in Ps}
{Elliptic Curve defined by y^2 = x^3 + 140*x + 214 over Finite Field in z2 of size 419^2}
"""
if self._domain.defining_polynomial()(*P):
raise ValueError(f'{P} not on {self._domain}')

if not P:
k = Sequence(tuple(P)).universe()
return self._codomain(0).change_ring(k)

Q = P.xy()
pre_iso = self.get_pre_isomorphism()
if pre_iso is not None:
Q = baseWI.__call__(pre_iso, Q)

if self.__algorithm == 'velu':
compute = self.__compute_via_velu
elif self.__algorithm == 'kohel':
compute = self.__compute_via_kohel
else:
raise NotImplementedError

try:
Q = compute(*Q)
except ZeroDivisionError:
Q = (0,1,0)

post_iso = self.get_post_isomorphism()
if post_iso is not None:
Q = baseWI.__call__(post_iso, Q)

k = Sequence(tuple(P) + tuple(Q)).universe()
return self._codomain.base_extend(k).point(Q)


def _call_(self, P):
r"""
Function that implements the call-ability of elliptic curve
Expand Down Expand Up @@ -2534,17 +2598,10 @@ def __compute_via_kohel_numeric(self, xP, yP):
"""
# first check if this point is in the kernel:

if 0 == self.__inner_kernel_polynomial(x=xP):
return self.__intermediate_codomain(0)

(xP_out, yP_out) = self.__compute_via_kohel(xP, yP)

# xP_out and yP_out do not always get evaluated to field
# elements but rather constant polynomials, so we do some
# explicit casting

return (self.__base_field(xP_out), self.__base_field(yP_out))
return self.__compute_via_kohel(xP, yP)

def __compute_via_kohel(self, xP, yP):
r"""
Expand All @@ -2571,9 +2628,7 @@ def __compute_via_kohel(self, xP, yP):
a = self.__phi(xP)
b = self.__omega(xP, yP)
c = self.__psi(xP)
cc = self.__mpoly_ring(c)

return (a/c**2, b/cc**3)
return (a/c**2, b/c**3)

def __initialize_rational_maps_via_kohel(self):
r"""
Expand All @@ -2595,7 +2650,7 @@ def __initialize_rational_maps_via_kohel(self):
"""
x = self.__poly_ring.gen()
y = self.__mpoly_ring.gen(1)
y = self.__xyfield.gen(1)
return self.__compute_via_kohel(x,y)

#
Expand Down
69 changes: 50 additions & 19 deletions src/sage/schemes/elliptic_curves/hom.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

from sage.categories.morphism import Morphism

import sage.schemes.elliptic_curves.weierstrass_morphism as wm


class EllipticCurveHom(Morphism):
"""
Expand Down Expand Up @@ -162,9 +164,11 @@ def degree(self):
r"""
Return the degree of this elliptic-curve morphism.
Implemented by child classes. For examples,
see :meth:`EllipticCurveIsogeny.degree` and
:meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.degree`.
Implemented by child classes. For examples, see:
- :meth:`EllipticCurveIsogeny.degree`
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.degree`
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.degree`
TESTS::
Expand All @@ -180,9 +184,11 @@ def kernel_polynomial(self):
r"""
Return the kernel polynomial of this elliptic-curve morphism.
Implemented by child classes. For examples,
see :meth:`EllipticCurveIsogeny.kernel_polynomial` and
:meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.kernel_polynomial`.
Implemented by child classes. For examples, see:
- :meth:`EllipticCurveIsogeny.kernel_polynomial`
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.kernel_polynomial`
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.kernel_polynomial`
TESTS::
Expand All @@ -198,9 +204,11 @@ def dual(self):
r"""
Return the dual of this elliptic-curve morphism.
Implemented by child classes. For examples,
see :meth:`EllipticCurveIsogeny.dual` and
:meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.dual`.
Implemented by child classes. For examples, see:
- :meth:`EllipticCurveIsogeny.dual`
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.dual`
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.dual`
TESTS::
Expand All @@ -218,9 +226,11 @@ def rational_maps(self):
elliptic-curve morphism as fractions of bivariate
polynomials in `x` and `y`.
Implemented by child classes. For examples,
see :meth:`EllipticCurveIsogeny.rational_maps` and
:meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.rational_maps`.
Implemented by child classes. For examples, see:
- :meth:`EllipticCurveIsogeny.rational_maps`
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.rational_maps`
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.rational_maps`
TESTS::
Expand All @@ -237,9 +247,11 @@ def x_rational_map(self):
Return the `x`-coordinate rational map of this elliptic-curve
morphism as a univariate rational expression in `x`.
Implemented by child classes. For examples,
see :meth:`EllipticCurveIsogeny.x_rational_map` and
:meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.x_rational_map`.
Implemented by child classes. For examples, see:
- :meth:`EllipticCurveIsogeny.x_rational_map`
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.x_rational_map`
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.x_rational_map`
TESTS::
Expand Down Expand Up @@ -448,7 +460,7 @@ def is_surjective(self):
sage: phi.is_surjective()
True
"""
return True
return bool(self.degree())

def is_injective(self):
r"""
Expand Down Expand Up @@ -477,9 +489,9 @@ def is_injective(self):
sage: phi.is_injective()
True
"""
# This will become wrong once purely inseparable isogenies
# are implemented. We should probably add something like a
# separable_degree() method then.
if not self.is_separable():
#TODO: should implement .separable_degree() or similar
raise NotImplementedError
return self.degree() == 1

def is_zero(self):
Expand All @@ -501,6 +513,25 @@ def is_zero(self):
"""
return not self.degree()

def __neg__(self):
r"""
Return the negative of this elliptic-curve morphism. In other
words, return `[-1]\circ\varphi` where `\varphi` is ``self``
and `[-1]` is the negation automorphism on the codomain curve.
EXAMPLES::
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
sage: E = EllipticCurve(GF(1019), [5,5])
sage: phi = E.isogeny(E.lift_x(73))
sage: f,g = phi.rational_maps()
sage: psi = EllipticCurveHom.__neg__(phi)
sage: psi.rational_maps() == (f, -g)
True
"""
a1,_,a3,_,_ = self.codomain().a_invariants()
return wm.WeierstrassIsomorphism(self.codomain(), (-1,0,-a1,-a3)) * self

@cached_method
def __hash__(self):
"""
Expand Down
Loading

0 comments on commit bdce391

Please sign in to comment.