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

Commit

Permalink
implement more flexible comparison for EllipticCurveHom children incl…
Browse files Browse the repository at this point in the history
…uding √élu
  • Loading branch information
yyyyx4 committed Aug 21, 2022
1 parent 8bdcd45 commit 1e80198
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 45 deletions.
48 changes: 39 additions & 9 deletions src/sage/schemes/elliptic_curves/hom.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"""

from sage.misc.cachefunc import cached_method
from sage.structure.richcmp import richcmp_not_equal, richcmp
from sage.structure.richcmp import richcmp_not_equal, richcmp, op_EQ, op_NE

from sage.categories.morphism import Morphism

Expand Down Expand Up @@ -97,13 +97,29 @@ def _composition_(self, other, homset):
return Morphism._composition_(self, other, homset)


@staticmethod
def _comparison_impl(left, right, op):
"""
Called by :meth:`_richcmp_`.
TESTS::
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
sage: EllipticCurveHom._comparison_impl(None, None, None)
NotImplemented
"""
return NotImplemented

def _richcmp_(self, other, op):
r"""
Compare :class:`EllipticCurveHom` objects.
ALGORITHM:
This method compares domains, codomains, and :meth:`rational_maps`.
The method first makes sure that domain, codomain and degree match.
Then, it determines if there is a specialized comparison method by
trying :meth:`_comparison_impl` on either input. If not, it falls
back to comparing :meth:`rational_maps`.
EXAMPLES::
Expand Down Expand Up @@ -144,14 +160,16 @@ def _richcmp_(self, other, op):
.. SEEALSO::
:func:`compare_via_evaluation`
- :meth:`_comparison_impl`
- :func:`compare_via_evaluation`
"""
# We cannot just compare kernel polynomials, as was done until
# Trac #11327, as then phi and -phi compare equal, and
# similarly with phi and any composition of phi with an
# automorphism of its codomain, or any post-isomorphism.
# Comparing domains, codomains and rational maps seems much
# safer.
if not isinstance(self, EllipticCurveHom) or not isinstance(other, EllipticCurveHom):
raise TypeError(f'cannot compare {type(self)} to {type(other)}')

if op == op_NE:
return not self._richcmp_(other, op_EQ)

# We first compare domain, codomain, and degree; cf. Trac #11327

lx, rx = self.domain(), other.domain()
if lx != rx:
Expand All @@ -165,6 +183,18 @@ def _richcmp_(self, other, op):
if lx != rx:
return richcmp_not_equal(lx, rx, op)

# Do self or other have specialized comparison methods?

ret = self._comparison_impl(self, other, op)
if ret is not NotImplemented:
return ret

ret = other._comparison_impl(self, other, op)
if ret is not NotImplemented:
return ret

# If not, fall back to comparing rational maps; cf. Trac #11327

return richcmp(self.rational_maps(), other.rational_maps(), op)


Expand Down
28 changes: 11 additions & 17 deletions src/sage/schemes/elliptic_curves/hom_composite.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
documentation and tests, equality testing
"""

from sage.structure.richcmp import op_EQ, op_NE
from sage.structure.richcmp import op_EQ
from sage.misc.cachefunc import cached_method
from sage.structure.sequence import Sequence

Expand Down Expand Up @@ -480,6 +480,8 @@ def factors(self):
return self._phis


# EllipticCurveHom methods

@staticmethod
def _composition_impl(left, right):
"""
Expand Down Expand Up @@ -528,24 +530,20 @@ def _composition_impl(left, right):
return EllipticCurveHom_composite.from_factors(right.factors() + (left,))
return NotImplemented


# EllipticCurveHom methods

def _richcmp_(self, other, op):
@staticmethod
def _comparison_impl(left, right, op):
r"""
Compare this composite isogeny to another elliptic-curve morphism.
Compare a composite isogeny to another elliptic-curve morphism.
Called by :meth:`EllipticCurveHom._richcmp_`.
ALGORITHM:
If possible, we use
:func:`~sage.schemes.elliptic_curves.hom.compare_via_evaluation`
:func:`~sage.schemes.elliptic_curves.hom.compare_via_evaluation`.
The complexity in that case is polynomial in the representation
size of this morphism.
Over more general base fields, we fall back to comparing the
results of :meth:`rational_maps`, which takes time at least
linear in the degree.
TESTS::
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
Expand All @@ -570,16 +568,12 @@ def _richcmp_(self, other, op):
sage: phi2 * phi1 == psi2 * psi1
True
"""
if op == op_NE:
return not self._richcmp_(other, op_EQ)
if op != op_EQ:
return NotImplemented

try:
return compare_via_evaluation(self, other)
return compare_via_evaluation(left, right)
except NotImplementedError:
# fall back to generic method
return self.rational_maps() == other.rational_maps()
return NotImplemented

def rational_maps(self):
"""
Expand Down
44 changes: 38 additions & 6 deletions src/sage/schemes/elliptic_curves/hom_velusqrt.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,8 @@
However, they are certainly separable isogenies with the same kernel
and must therefore be equal *up to post-isomorphism*::
sage: sum(iso * psi == phi for iso in isos) # TODO: comparison is not implemented yet
1
sage: Q = E.gens()[0]
sage: phiQ, psiQ = phi(Q), psi(Q)
sage: isos = psi.codomain().isomorphisms(phi.codomain())
sage: sum(iso(psiQ) == phiQ for iso in isos)
sage: sum(iso * psi == phi for iso in isos)
1
Just like
Expand Down Expand Up @@ -140,9 +136,11 @@

from sage.misc.misc_c import prod

from sage.structure.richcmp import op_EQ

from sage.schemes.elliptic_curves.constructor import EllipticCurve
from sage.schemes.elliptic_curves.ell_finite_field import EllipticCurve_finite_field
from sage.schemes.elliptic_curves.hom import EllipticCurveHom
from sage.schemes.elliptic_curves.hom import EllipticCurveHom, compare_via_evaluation

from sage.misc.superseded import experimental_warning
experimental_warning(34303, 'This module is experimental.')
Expand Down Expand Up @@ -1107,6 +1105,40 @@ def _repr_(self):
f'\n From: {self._domain}' \
f'\n To: {self._codomain}'

@staticmethod
def _comparison_impl(left, right, op):
r"""
Compare a Îlu isogeny to another elliptic-curve morphism.
Called by :meth:`EllipticCurveHom._richcmp_`.
INPUT:
- ``left, right`` -- :class:`~sage.schemes.elliptic_curves.hom.EllipticCurveHom` objects
ALGORITHM:
:func:`~sage.schemes.elliptic_curves.hom.compare_via_evaluation`
EXAMPLES::
sage: from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt
sage: E = EllipticCurve(GF(101), [5,5,5,5,5])
sage: phi = EllipticCurveHom_velusqrt(E, E.lift_x(11)); phi
Elliptic-curve isogeny (using Îlu) of degree 59:
From: Elliptic Curve defined by y^2 + 5*x*y + 5*y = x^3 + 5*x^2 + 5*x + 5 over Finite Field of size 101
To: Elliptic Curve defined by y^2 = x^3 + 15*x + 25 over Finite Field of size 101
sage: psi = EllipticCurveHom_velusqrt(E, E.lift_x(-1)); psi
Elliptic-curve isogeny (using Îlu) of degree 59:
From: Elliptic Curve defined by y^2 + 5*x*y + 5*y = x^3 + 5*x^2 + 5*x + 5 over Finite Field of size 101
To: Elliptic Curve defined by y^2 = x^3 + 15*x + 25 over Finite Field of size 101
sage: phi == psi
True
"""
if op != op_EQ:
return NotImplemented
return compare_via_evaluation(left, right)


def _random_example_for_testing():
r"""
Expand Down
29 changes: 16 additions & 13 deletions src/sage/schemes/elliptic_curves/weierstrass_morphism.py
Original file line number Diff line number Diff line change
Expand Up @@ -534,9 +534,12 @@ def __init__(self, E=None, urst=None, F=None):
self._degree = Integer(1)
EllipticCurveHom.__init__(self, self._domain, self._codomain)

def _richcmp_(self, other, op):
@staticmethod
def _comparison_impl(left, right, op):
r"""
Standard comparison function for the WeierstrassIsomorphism class.
Compare an isomorphism to another elliptic-curve morphism.
Called by :meth:`EllipticCurveHom._richcmp_`.
EXAMPLES::
Expand All @@ -562,20 +565,20 @@ def _richcmp_(self, other, op):
sage: a == c
True
"""
if isinstance(other, WeierstrassIsomorphism):
lx = self._domain
rx = other._domain
if lx != rx:
return richcmp_not_equal(lx, rx, op)
if not isinstance(left, WeierstrassIsomorphism) or not isinstance(right, WeierstrassIsomorphism):
return NotImplemented

lx = self._codomain
rx = other._codomain
if lx != rx:
return richcmp_not_equal(lx, rx, op)
lx = left._domain
rx = right._domain
if lx != rx:
return richcmp_not_equal(lx, rx, op)

return baseWI.__richcmp__(self, other, op)
lx = left._codomain
rx = right._codomain
if lx != rx:
return richcmp_not_equal(lx, rx, op)

return EllipticCurveHom._richcmp_(self, other, op)
return baseWI.__richcmp__(left, right, op)

def _eval(self, P):
r"""
Expand Down

0 comments on commit 1e80198

Please sign in to comment.