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

Commit

Permalink
move comparison by evaluation up from hom_composite.py to hom.py
Browse files Browse the repository at this point in the history
  • Loading branch information
yyyyx4 committed Aug 21, 2022
1 parent 9f9a77c commit 8bdcd45
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 44 deletions.
78 changes: 78 additions & 0 deletions src/sage/schemes/elliptic_curves/hom.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@

from sage.categories.morphism import Morphism

from sage.arith.misc import integer_floor

from sage.rings.finite_rings import finite_field_base
from sage.rings.number_field import number_field_base


class EllipticCurveHom(Morphism):
"""
Expand Down Expand Up @@ -136,6 +141,10 @@ def _richcmp_(self, other, op):
[True, True]
sage: [a == b for a in (wE,mE) for b in (wF,mF)]
[False, False, False, False]
.. SEEALSO::
:func:`compare_via_evaluation`
"""
# We cannot just compare kernel polynomials, as was done until
# Trac #11327, as then phi and -phi compare equal, and
Expand Down Expand Up @@ -621,3 +630,72 @@ def __hash__(self):
Isogeny of degree 7 from Elliptic Curve defined by y^2 + x*y = x^3 - x^2 - 107*x + 552 over Rational Field to Elliptic Curve defined by y^2 + x*y = x^3 - x^2 - 5252*x - 178837 over Rational Field
"""
return hash((self.domain(), self.codomain(), self.kernel_polynomial()))


def compare_via_evaluation(left, right):
r"""
Test if two elliptic-curve morphisms are equal by evaluating
them at enough points.
INPUT:
- ``left``, ``right`` -- :class:`EllipticCurveHom` objects
ALGORITHM:
We use the fact that two isogenies of equal degree `d` must be
the same if and only if they behave identically on more than
`4d` points. (It suffices to check this on a few points that
generate a large enough subgroup.)
If the domain curve does not have sufficiently many rational
points, the base field is extended first: Taking an extension
of degree `O(\log(d))` suffices.
EXAMPLES::
sage: E = EllipticCurve(GF(83), [1,0])
sage: phi = E.isogeny(12*E.0, model='montgomery'); phi
Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 83 to Elliptic Curve defined by y^2 = x^3 + 70*x^2 + x over Finite Field of size 83
sage: psi = phi.dual(); psi
Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 70*x^2 + x over Finite Field of size 83 to Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 83
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
sage: mu = EllipticCurveHom_composite.from_factors([phi, psi])
sage: from sage.schemes.elliptic_curves.hom import compare_via_evaluation
sage: compare_via_evaluation(mu, E.multiplication_by_m_isogeny(7))
True
.. SEEALSO::
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite._richcmp_`
"""
if left.domain() != right.domain():
return False
if left.codomain() != right.codomain():
return False
if left.degree() != right.degree():
return False

E = left.domain()
F = E.base_ring()

if isinstance(F, finite_field_base.FiniteField):
q = F.cardinality()
d = left.degree()
e = integer_floor(1 + 2 * (2*d.sqrt() + 1).log(q)) # from Hasse bound
e = next(i for i,n in enumerate(E.count_points(e+1), 1) if n > 4*d)
EE = E.base_extend(F.extension(e))
Ps = EE.gens()
return all(left._eval(P) == right._eval(P) for P in Ps)

elif isinstance(F, number_field_base.NumberField):
for _ in range(100):
P = E.lift_x(F.random_element(), extend=True)
if not P.has_finite_order():
return left._eval(P) == right._eval(P)
else:
assert False, "couldn't find a point of infinite order"

else:
raise NotImplementedError('not implemented for this base field')

53 changes: 9 additions & 44 deletions src/sage/schemes/elliptic_curves/hom_composite.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,10 @@
from sage.misc.cachefunc import cached_method
from sage.structure.sequence import Sequence

from sage.arith.misc import prod, integer_floor
from sage.functions.log import log
from sage.functions.other import sqrt

from sage.rings.finite_rings import finite_field_base
from sage.rings.number_field import number_field_base
from sage.arith.misc import prod

from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic
from sage.schemes.elliptic_curves.hom import EllipticCurveHom
from sage.schemes.elliptic_curves.hom import EllipticCurveHom, compare_via_evaluation
from sage.schemes.elliptic_curves.ell_curve_isogeny import EllipticCurveIsogeny
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism

Expand Down Expand Up @@ -542,15 +537,10 @@ def _richcmp_(self, other, op):
ALGORITHM:
Over finite fields and number fields, we use the fact that two
isogenies of equal degree `d` are the same if and only if they
act identically on more than `4d` points. (It suffices to check
this on a few points that generate a large enough subgroup.)
If the domain curve does not have sufficiently many rational
points, the base field is extended first. Since an extension of
degree `O(\log(d))` suffices, the complexity is polynomial in
the representation size of this morphism.
If possible, we use
: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
Expand Down Expand Up @@ -585,34 +575,9 @@ def _richcmp_(self, other, op):
if op != op_EQ:
return NotImplemented

if self.domain() != other.domain():
return False
if self.codomain() != other.codomain():
return False
if self.degree() != other.degree():
return False

E = self.domain()
F = E.base_ring()

if isinstance(F, finite_field_base.FiniteField):
q = F.cardinality()
d = self.degree()
e = integer_floor(1 + 2 * log(2*sqrt(d) + 1, q)) # from Hasse bound
e = next(i for i,n in enumerate(E.count_points(e+1), 1) if n > 4*d)
EE = E.base_extend(F.extension(e))
Ps = EE.gens()
return all(self._eval(P) == other._eval(P) for P in Ps)

elif isinstance(F, number_field_base.NumberField):
for _ in range(100):
P = E.lift_x(F.random_element(), extend=True)
if not P.has_finite_order():
return self._eval(P) == other._eval(P)
else:
assert False, "_richcmp_() couldn't find a point of infinite order"

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

Expand Down

0 comments on commit 8bdcd45

Please sign in to comment.