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

Commit

Permalink
11474: Make elliptic curves unique parents.
Browse files Browse the repository at this point in the history
  • Loading branch information
defeo committed Apr 18, 2014
1 parent 12bbca0 commit 8cbb73e
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 101 deletions.
8 changes: 7 additions & 1 deletion src/sage/databases/cremona.py
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,13 @@ def elliptic_curve(self, label):
+ "USING(class) WHERE curve=?",(label,))
try:
c = q.next()
F = elliptic.EllipticCurve(eval(c[0]))
from sage.all import QQ
from sage.structure.sequence import Sequence
from sage.schemes.elliptic_curves.ell_rational_field import EllipticCurve_rational_field
#F = elliptic.EllipticCurve(eval(c[0]))
F = EllipticCurve_rational_field.__new__(EllipticCurve_rational_field)
EllipticCurve_rational_field.__init__(F, QQ,
Sequence(eval(c[0]),universe=QQ,immutable=True))
F._set_cremona_label(label)
F._set_rank(c[1])
F._set_torsion_order(c[2])
Expand Down
90 changes: 73 additions & 17 deletions src/sage/schemes/elliptic_curves/constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
- William Stein (2005): Initial version
- John Cremona (2008-01): EllipticCurve(j) fixed for all cases
- Simon King (2011-06): Make elliptic curves unique parents (trac ticket #11474)
"""

#*****************************************************************************
Expand Down Expand Up @@ -90,15 +92,49 @@ def EllipticCurve(x=None, y=None, j=None, minimal_twist=True):
sage: EllipticCurve([0,0,1,-1,0])
Elliptic Curve defined by y^2 + y = x^3 - x over Rational Field
sage: EllipticCurve([0,0,1,-1,0]) is EllipticCurve([0,0,1,-1,0])
True
We create a curve from a Cremona label::
sage: EllipticCurve('37b2')
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field
sage: EllipticCurve('5077a')
sage: E = EllipticCurve('5077a'); E
Elliptic Curve defined by y^2 + y = x^3 - 7*x + 6 over Rational Field
sage: EllipticCurve('389a')
Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field
Note that elliptic curves almost are unique parent structures, by trac
ticket #11461: Two elliptic curves have equal `a`-invariants and are defined
over the same field then they are not only equal but identical::
sage: E is EllipticCurve('5077a') is EllipticCurve(QQ, E.a_invariants()) is EllipticCurve(j = E.j_invariant())
True
The only exception can occur if an elliptic curve is equal to a
curve from the database: If an elliptic curve found in the cache
has data that are different from the data provided by the
database, then the two elliptic curves are equal but distinct::
sage: E = EllipticCurve([0, 1, 1, -2, 0])
sage: E is EllipticCurve('389a')
True
sage: E._EllipticCurve_rational_field__cremona_label = 'bogus'
sage: E is EllipticCurve('389a')
False
sage: E.label()
'bogus'
sage: EllipticCurve('389a').label()
'389a1'
However, attributes that are provided by the database are
automatically added to the curve found in the cache, if these
attributes have not been previously assigned.
::
sage: del E._EllipticCurve_rational_field__cremona_label
sage: E is EllipticCurve('389a')
True
sage: E._EllipticCurve_rational_field__cremona_label
'389 a 1'
Old Cremona labels are allowed::
Expand All @@ -114,16 +150,20 @@ def EllipticCurve(x=None, y=None, j=None, minimal_twist=True):
sage: EllipticCurve([GF(5)(0),0,1,-1,0])
Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5
sage: EllipticCurve(GF(5), [0, 0,1,-1,0])
Elliptic Curve defined by y^2 + y = x^3 + 4*x over Finite Field of size 5
The same object can be obtained by providing the data in a slightly
different way::
sage: EllipticCurve([GF(5)(0),0,1,-1,0]) is EllipticCurve(GF(5), [0, 0,1,-1,0])
True
Elliptic curves over `\ZZ/N\ZZ` with `N` prime are of type
"elliptic curve over a finite field"::
sage: F = Zmod(101)
sage: EllipticCurve(F, [2, 3])
sage: E = EllipticCurve(F, [2, 3]); E
Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 101
sage: E = EllipticCurve([F(2), F(3)])
sage: E is EllipticCurve([F(2), F(3)])
sage: type(E)
<class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field_with_category'>
sage: E.category()
Expand All @@ -133,9 +173,10 @@ def EllipticCurve(x=None, y=None, j=None, minimal_twist=True):
are of type "generic elliptic curve"::
sage: F = Zmod(95)
sage: EllipticCurve(F, [2, 3])
sage: E = EllipticCurve(F, [2, 3]); E
Elliptic Curve defined by y^2 = x^3 + 2*x + 3 over Ring of integers modulo 95
sage: E = EllipticCurve([F(2), F(3)])
sage: E is EllipticCurve([F(2), F(3)])
True
sage: type(E)
<class 'sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic_with_category'>
sage: E.category()
Expand All @@ -149,26 +190,41 @@ def EllipticCurve(x=None, y=None, j=None, minimal_twist=True):
sage: E.j_invariant()
2988.97297297297
We can also create elliptic curves by giving the Weierstrass equation::
We can also create elliptic curves by giving the Weierstrass equation, and again
we find that elliptic curves are unique::
sage: x, y = var('x,y')
sage: EllipticCurve(y^2 + y == x^3 + x - 9)
sage: E = EllipticCurve(y^2 + y == x^3 + x - 9); E
Elliptic Curve defined by y^2 + y = x^3 + x - 9 over Rational Field
sage: E is EllipticCurve(E.base_ring(), E.a_invariants())
True
sage: R.<x,y> = GF(5)[]
sage: EllipticCurve(x^3 + x^2 + 2 - y^2 - y*x)
sage: E = EllipticCurve(x^3 + x^2 + 2 - y^2 - y*x); E
Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 2 over Finite Field of size 5
sage: E is EllipticCurve(E.base_ring(), E.a_invariants())
True
We can explicitly specify the `j`-invariant::
We can explicitly specify the `j`-invariant, again in a unique way::
sage: E = EllipticCurve(j=1728); E; E.j_invariant(); E.label()
sage: E = EllipticCurve(j=1728); E; E.j_invariant(); E.a_invariants(); E.label()
Elliptic Curve defined by y^2 = x^3 - x over Rational Field
1728
(0, 0, 0, -1, 0)
'32a2'
sage: E is EllipticCurve(E.base_ring(), E.a_invariants())
True
sage: E is EllipticCurve(E.label())
True
sage: E is EllipticCurve(j = E.j_invariant())
True
::
sage: E = EllipticCurve(j=GF(5)(2)); E; E.j_invariant()
Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5
2
sage: E is EllipticCurve(E.base_ring(), E.a_invariants())
True
See :trac:`6657` ::
Expand Down
37 changes: 27 additions & 10 deletions src/sage/schemes/elliptic_curves/ell_finite_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
import sage.groups.generic as generic
import ell_point
from sage.rings.arith import gcd, lcm
from sage.structure.sequence import Sequence
from sage.structure.sequence import Sequence, Sequence_generic

import sage.plot.all as plot

Expand All @@ -51,10 +51,33 @@ class EllipticCurve_finite_field(EllipticCurve_field, HyperellipticCurve_finite_
"""
Elliptic curve over a finite field.
"""
def __init__(self, x, y=None):
@staticmethod
def __classcall__(cls, x, y=None):
"""
Special constructor for elliptic curves over a finite field
Preprocess arguments such as to obtain a unique descriptor.
TESTS::
sage: E = EllipticCurve(GF(101),[2,3])
sage: type(E)
<class 'sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field'>
sage: E is EllipticCurve(E.base_ring(), E.a_invariants()) # indirect doctest
True
"""
if y is None:
if isinstance(x, Sequence_generic) and x.is_immutable():
ainvs = x
else:
ainvs = Sequence(x, immutable=True)
else:
ainvs = Sequence(y, universe=x, immutable=True)
return super(EllipticCurve_finite_field, cls).__classcall__(cls, ainvs.universe(), ainvs)

def __init__(self, field, ainvs):
"""
Special constructor for elliptic curves over a finite field
EXAMPLES::
sage: EllipticCurve(GF(101),[2,3])
Expand Down Expand Up @@ -91,16 +114,10 @@ def __init__(self, x, y=None):
Category of schemes over Ring of integers modulo 95
sage: TestSuite(E).run(skip=["_test_elements"])
"""
if isinstance(x, list):
seq = Sequence(x)
else:
seq = Sequence(y, universe=x)
ainvs = list(seq)
field = seq.universe()
if not isinstance(field, ring.Ring):
raise TypeError

EllipticCurve_field.__init__(self, ainvs)
EllipticCurve_field.__init__(self, field, ainvs)

self._point = ell_point.EllipticCurvePoint_finite_field

Expand Down
42 changes: 30 additions & 12 deletions src/sage/schemes/elliptic_curves/ell_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
import formal_group
import weierstrass_morphism as wm

from sage.structure.sequence import Sequence, Sequence_generic
from sage.structure.unique_representation import UniqueRepresentation

factor = arith.factor
sqrt = math.sqrt
Expand Down Expand Up @@ -97,7 +99,7 @@ def is_EllipticCurve(x):
"""
return isinstance(x, EllipticCurve_generic)

class EllipticCurve_generic(plane_curve.ProjectiveCurve_generic):
class EllipticCurve_generic(UniqueRepresentation, plane_curve.ProjectiveCurve_generic):
r"""
Elliptic curve over a generic base ring.
Expand All @@ -112,14 +114,38 @@ class EllipticCurve_generic(plane_curve.ProjectiveCurve_generic):
sage: -5*P
(179051/80089 : -91814227/22665187 : 1)
"""
def __init__(self, ainvs, extra=None):
@staticmethod
def __classcall__(cls, ainvs, extra=None):
"""
Preprocess arguments such as to obtain a unique descriptor.
TESTS::
sage: E = EllipticCurve(IntegerModRing(91),[1,2,3,4,5])
sage: type(E)
<class 'sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic'>
sage: E is EllipticCurve(E.base_ring(), E.a_invariants()) # indirect doctest
True
"""
if extra != None: # possibility of two arguments
K, ainvs = ainvs, extra
else:
K = ainvs[0].parent()
assert len(ainvs) == 2 or len(ainvs) == 5
if len(ainvs) == 2:
ainvs = [K(0),K(0),K(0)] + ainvs
if not (isinstance(ainvs,Sequence_generic) and ainvs.is_immutable()):
ainvs = Sequence(ainvs, universe=K, immutable=True)
return super(EllipticCurve_generic,cls).__classcall__(cls, K, ainvs)

def __init__(self, K, ainvs):
r"""
Constructor from `a`-invariants (long or short Weierstrass coefficients).
INPUT:
- ``ainvs`` (list) -- either `[a_1,a_2,a_3,a_4,a_6]` or
`[a_4,a_6]` (with `a_1=a_2=a_3=0` in the second case).
- ``ainvs`` (immutable Sequence) -- `[a_1,a_2,a_3,a_4,a_6]`
.. note::
Expand All @@ -142,15 +168,7 @@ def __init__(self, ainvs, extra=None):
sage: EllipticCurve(IntegerModRing(91),[1,2,3,4,5])
Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Ring of integers modulo 91
"""
if extra != None: # possibility of two arguments
K, ainvs = ainvs, extra
else:
K = ainvs[0].parent()
assert len(ainvs) == 2 or len(ainvs) == 5
self.__base_ring = K
ainvs = [K(x) for x in ainvs]
if len(ainvs) == 2:
ainvs = [K(0),K(0),K(0)] + ainvs
self.__ainvs = tuple(ainvs)
if self.discriminant() == 0:
raise ArithmeticError, \
Expand Down
51 changes: 32 additions & 19 deletions src/sage/schemes/elliptic_curves/ell_number_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@
from sage.misc.misc import verbose, forall
from sage.rings.integer import Integer
from sage.rings.arith import valuation

import gal_reps_number_field
from sage.structure.sequence import Sequence

class EllipticCurve_number_field(EllipticCurve_field):
r"""
Expand All @@ -119,7 +119,36 @@ class EllipticCurve_number_field(EllipticCurve_field):
sage: EllipticCurve([i, i - 1, i + 1, 24*i + 15, 14*i + 35])
Elliptic Curve defined by y^2 + i*x*y + (i+1)*y = x^3 + (i-1)*x^2 + (24*i+15)*x + (14*i+35) over Number Field in i with defining polynomial x^2 + 1
"""
def __init__(self, x, y=None):
@staticmethod
def __classcall__(cls, x, y=None):
"""
Preprocess arguments such as to obtain a unique descriptor.
TESTS::
sage: K.<i>=NumberField(x^2+1)
sage: E = EllipticCurve([i, i - 1, i + 1, 24*i + 15, 14*i + 35])
sage: E is EllipticCurve(E.base_ring(),E.a_invariants()) # indirect doctest
True
"""
if y is None:
if isinstance(x, (list,tuple)):
field = x[0].parent()
ainvs = Sequence(x, universe=field, immutable=True)
else:
if isinstance(y, str):
field = x
X = sage.databases.cremona.CremonaDatabase()[y]
ainvs = Sequence(X.a_invariants(), universe=field, immutable=True)
else:
field = x
ainvs = Sequence(y, universe=field, immutable=True)
if not (isinstance(field, Ring)):
raise TypeError, "Can not determine the ring for that elliptic curve"
return super(EllipticCurve_number_field,cls).__classcall__(cls, field, ainvs)

def __init__(self, K, ainvs):
r"""
Allow some ways to create an elliptic curve over a number
field in addition to the generic ones.
Expand All @@ -142,23 +171,7 @@ def __init__(self, x, y=None):
Elliptic Curve defined by y^2 + y = x^3 + (-1)*x^2 over Number Field in i with defining polynomial x^2 + 1
"""
if y is None:
if isinstance(x, list):
ainvs = x
field = ainvs[0].parent()
else:
if isinstance(y, str):
from sage.databases.cremona import CremonaDatabase
field = x
X = CremonaDatabase()[y]
ainvs = list(X.a_invariants())
else:
field = x
ainvs = y
if not (isinstance(field, Ring) and isinstance(ainvs,list)):
raise TypeError

EllipticCurve_field.__init__(self, [field(x) for x in ainvs])
EllipticCurve_field.__init__(self, K, ainvs)
self._point = ell_point.EllipticCurvePoint_number_field

def simon_two_descent(self, verbose=0, lim1=2, lim3=4, limtriv=2, maxprob=20, limbigprime=30):
Expand Down
Loading

0 comments on commit 8cbb73e

Please sign in to comment.