Skip to content

Commit

Permalink
gh-37415: make EllipticCurvePoint_field inherit from EllipticCurvePoint
Browse files Browse the repository at this point in the history
    
The method `EllipticCurve_generic.__contains__()` checks for inheritance
from `EllipticCurvePoint`; however, the other classes for points on
elliptic curves do not inherit from this class.  This pull request fixes
this. Note that there is some overlap with #33228.

This change makes `P in E` much faster:
- Over **Q**:
```python
E = EllipticCurve('37a1')
P = E((0, -1))
%timeit P in E
```
Before: `35.3 µs ± 186 ns per loop (mean ± std. dev. of 7 runs, 10,000
loops each)`
After: `324 ns ± 0.535 ns per loop (mean ± std. dev. of 7 runs,
1,000,000 loops each)`

- Over a finite field:
```python
F.<a> = FiniteField((23, 2), modulus='random')
E = EllipticCurve_from_j(F.random_element())
P = E.random_point()
%timeit P in E
```
Before: `36.4 µs ± 542 ns per loop (mean ± std. dev. of 7 runs, 10,000
loops each)`
After: `333 ns ± 5.03 ns per loop (mean ± std. dev. of 7 runs, 1,000,000
loops each)`
    
URL: #37415
Reported by: Peter Bruin
Reviewer(s): Kwankyu Lee, Peter Bruin
  • Loading branch information
Release Manager committed May 23, 2024
2 parents 4a6edc3 + 051126d commit 5c0dd60
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 69 deletions.
10 changes: 2 additions & 8 deletions src/sage/schemes/elliptic_curves/ell_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,10 +456,7 @@ def __contains__(self, P):
P = self(P)
except TypeError:
return False
if P.curve() == self:
return True
x, y, a = P[0], P[1], self.ainvs()
return y**2 + a[0]*x*y + a[2]*y == x**3 + a[1]*x**2 + a[3]*x + a[4]
return P.curve() == self

def __call__(self, *args, **kwds):
r"""
Expand Down Expand Up @@ -572,10 +569,7 @@ def __call__(self, *args, **kwds):
P = args[0]
if isinstance(P, groups.AdditiveAbelianGroupElement) and isinstance(P.parent(),ell_torsion.EllipticCurveTorsionSubgroup):
return self(P.element())
if isinstance(args[0],
(ell_point.EllipticCurvePoint_field,
ell_point.EllipticCurvePoint_number_field,
ell_point.EllipticCurvePoint)):
if isinstance(args[0], ell_point.EllipticCurvePoint):
if P.curve() is self:
return P
# check if denominator of the point contains a factor of the
Expand Down
100 changes: 39 additions & 61 deletions src/sage/schemes/elliptic_curves/ell_point.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
r"""
Points on elliptic curves
The base class ``EllipticCurvePoint_field``, derived from
``AdditiveGroupElement``, provides support for points on elliptic
curves defined over general fields. The derived classes
``EllipticCurvePoint_number_field`` and
``EllipticCurvePoint_finite_field`` provide further support for point
on curves defined over number fields (including the rational field
The base class :class:`EllipticCurvePoint` currently provides little
functionality of its own. Its derived class
:class:`EllipticCurvePoint_field` provides support for points on
elliptic curves over general fields. The derived classes
:class:`EllipticCurvePoint_number_field` and
:class:`EllipticCurvePoint_finite_field` provide further support for
points on curves over number fields (including the rational field
`\QQ`) and over finite fields.
The class ``EllipticCurvePoint``, which is based on
``SchemeMorphism_point_projective_ring``, currently has little extra
functionality.
EXAMPLES:
An example over `\QQ`::
Expand Down Expand Up @@ -107,7 +104,6 @@
- Mariah Lenox (March 2011) -- Added ``tate_pairing`` and ``ate_pairing``
functions to ``EllipticCurvePoint_finite_field`` class
"""

# ****************************************************************************
Expand All @@ -134,6 +130,8 @@
from sage.rings.real_mpfr import RealField
from sage.rings.real_mpfr import RR
import sage.groups.generic as generic

from sage.structure.element import AdditiveGroupElement
from sage.structure.sequence import Sequence
from sage.structure.richcmp import richcmp

Expand All @@ -153,14 +151,41 @@
PariError = ()


class EllipticCurvePoint(SchemeMorphism_point_projective_ring):
class EllipticCurvePoint(AdditiveGroupElement,
SchemeMorphism_point_projective_ring):
"""
A point on an elliptic curve.
"""
pass
def curve(self):
"""
Return the curve that this point is on.
This is a synonym for :meth:`scheme`.
EXAMPLES::
class EllipticCurvePoint_field(SchemeMorphism_point_abelian_variety_field):
sage: E = EllipticCurve('389a')
sage: P = E([-1, 1])
sage: P.curve()
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
sage: E = EllipticCurve(QQ, [1, 1])
sage: P = E(0, 1)
sage: P.scheme()
Elliptic Curve defined by y^2 = x^3 + x + 1 over Rational Field
sage: P.scheme() == P.curve()
True
sage: x = polygen(ZZ, 'x')
sage: K.<a> = NumberField(x^2 - 3,'a') # needs sage.rings.number_field
sage: P = E.base_extend(K)(1, a) # needs sage.rings.number_field
sage: P.scheme() # needs sage.rings.number_field
Elliptic Curve defined by y^2 = x^3 + x + 1 over Number Field in a with defining polynomial x^2 - 3
"""
return self.scheme()


class EllipticCurvePoint_field(EllipticCurvePoint,
SchemeMorphism_point_abelian_variety_field):
"""
A point on an elliptic curve over a field. The point has coordinates
in the base field.
Expand Down Expand Up @@ -275,7 +300,6 @@ def __init__(self, curve, v, check=True):
v = (R.zero(), R.one(), R.zero())

SchemeMorphism_point_abelian_variety_field.__init__(self, point_homset, v, check=check)
# AdditiveGroupElement.__init__(self, point_homset)

self.normalize_coordinates()

Expand Down Expand Up @@ -426,39 +450,6 @@ def __pari__(self):
else:
return pari([0])

def scheme(self):
"""
Return the scheme of this point, i.e., the curve it is on.
This is synonymous with :meth:`curve` which is perhaps more
intuitive.
EXAMPLES::
sage: E = EllipticCurve(QQ,[1,1])
sage: P = E(0,1)
sage: P.scheme()
Elliptic Curve defined by y^2 = x^3 + x + 1 over Rational Field
sage: P.scheme() == P.curve()
True
sage: x = polygen(ZZ, 'x')
sage: K.<a> = NumberField(x^2 - 3,'a') # needs sage.rings.number_field
sage: P = E.base_extend(K)(1, a) # needs sage.rings.number_field
sage: P.scheme() # needs sage.rings.number_field
Elliptic Curve defined by y^2 = x^3 + x + 1
over Number Field in a with defining polynomial x^2 - 3
"""
# The following text is just not true: it applies to the class
# EllipticCurvePoint, which appears to be never used, but does
# not apply to EllipticCurvePoint_field which is simply derived
# from AdditiveGroupElement.
#
# "Technically, points on curves in Sage are scheme maps from
# the domain Spec(F) where F is the base field of the curve to
# the codomain which is the curve. See also domain() and
# codomain()."

return self.codomain()

def order(self):
r"""
Return the order of this point on the elliptic curve.
Expand Down Expand Up @@ -497,19 +488,6 @@ def order(self):

additive_order = order

def curve(self):
"""
Return the curve that this point is on.
EXAMPLES::
sage: E = EllipticCurve('389a')
sage: P = E([-1,1])
sage: P.curve()
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
"""
return self.scheme()

def __bool__(self):
"""
Return ``True`` if this is not the zero point on the curve.
Expand Down

0 comments on commit 5c0dd60

Please sign in to comment.