From 1e80198ddfd554ab358d88b5740dee3ab20e02a9 Mon Sep 17 00:00:00 2001 From: Lorenz Panny Date: Sun, 21 Aug 2022 07:40:16 +0800 Subject: [PATCH] =?UTF-8?q?implement=20more=20flexible=20comparison=20for?= =?UTF-8?q?=20EllipticCurveHom=20children=20including=20=E2=88=9A=C3=A9lu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/schemes/elliptic_curves/hom.py | 48 +++++++++++++++---- .../schemes/elliptic_curves/hom_composite.py | 28 +++++------ .../schemes/elliptic_curves/hom_velusqrt.py | 44 ++++++++++++++--- .../elliptic_curves/weierstrass_morphism.py | 29 ++++++----- 4 files changed, 104 insertions(+), 45 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index 02432c44892..8d707e8e6b7 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -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 @@ -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:: @@ -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: @@ -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) diff --git a/src/sage/schemes/elliptic_curves/hom_composite.py b/src/sage/schemes/elliptic_curves/hom_composite.py index 62ca45a2af6..32b1fa9e0bb 100644 --- a/src/sage/schemes/elliptic_curves/hom_composite.py +++ b/src/sage/schemes/elliptic_curves/hom_composite.py @@ -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 @@ -480,6 +480,8 @@ def factors(self): return self._phis + # EllipticCurveHom methods + @staticmethod def _composition_impl(left, right): """ @@ -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 @@ -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): """ diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index fdb78ce9a33..70b03ccfe28 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -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 @@ -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.') @@ -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""" diff --git a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py index ca5931fbd62..33549debee1 100644 --- a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py @@ -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:: @@ -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"""