# Ticket #12768: 12768.patch

File 12768.patch, 68.6 KB (added by roed, 10 years ago)

• ## sage/databases/cremona.py

```# HG changeset patch
# User David Roe <roed.math@gmail.com>
# Date 1333666108 25200
# Node ID 78ede397675813442c5a0afbe082faa16cd95edb
# Parent  bcf3992cc582036a4668e3541bb6e59b1db7a4d3
#12768: new class for isogeny classes of elliptic curves.  Better plotting for the graph.

diff --git a/sage/databases/cremona.py b/sage/databases/cremona.py```
 a label = chr(k)*int(n//26 + 1) return label cremona_label_regex = re.compile(r'(\d+)([a-z]*)(\d*)') lmfdb_label_regex = re.compile(r'(\d+)\.([a-z]+)(\d*)') def parse_cremona_label(label): """ Given a Cremona label that defines an elliptic curve, e.g., 11A1 or 37B3, parse the label and return the curve, e.g., 11a1 or 37b3, parse the label and return the conductor, isogeny class label, and number. The isogeny number may be omitted, in which case it defaults to 1. If the isogeny number and letter are both omitted, so label is just a string representing a conductor, then the label defaults to 'A' and the number to 1. For this function, the curve number may be omitted, in which case it defaults to 1.  If the curve number and isogeny class are both omitted (label is just a string representing a conductor), then the isogeny class defaults to 'a' and the number to 1. INPUT: sage: parse_cremona_label('10bb2') (10, 'bb', 2) """ if not isinstance(label, str): label = str(label) i=0 while i='0' and label[i]<='9': i += 1 j=i+1 if j>len(label): label += "a" while j='0' and label[j]<='9'): j += 1 if j>=len(label): label += "1" conductor, iso, num = int(label[:i]), label[i:j], int(label[j:]) return conductor, iso, num m = cremona_label_regex.match(str(label).lower()) if m is None: raise ValueError(label + " is not a valid Cremona label") conductor, iso, num = m.groups() if len(iso) == 0: iso = "a" if len(num) == 0: num = "1" return int(conductor), iso, int(num) def parse_lmfdb_label(label): """ Given an LMFDB label that defines an elliptic curve, e.g., 11.a1 or 37.b3, parse the label and return the conductor, isogeny class label, and number. The LMFDB label (named after the L-functions and modular forms database), is determined by the following two orders: - Isogeny classes with the same conductor are ordered lexicographically by the coefficients in the q-expansion of the associated modular form. - Curves within the same isogeny class are ordered lexicographically by the a-invariants of the minimal model. The format is ., where the isogeny class is encoded using the same base-26 encoding into letters used in Cremona's labels.  For example, 990.h3 is the same as Cremona's 990j1 For this function, the curve number may be omitted, in which case it defaults to 1.  If the curve number and isogeny class are both omitted (label is just a string representing a conductor), then the isogeny class defaults to 'a' and the number to 1. INPUT: -  ``label`` - str OUTPUT: -  ``int`` - the conductor -  ``str`` - the isogeny class label -  ``int`` - the number EXAMPLES:: sage: from sage.databases.cremona import parse_lmfdb_label sage: parse_cremona_label('37.a2') (37, 'a', 2) sage: parse_cremona_label('37.b') (37, 'b', 1) sage: parse_cremona_label('10.bb2') (10, 'bb', 2) """ m = lmfdb_label_regex.match(str(label).lower()) if m is None: raise ValueError(label + " is not a valid LMFDB label") conductor, iso, num = m.groups() if len(iso) == 0: iso = "a" if len(num) == 0: num = "1" return int(conductor), iso, int(num) def split_code(key): """ if d!=0:  return d return cmp(cu1,cu2) def cremona_to_lmfdb(cremona_label, CDB=None): """ Converts a Cremona label into an LMFDB label. See :func:`parse_lmfdb_label` for an explanation of LMFDB labels. INPUT: - ``cremona_label`` -- a string, the Cremona label of a curve. This can be the label of a curve (e.g. '990j1') or of an isogeny class (e.g. '990j') - ``CDB`` -- the Cremona database in which to look up the isogeny classes of the same conductor. OUTPUT: - ``lmfdb_label`` -- a string, the corresponding LMFDB label. EXAMPLES:: sage: from sage.databases.cremona import cremona_to_lmfdb, lmfdb_to_cremona sage: cremona_to_lmfdb('990j1') '990.h3' sage: lmfdb_to_cremona('990.h3') '990j1' TESTS:: sage: for label in ['5077a1','66a3','102b','420c2']: ...       assert(lmfdb_to_cremona(cremona_to_lmfdb(label)) == label) sage: for label in ['438.c2','306.b','462.f3']: ...       assert(cremona_to_lmfdb(lmfdb_to_cremona(label)) == label) """ from sage.libs.pari.all import pari m = cremona_label_regex.match(cremona_label) if m is None: raise ValueError("Invalid Cremona label") N, cremona_iso, cremona_number = m.groups() if CDB is None: CDB = CremonaDatabase() classes = CDB.isogeny_classes(N) ft = int(53) tff = int(255) # This should be enough to distinguish between curves (using heuristics from Sato-Tate for example) isos = [] for i, iso in enumerate(classes): alist = iso E = pari(alist).ellinit(precision=ft) isos.append((E.ellan(tff, python_ints=True), cremona_letter_code(i))) isos.sort() sorted_letters = [iso for iso in isos] lmfdb_iso = cremona_letter_code(sorted_letters.index(cremona_iso)) if len(cremona_number) > 0: iso_class = [(curve,str(i+1)) for i,curve in enumerate(classes[class_to_int(cremona_iso)])] iso_class.sort() sorted_numbers = [curve for curve in iso_class] lmfdb_number = str(sorted_numbers.index(cremona_number)+1) return N + '.' + lmfdb_iso + lmfdb_number else: return N + '.' + lmfdb_iso def lmfdb_to_cremona(lmfdb_label, CDB=None): """ Converts an LMFDB labe into a Cremona label. See :func:`parse_lmfdb_label` for an explanation of LMFDB labels. INPUT: - ``lmfdb_label`` -- a string, the LMFDB label of a curve. This can be the label of a curve (e.g. '990.j1') or of an isogeny class (e.g. '990.j') - ``CDB`` -- the Cremona database in which to look up the isogeny classes of the same conductor. OUTPUT: - ``cremona_label`` -- a string, the corresponding Cremona label. EXAMPLES:: sage: from sage.databases.cremona import cremona_to_lmfdb, lmfdb_to_cremona sage: lmfdb_to_cremona('990.h3') '990j1' sage: cremona_to_lmfdb('990j1') '990.h3' """ from sage.libs.pari.all import pari m = lmfdb_label_regex.match(lmfdb_label) if m is None: raise ValueError("Invalid LMFDB label") N, lmfdb_iso, lmfdb_number = m.groups() if CDB is None: CDB = CremonaDatabase() classes = CDB.isogeny_classes(N) ft = int(53) tff = int(255) # This should be enough to distinguish between curves (using heuristics from Sato-Tate for example) isos = [] for i, iso in enumerate(classes): alist = iso E = pari(alist).ellinit(precision=ft) isos.append((E.ellan(tff, python_ints=True), cremona_letter_code(i))) isos.sort() cremona_iso = isos[class_to_int(lmfdb_iso)] if len(lmfdb_number) > 0: iso_class = [(curve,i+1) for i,curve in enumerate(classes[class_to_int(cremona_iso)])] iso_class.sort() cremona_number = str(iso_class[int(lmfdb_number)-1]) return N + cremona_iso + cremona_number else: return N + cremona_iso class MiniCremonaDatabase(SQLDatabase): """ The Cremona database of elliptic curves. INPUT: -  ``label`` - str (Cremona label) -  ``label`` - str (Cremona or LMFDB label) OUTPUT: EllipticCurve OUTPUT: - an :class:`sage.schemes.elliptic_curves.ell_rational_field.EllipticCurve_rational_field` .. note:: For more details on LMFDB labels see :func:`parse_lmfdb_label`. EXAMPLES:: Traceback (most recent call last): ... ValueError: There is no elliptic curve with label 48c1 in the database (note: use lower case letters!) You can also use LMFDB labels:: sage: c.elliptic_curve('462.f3') Elliptic Curve defined by y^2 + x*y = x^3 - 363*x + 1305 over Rational Field """ N, iso, num = parse_cremona_label(label) # There are two possible strings: the Cremona label and the LMFDB label. # They are distinguished by the presence of a period. if label.find('.') == -1: cremona_label = label lmfdb_label = None else: cremona_label = lmfdb_to_cremona(label) lmfdb_label = label N, iso, num = parse_cremona_label(cremona_label) label = str(N)+iso+str(num) if self.get_skeleton() == _miniCremonaSkeleton: q = self.__connection__.cursor().execute("SELECT eqn,rank,tors " \ F._set_rank(c) F._set_torsion_order(c) F._set_conductor(N) if lmfdb_label: F._lmfdb_label = lmfdb_label if len(c) > 3: if num == 1: F._set_modular_degree(c)
• ## sage/schemes/elliptic_curves/BSD.py

`diff --git a/sage/schemes/elliptic_curves/BSD.py b/sage/schemes/elliptic_curves/BSD.py`
 a if BSD.curve.j_invariant() in non_max_j_invs: # is this possible for optimal curves? if verbosity > 0: print 'CM by non maximal order: switching curves' for E in BSD.curve.isogeny_class(): for E in BSD.curve.isogeny_class(use_tuple=False): if E.j_invariant() not in non_max_j_invs: BSD.curve = E break kolyvagin_primes.append(p) # Stein et al. if not BSD.curve.has_cm(): L = arith.lcm([F.torsion_order() for F in BSD.curve.isogeny_class()]) L = arith.lcm([F.torsion_order() for F in BSD.curve.isogeny_class(use_tuple=False)]) for p in BSD.primes: if p in kolyvagin_primes or p == 2: continue if L%p != 0:
• ## sage/schemes/elliptic_curves/ell_modular_symbols.py

`diff --git a/sage/schemes/elliptic_curves/ell_modular_symbols.py b/sage/schemes/elliptic_curves/ell_modular_symbols.py`
 a 8 sage: E = EllipticCurve('15a1') sage: [C.modular_symbol(use_eclib=True,normalize='L_ratio')(0) for C in E.isogeny_class()] sage: [C.modular_symbol(use_eclib=True,normalize='L_ratio')(0) for C in E.isogeny_class(use_tuple=False)] [1/4, 1/8, 1/4, 1/2, 1/8, 1/16, 1/2, 1] sage: [C.modular_symbol(use_eclib=True,normalize='none')(0) for C in E.isogeny_class()] sage: [C.modular_symbol(use_eclib=True,normalize='none')(0) for C in E.isogeny_class(use_tuple=False)] [1/4, 1/4, 1/4, 1/4, 1/4, 1/4, 1/4, 1/4] Currently, the interface for negative modular symbols in eclib is not yet written:: 1 sage: E = EllipticCurve('15a1') sage: [C.modular_symbol(use_eclib=False, normalize='L_ratio')(0) for C in E.isogeny_class()] sage: [C.modular_symbol(use_eclib=False, normalize='L_ratio')(0) for C in E.isogeny_class(use_tuple=False)] [1/4, 1/8, 1/4, 1/2, 1/8, 1/16, 1/2, 1] sage: [C.modular_symbol(use_eclib=False, normalize='period')(0) for C in E.isogeny_class()] sage: [C.modular_symbol(use_eclib=False, normalize='period')(0) for C in E.isogeny_class(use_tuple=False)] [1/8, 1/16, 1/8, 1/4, 1/16, 1/32, 1/4, 1/2] sage: [C.modular_symbol(use_eclib=False, normalize='none')(0) for C in E.isogeny_class()] sage: [C.modular_symbol(use_eclib=False, normalize='none')(0) for C in E.isogeny_class(use_tuple=False)] [1, 1, 1, 1, 1, 1, 1, 1] """
• ## sage/schemes/elliptic_curves/ell_rational_field.py

`diff --git a/sage/schemes/elliptic_curves/ell_rational_field.py b/sage/schemes/elliptic_curves/ell_rational_field.py`
 a Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Rational Field Constructor from `[a_4,a_6]` sets `a_1=a_2=a_3=0`:: sage: EllipticCurve([4,5]).ainvs() (0, 0, 0, 4, 5) Constructor from a label:: sage: EllipticCurve('389a1') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field Constructor from a Cremona label:: sage: EllipticCurve('389a1') Elliptic Curve defined by y^2 + y = x^3 + x^2 - 2*x over Rational Field Constructor from an LMFDB label:: sage: EllipticCurve('462.f3') Elliptic Curve defined by y^2 + x*y = x^3 - 363*x + 1305 over Rational Field TESTS: label, we must be careful that the copied generators have the right curve (see #10999: the following used not to work when the large database was installed):: sage: E=EllipticCurve('389a1') sage: [P.curve() is E for P in E.gens()] [True, True] """ if extra != None:   # possibility of two arguments (the first would be the field) ainvs = extra self.__np = {} self.__gens = {} self.__rank = {} self.__regulator = {} self._isoclass = {} if isinstance(ainvs, str): label = ainvs X = sage.databases.cremona.CremonaDatabase()[label] EllipticCurve_number_field.__init__(self, Q, list(X.a_invariants())) self.__np = {} self.__gens = {} self.__rank = {} self.__regulator = {} for attr in ['rank', 'torsion_order', 'cremona_label', 'conductor', 'modular_degree', 'gens', 'regulator']: s = "_EllipticCurve_rational_field__"+attr setattr(self, s, gens_dict) else: setattr(self, s, getattr(X, s)) if hasattr(X,'_lmfdb_label'): self._lmfdb_label = X._lmfdb_label return EllipticCurve_number_field.__init__(self, Q, ainvs) self.__np = {} self.__gens = {} self.__rank = {} self.__regulator = {} if self.base_ring() != Q: raise TypeError, "Base field (=%s) must be the Rational Field."%self.base_ring() ########################################################## # Isogeny class ########################################################## def isogeny_class(self, algorithm="sage", verbose=False, fill_matrix=True, return_maps=False): r""" def isogeny_class(self, algorithm="sage", verbose=False, fill_matrix=True, return_maps=False, order=None, use_tuple=True): r""" Returns all curves over `\QQ` isogenous to this elliptic curve. INPUT: -  ``algorithm`` - string: one of the following: - "mwrank" - use the mwrank C++ library - "database" - use the Cremona database (only works if curve is isomorphic to a curve in the database) - "sage" (default) - use the native Sage implementation. - ``verbose`` -- bool (default: False): ignored unless ``algorithm`` == "mwrank", in which case it is passed to the isogeny class function in mwrank. -  ``algorithm`` - string: one of the following: - "mwrank" - (default) use the mwrank C++ library - "database" - use the Cremona database (only works if curve is isomorphic to a curve in the database) - "sage" - use the native Sage implementation. - ``fill_matrix`` -- bool (default: True): See below. - ``return_maps`` -- bool (default: False): Ignored unless `(i,j)` entry is the isogeny from curve `i` to curve `j` if that isogeny has prime degree, else 0. OUTPUT: Tuple (list of curves, matrix of integers) or (list of curves, - ``order`` -- None, string, or list of curves (default: None): If not None then the curves in the class are reordered after being computed.  Note that if the order is None then the resulting order will depend on the algorithm. - if ``order`` is "mwrank", "database", or "sage" then the reordering is so that the order of curves lines up with the order produced by that algorithm. - if ``order`` is "lmfdb" then the curves are sorted lexicographically by a-invariants. - if ``order`` is a list of curves, then the curves in the class are reordered to be isogenous with the specified list of curves. - ``use_tuple`` -- bool (default: True).  Controls the output format: see below.  ``use_tuple==True`` is deprecated. OUTPUT: If ``use_tuple`` is False, returns a :class:`sage.schemes.elliptic_curves.isogeny_class.IsogenyClass_EC_Rational` instace.  This object models a list of minimal models (with containment, index, etc based on isomorphism classes).  It also has methods for computing the isogeny matrix and the list of isogenies between curves in this class. If ``use_tuple`` is True (deprecated), then returns a tuple (isogeny class, matrix of integers) or (isogeny class, matrix of integers, matrix of isogenies). The sorted list of all curves isogenous to self is returned. If ``algorithm`` is not "database", the isogeny matrix is also returned, otherwise ``isogeny_graph()`` function). .. note:: The ordering depends on which algorithm is used. .. note:: The curves returned are all standard minimal models. .. warning:: The curves in the isogeny class are all standard minimal models. .. warning:: With ``algorithm`` "mwrank", the result is *not* provably correct, in the sense that when the numbers are degree. EXAMPLES:: sage: I, A = EllipticCurve('37b').isogeny_class('mwrank') sage: I   # randomly ordered [Elliptic Curve defined by y^2 + y = x^3 + x^2 - 23*x - 50 over Rational Field, Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field, Elliptic Curve defined by y^2 + y = x^3 + x^2 - 3*x +1 over Rational Field] sage: A [1 3 3] [3 1 9] [3 9 1] sage: isocls = EllipticCurve('37b').isogeny_class('mwrank',order="lmfdb",use_tuple=False) sage: isocls Elliptic curve isogeny class 37b sage: isocls.curves (Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field, Elliptic Curve defined by y^2 + y = x^3 + x^2 - 23*x - 50 over Rational Field, Elliptic Curve defined by y^2 + y = x^3 + x^2 - 3*x + 1 over Rational Field) sage: isocls.matrix() [1 3 9] [3 1 3] [9 3 1] :: sage: I, _ = EllipticCurve('37b').isogeny_class('database'); I [Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field, sage: isocls = EllipticCurve('37b').isogeny_class('database', order="lmfdb", use_tuple=False); isocls.curves (Elliptic Curve defined by y^2 + y = x^3 + x^2 - 1873*x - 31833 over Rational Field, Elliptic Curve defined by y^2 + y = x^3 + x^2 - 23*x - 50 over Rational Field, Elliptic Curve defined by y^2 + y = x^3 + x^2 - 3*x + 1 over Rational Field] Elliptic Curve defined by y^2 + y = x^3 + x^2 - 3*x + 1 over Rational Field) This is an example of a curve with a `37`-isogeny:: sage: E = EllipticCurve([1,1,1,-8,6]) sage: E.isogeny_class () ([Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 8*x + 6 over Rational Field, Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 208083*x - 36621194 over Rational Field], [ 1 37] [37  1]) sage: isocls = E.isogeny_class(use_tuple=False); isocls Isogeny class of Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 8*x + 6 over Rational Field sage: isocls.matrix() [ 1 37] [37  1] sage: print "\n".join([repr(E) for E in isocls.curves]) Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 8*x + 6 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 208083*x - 36621194 over Rational Field This curve had numerous `2`-isogenies:: sage: e=EllipticCurve([1,0,0,-39,90]) sage: e.isogeny_class () ([Elliptic Curve defined by y^2 + x*y = x^3 - 39*x + 90 over Rational Field, Elliptic Curve defined by y^2 + x*y = x^3 - 4*x - 1 over Rational Field, Elliptic Curve defined by y^2 + x*y = x^3 + x over Rational Field, Elliptic Curve defined by y^2 + x*y = x^3 - 49*x - 136 over Rational Field, Elliptic Curve defined by y^2 + x*y = x^3 - 34*x - 217 over Rational Field, Elliptic Curve defined by y^2 + x*y = x^3 - 784*x - 8515 over Rational Field], [1 2 4 4 8 8] sage: isocls = e.isogeny_class(use_tuple=False); isocls.matrix() [1 2 4 4 8 8] [2 1 2 2 4 4] [4 2 1 4 8 8] [4 2 4 1 2 2] [8 4 8 2 1 4] [8 4 8 2 4 1]) [8 4 8 2 4 1] See http://math.harvard.edu/~elkies/nature.html for more interesting examples of isogeny structures. :: sage: E = EllipticCurve(j = -262537412640768000) sage: E.isogeny_class(algorithm="sage") ([Elliptic Curve defined by y^2 + y = x^3 - 2174420*x + 1234136692 over Rational Field, Elliptic Curve defined by y^2 + y = x^3 - 57772164980*x - 5344733777551611 over Rational Field], [  1 163] [163   1]) sage: isocls = E.isogeny_class(algorithm="sage", use_tuple=False); isocls.matrix() [  1 163] [163   1] sage: print "\n".join([repr(C) for C in isocls.curves]) Elliptic Curve defined by y^2 + y = x^3 - 2174420*x + 1234136692 over Rational Field Elliptic Curve defined by y^2 + y = x^3 - 57772164980*x - 5344733777551611 over Rational Field For large examples, the "mwrank" algorithm may fail to find some isogenies since it works in fixed precision:: sage: E1 = E.quadratic_twist(6584935282) sage: E1.isogeny_class(algorithm="mwrank") ([Elliptic Curve defined by y^2 = x^3 - 94285835957031797981376080*x + 352385311612420041387338054224547830898 over Rational Field], ) Since the result is cached, this looks no different:: sage: E1.isogeny_class(algorithm="sage") ([Elliptic Curve defined by y^2 = x^3 - 94285835957031797981376080*x + 352385311612420041387338054224547830898 over Rational Field], ) But resetting the curve shows that the native algorithm is better:: sage: E1 = E.quadratic_twist(6584935282) sage: E1.isogeny_class(algorithm="sage") ([Elliptic Curve defined by y^2 = x^3 - 94285835957031797981376080*x + 352385311612420041387338054224547830898 over Rational Field, Elliptic Curve defined by y^2 = x^3 - 2505080375542377840567181069520*x - 1526091631109553256978090116318797845018020806 over Rational Field], [  1 163] [163   1]) sage: E1.isogeny_class(algorithm="mwrank", use_tuple=False).matrix()  Using algorithm="sage" gives another isogeny (even though results are cached: the cache depends on the algorithm):: sage: isocls = E1.isogeny_class(algorithm="sage", use_tuple=False); isocls.matrix() [  1 163] [163   1] sage: E1.conductor() 18433092966712063653330496 :: sage: E = EllipticCurve('14a1') sage: E.isogeny_class(algorithm="sage") ([Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field, Elliptic Curve defined by y^2 + x*y + y = x^3 - 36*x - 70 over Rational Field, Elliptic Curve defined by y^2 + x*y + y = x^3 - x over Rational Field, Elliptic Curve defined by y^2 + x*y + y = x^3 - 171*x - 874 over Rational Field, Elliptic Curve defined by y^2 + x*y + y = x^3 - 11*x + 12 over Rational Field, Elliptic Curve defined by y^2 + x*y + y = x^3 - 2731*x - 55146 over Rational Field], [ 1  2  3  3  6  6] :: sage: E = EllipticCurve('14a1') sage: isocls = E.isogeny_class(algorithm="sage", use_tuple=False); isocls.matrix() [ 1  2  3  3  6  6] [ 2  1  6  6  3  3] [ 3  6  1  9  2 18] [ 3  6  9  1 18  2] [ 6  3  2 18  1  9] [ 6  3 18  2  9  1]) [ 6  3 18  2  9  1] sage: print "\n".join([repr(C) for C in isocls.curves]) Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 - 36*x - 70 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 - x over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 - 171*x - 874 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 - 11*x + 12 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 - 2731*x - 55146 over Rational Field sage: isocls2 = isocls.reorder('lmfdb'); isocls2.matrix() [ 1  2  3  9 18  6] [ 2  1  6 18  9  3] [ 3  6  1  3  6  2] [ 9 18  3  1  2  6] [18  9  6  2  1  3] [ 6  3  2  6  3  1] sage: print "\n".join([repr(C) for C in isocls2.curves]) Elliptic Curve defined by y^2 + x*y + y = x^3 - 2731*x - 55146 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 - 171*x - 874 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 - 36*x - 70 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 - 11*x + 12 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 - x over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x - 6 over Rational Field :: sage: E = EllipticCurve('11a1') sage: E.isogeny_class(algorithm="sage", return_maps=True) ([Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field, Elliptic Curve defined by y^2 + y = x^3 - x^2 over Rational Field, Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field], [ 1  5  5] sage: isocls = E.isogeny_class(algorithm="sage", use_tuple=False); isocls.matrix() [ 1  5  5] [ 5  1 25] [ 5 25  1], [[0, Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 over Rational Field, Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field], [Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 - x^2 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field, 0, 0], [Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field, 0, 0]]) """ from sage.schemes.elliptic_curves.ell_curve_isogeny import fill_isogeny_matrix, unfill_isogeny_matrix from sage.matrix.all import MatrixSpace [ 5 25  1] sage: f = isocls.isogenies(); f.kernel_polynomial() x^2 + x - 29/5 """ try: curves, M = self.__isogeny_class if fill_matrix and M[0,0]==0: M = fill_isogeny_matrix(M) elif not fill_matrix and M[0,0]==1: M = unfill_isogeny_matrix(M) return curves, M except AttributeError: pass if algorithm == "mwrank": try: E = self.mwrank_curve() except ValueError: E = self.minimal_model().mwrank_curve() I, A = E.isogeny_class(verbose=verbose) M = matrix.MatrixSpace(rings.IntegerRing(), len(A))(A) curves = [constructor.EllipticCurve(ainvs) for ainvs in I] elif algorithm == "database": try: label = self.cremona_label(space=False) except RuntimeError: raise RuntimeError, "unable to to find %s in the database"%self db = sage.databases.cremona.CremonaDatabase() curves = db.isogeny_class(label) if len(curves) == 0: raise RuntimeError, "unable to to find %s in the database"%self curves.sort() M = None elif algorithm == "sage": curves = [self.minimal_model()] ijl_triples = [] l_list = None i = 0 while i M.entries() change... # Take logs here since shortest path minimizes the *sum* of the weights -- not the product. M = M.parent()([a.log() if a else 0 for a in M.list()]) G = Graph(M, format='weighted_adjacency_matrix') G.set_vertices(dict([(v,L[v]) for v in G.vertices()])) G.set_vertices(dict([(v,isocls[v]) for v in G.vertices()])) v = G.shortest_path_lengths(0, by_weight=True, weight_sums=True) # Now exponentiate and round to get degrees of isogenies v = dict([(i, j.exp().round() if j else 0) for i,j in v.iteritems()]) return L, v return isocls.curves, v def _multiple_of_degree_of_isogeny_to_optimal_curve(self): r"""
• ## sage/schemes/elliptic_curves/gal_reps.py

`diff --git a/sage/schemes/elliptic_curves/gal_reps.py b/sage/schemes/elliptic_curves/gal_reps.py`
 a if t == True: self.__is_reducible[p] = False return False  # definitely not reducible isogeny_matrix = self.E.isogeny_class()[ 1 ] isogeny_matrix = self.E.isogeny_class(use_tuple=False).matrix(fill=True) v = isogeny_matrix.row(0) # first row for a in v: if a != 0 and a % p == 0: return self.__reducible_primes except AttributeError: pass C, I = self.E.isogeny_class(algorithm='sage') X = set(I.list()) isocls = self.E.isogeny_class(algorithm='sage', use_tuple=False) X = set(isocls.matrix().list()) R = [p for p in X if arith.is_prime(p)] self.__reducible_primes = R return R
• ## new file sage/schemes/elliptic_curves/isogeny_class.py

```diff --git a/sage/schemes/elliptic_curves/isogeny_class.py b/sage/schemes/elliptic_curves/isogeny_class.py
new file mode 100644```
 - """ This file defines a class for an isogeny class of an elliptic curve. AUTHORS: David Roe (2012-03-29) -- initial version. """ ############################################################################## #       Copyright (C) 2012 David Roe #                          William Stein # #  Distributed under the terms of the GNU General Public License (GPL) # #    This code is distributed in the hope that it will be useful, #    but WITHOUT ANY WARRANTY; without even the implied warranty of #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU #    General Public License for more details. # #  The full text of the GPL is available at: # #                  http://www.gnu.org/licenses/ ############################################################################## from sage.structure.sage_object import SageObject from sage.misc.lazy_attribute import lazy_attribute import constructor import sage.databases.cremona from sage.rings.all import ZZ from sage.misc.cachefunc import cached_method from sage.misc.abstract_method import abstract_method from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic class IsogenyClass_EC(SageObject): """ Isogeny class of an elliptic curve. The current implementation chooses a curve from each isomorphism class in the isogeny class, since over Q there is a unique minimal model in each isomorphism class. EXAMPLES:: """ def __init__(self, E, label=None, empty=False): """ Over Q we use curves since minimal models exist and there is a canonical choice of one. INPUT: - ``label`` -- string or None, a Cremona or LMFDB label, used in printing EXAMPLES:: sage: cls = EllipticCurve('1011b1').isogeny_class(use_tuple=False) sage: print "\n".join([repr(E) for E in cls.curves]) Elliptic Curve defined by y^2 + x*y = x^3 - 8*x - 9 over Rational Field Elliptic Curve defined by y^2 + x*y = x^3 - 23*x + 30 over Rational Field """ self.E = E self._label = label if not empty: self._compute() def __len__(self): """ The length is just the number of curves in the class. EXAMPLES:: sage: E = EllipticCurve('15a') sage: len(E.isogeny_class(use_tuple=False)) # indirect doctest 8 """ return len(self.curves) def __iter__(self): """ Iterator over curves in the class. EXAMPLES:: sage: E = EllipticCurve('15a') sage: all(C.conductor() == 15 for C in E.isogeny_class(use_tuple=False)) # indirect doctest True """ return iter(self.curves) def __getitem__(self, i): """ Gets the `i`th curve in the class. EXAMPLES:: sage: E = EllipticCurve('990j1') sage: iso = E.isogeny_class(order="lmfdb",use_tuple=False) # orders lexicographically on a-invariants sage: iso == E # indirect doctest True """ return self.curves[i] def index(self, C): """ Returns the index of a curve in this class. INPUT: - ``C`` -- an elliptic curve in this isogeny class. OUTPUT: - ``i`` -- an integer so that the ``i``th curve in the class is isomorphic to ``C`` EXAMPLES:: sage: E = EllipticCurve('990j1') sage: iso = E.isogeny_class(order="lmfdb", use_tuple=False) # orders lexicographically on a-invariants sage: iso.index(E.short_weierstrass_model()) 2 """ # This will need updating once we start talking about curves over more general number fields if not isinstance(C, EllipticCurve_generic): raise ValueError("x not in isogeny class") return self.curves.index(C.minimal_model()) def __cmp__(self, other): """ Returns 0 if self and other are the same isogeny class. If they are different, compares the sorted underlying lists of curves. Note that two isogeny classes with different orderings will compare as the same.  If you want to include the ordering, just compare the list of curves. EXAMPLES:: sage: E = EllipticCurve('990j1') sage: EE = EllipticCurve('990j4') sage: E.isogeny_class(use_tuple=False) == EE.isogeny_class(use_tuple=False) # indirect doctest True """ # This will need updating once we start talking about curves over more general number fields if isinstance(other, IsogenyClass_EC): return cmp(sorted(self.curves), sorted(other.curves)) return cmp(type(self), type(other)) def __hash__(self): """ Hash is based on the a-invariants of the sorted list of minimal models. EXAMPLES:: sage: E = EllipticCurve('990j1') sage: C = E.isogeny_class(use_tuple=False) sage: hash(C) == hash(tuple(sorted([curve.a_invariants() for curve in C.curves]))) # indirect doctest True """ try: return self._hash except AttributeError: self._hash = hash(tuple(sorted([E.a_invariants() for E in self.curves]))) return self._hash def _repr_(self): """ The string representation depends on whether an LMFDB or Cremona label for the curve is known when this isogeny class is constructed. EXAMPLES: If the curve is constructed from an LMFDB label then that label is used:: sage: E = EllipticCurve('462.f3') sage: E.isogeny_class(use_tuple=False) # indirect doctest Elliptic curve isogeny class 462.f If the curve is constructed from a Cremona label then that label is used:: sage: E = EllipticCurve('990j1') sage: E.isogeny_class(use_tuple=False) Elliptic curve isogeny class 990j Otherwise the representation is determined from the first curve in the class:: sage: E = EllipticCurve([1,2,3,4,5]) sage: E.isogeny_class(use_tuple=False) Isogeny class of Elliptic Curve defined by y^2 + x*y = x^3 - x^2 + 4*x + 3 over Rational Field """ if self._label: return "Elliptic curve isogeny class %s"%(self._label) else: return "Isogeny class of %r"%(self.curves) def __contains__(self, x): """ INPUT: - ``x`` -- a Python object. OUTPUT: - boolean -- True iff ``x`` is an elliptic curve in this isogeny class. EXAMPLES:: sage: cls = EllipticCurve('15a3').isogeny_class(use_tuple=False) sage: E = EllipticCurve('15a7'); E in cls True sage: E.short_weierstrass_model() in cls True """ if not isinstance(x, EllipticCurve_generic): return False return x.minimal_model() in self.curves @cached_method def matrix(self, fill=True): """ Returns the matrix whose entries give the minimal degrees of isogenies between curves in this class. INPUT: - ``fill`` -- boolean (default True).  If False then the matrix will contain only zeros and prime entries; if True it will fill in the other degrees. EXAMPLES:: sage: isocls = EllipticCurve('15a3').isogeny_class(use_tuple=False) sage: isocls.matrix() [ 1  2  2  2  4  4  8  8] [ 2  1  4  4  8  8 16 16] [ 2  4  1  4  8  8 16 16] [ 2  4  4  1  2  2  4  4] [ 4  8  8  2  1  4  8  8] [ 4  8  8  2  4  1  2  2] [ 8 16 16  4  8  2  1  4] [ 8 16 16  4  8  2  4  1] sage: isocls.matrix(fill=False) [0 2 2 2 0 0 0 0] [2 0 0 0 0 0 0 0] [2 0 0 0 0 0 0 0] [2 0 0 0 2 2 0 0] [0 0 0 2 0 0 0 0] [0 0 0 2 0 0 2 2] [0 0 0 0 0 2 0 0] [0 0 0 0 0 2 0 0] """ if self._mat is None: self._compute_matrix() mat = self._mat if fill and mat[0,0] == 0: from sage.schemes.elliptic_curves.ell_curve_isogeny import fill_isogeny_matrix mat = fill_isogeny_matrix(mat) if not fill and mat[0,0] == 1: from sage.schemes.elliptic_curves.ell_curve_isogeny import unfill_isogeny_matrix mat = unfill_isogeny_matrix(mat) return mat @cached_method def isogenies(self, fill=False): """ Returns a list of lists of isogenies and 0s, corresponding to the entries of :meth:`matrix` INPUT: - ``fill`` -- boolean (default False).  Whether to only return prime degree isogenies.  Currently only implemented for ``fill=False``. OUTPUT: - a list of lists, where the ``j``th entry of the ``i``th list is either zero or a prime degree isogeny from ``i``th curve in this class to the ``j``th curve. WARNING: - The domains and codmains of the isogenies will have the same Weierstrass equation as the curves in this class, but they may not be identical python objects in the current implementation. EXAMPLES:: sage: isocls = EllipticCurve('15a3').isogeny_class(use_tuple=False) sage: f = isocls.isogenies(); f Isogeny of degree 2 from Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 5*x + 2 over Rational Field to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 80*x + 242 over Rational Field sage: f.domain() == isocls.curves and f.codomain() == isocls.curves True """ if fill: raise NotImplementedError isogenies = self._maps if isogenies is None: self._compute_isogenies() isogenies = self._maps return isogenies @cached_method def graph(self): """ Returns a graph whose vertices correspond to curves in this class, and whose edges correspond to prime degree isogenies. .. note: There are only finitely many possible isogeny graphs for curves over Q [M78].  This function tries to lay out the graph nicely by special casing each isogeny graph. .. note: The vertices are labeled 1 to n rather than 0 to n-1 to correspond to LMFDB and Cremona labels. EXAMPLES:: sage: isocls = EllipticCurve('15a3').isogeny_class(use_tuple=False) sage: G = isocls.graph() sage: sorted(G._pos.items()) [(1, [-0.8660254, 0.5]), (2, [-0.8660254, 1.5]), (3, [-1.7320508, 0]), (4, [0, 0]), (5, [0, -1]), (6, [0.8660254, 0.5]), (7, [0.8660254, 1.5]), (8, [1.7320508, 0])] REFERENCES: .. [M78] B. Mazur.  Rational Isogenies of Prime Degree. *Inventiones mathematicae* 44,129-162 (1978). """ from sage.graphs.graph import Graph M = self.matrix(fill = False) n = M.nrows() # = M.ncols() G = Graph(M, format='weighted_adjacency_matrix') N = self.matrix(fill = True) D = dict([(v,self.curves[v]) for v in G.vertices()]) # The maximum degree classifies the shape of the isogeny # graph, though the number of vertices is often enough. # This only holds over Q, so this code will need to change # once other isogeny classes are implemented. if n == 1: # one vertex pass elif n == 2: # one edge, two vertices.  We align horizontally and put # the lower number on the left vertex. G.set_pos(pos={0:[-0.5,0],1:[0.5,0]}) else: maxdegree = max(max(N)) if n == 3: # o--o--o centervert = [i for i in range(3) if max(N.row(i)) < maxdegree] other = [i for i in range(3) if i != centervert] G.set_pos(pos={centervert:[0,0],other:[-1,0],other:[1,0]}) elif maxdegree == 4: # o--o<8 centervert = [i for i in range(4) if max(N.row(i)) < maxdegree] other = [i for i in range(4) if i != centervert] G.set_pos(pos={centervert:[0,0],other:[0,1],other:[-0.8660254,-0.5],other:[0.8660254,-0.5]}) elif maxdegree == 27: # o--o--o--o centers = [i for i in range(4) if list(N.row(i)).count(3) == 2] left = [j for j in range(4) if N[centers,j] == 3 and j not in centers] right = [j for j in range(4) if N[centers,j] == 3 and j not in centers] G.set_pos(pos={left:[-1.5,0],centers:[-0.5,0],centers:[0.5,0],right:[1.5,0]}) elif n == 4: # square opp = [i for i in range(1,4) if not N[0,i].is_prime()] other = [i for i in range(1,4) if i != opp] G.set_pos(pos={0:[1,1],other:[-1,1],opp:[-1,-1],other:[1,-1]}) elif maxdegree == 8: # 8>o--o<8 centers = [i for i in range(6) if list(N.row(i)).count(2) == 3] left = [j for j in range(6) if N[centers,j] == 2 and j not in centers] right = [j for j in range(6) if N[centers,j] == 2 and j not in centers] G.set_pos(pos={centers:[-0.5,0],left:[-1,0.8660254],left:[-1,-0.8660254],centers:[0.5,0],right:[1,0.8660254],right:[1,-0.8660254]}) elif maxdegree == 18: # two squares joined on an edge centers = [i for i in range(6) if list(N.row(i)).count(3) == 2] top = [j for j in range(6) if N[centers,j] == 3] bl = [j for j in range(6) if N[top,j] == 2] br = [j for j in range(6) if N[top,j] == 2] G.set_pos(pos={centers:[0,0.5],centers:[0,-0.5],top:[-1,0.5],top:[1,0.5],bl:[-1,-0.5],br:[1,-0.5]}) elif maxdegree == 16: # tree from bottom, 3 regular except for the leaves. centers = [i for i in range(8) if list(N.row(i)).count(2) == 3] center = [i for i in centers if len([j for j in centers if N[i,j] == 2]) == 2] centers.remove(center) bottom = [j for j in range(8) if N[center,j] == 2 and j not in centers] left = [j for j in range(8) if N[centers,j] == 2 and j != center] right = [j for j in range(8) if N[centers,j] == 2 and j != center] G.set_pos(pos={center:[0,0],bottom:[0,-1],centers:[-0.8660254,0.5],centers:[0.8660254,0.5],left:[-0.8660254,1.5],right:[0.8660254,1.5],left:[-1.7320508,0],right:[1.7320508,0]}) elif maxdegree == 12: # tent centers = [i for i in range(8) if list(N.row(i)).count(2) == 3] left = [j for j in range(8) if N[centers,j] == 2] right = [] for i in range(3): right.append([j for j in range(8) if N[centers,j] == 2 and N[left[i],j] == 3]) G.set_pos(pos={centers:[-0.75,0],centers:[0.75,0],left:[-0.75,1],right:[0.75,1],left:[-1.25,-0.75],right:[0.25,-0.75],left:[-0.25,-0.25],right:[1.25,-0.25]}) G.set_vertices(D) G.relabel(range(1,n+1)) return G @cached_method def reorder(self, order): """ Return a new isogeny class with the curves reordered. INPUT: - ``order`` -- None, a string or an iterable over all curves in this class.  See :meth:`sage.schemes.elliptic_curves.ell_rational_field.EllipticCurve_rational_field.isogeny_class` for more details. OUTPUT: - Another :class:`IsogenyClass_EC` with the curves reordered (and matrices and maps changed as appropriate) EXAMPLES:: sage: isocls = EllipticCurve('15a1').isogeny_class(use_tuple=False) sage: print "\n".join([repr(C) for C in isocls.curves]) Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 5*x + 2 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + 35*x - 28 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 135*x - 660 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 80*x + 242 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 110*x - 880 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 2160*x - 39540 over Rational Field sage: isocls2 = isocls.reorder('lmfdb') sage: print "\n".join([repr(C) for C in isocls2.curves]) Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 2160*x - 39540 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 135*x - 660 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 110*x - 880 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 80*x + 242 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 10*x - 10 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 - 5*x + 2 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 over Rational Field Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + 35*x - 28 over Rational Field """ if order is None or isinstance(order, basestring) and order == self._algorithm: return self if isinstance(order, basestring): if order == "lmfdb": reordered_curves = sorted(self.curves, key = lambda E: E.a_invariants()) else: reordered_curves = list(self.E.isogeny_class(algorithm=order, use_tuple=False)) elif isinstance(order, (list, tuple, IsogenyClass_EC)): reordered_curves = list(order) if len(reordered_curves) != len(self.curves): raise ValueError("Incorrect length") else: raise TypeError("order parameter should be a string, list of curves or isogeny class") need_perm = self._mat is not None cpy = self.copy() curves = [] perm = [] for E in reordered_curves: try: j = self.curves.index(E) except ValueError: try: j = self.curves.index(E.minimal_model()) except ValueError: raise ValueError("order does not yield a permutation of curves") curves.append(self.curves[j]) if need_perm: perm.append(j+1) cpy.curves = tuple(curves) if need_perm: from sage.groups.perm_gps.permgroup_named import SymmetricGroup perm = SymmetricGroup(len(self.curves))(perm) cpy._mat = perm.matrix() * self._mat * (~perm).matrix() if self._maps is not None: n = len(self._maps) cpy._maps = [self._maps[perm(i+1)-1] for i in range(n)] for i in range(n): cpy._maps[i] = [cpy._maps[i][perm(j+1)-1] for j in range(n)] else: cpy._mat = None cpy._maps = None return cpy @abstract_method def _compute(self): """ This function is called during initialization and should fill in ``self.curves``, and possibly ``self._mat`` and ``self._maps`` as well, depending on the algorithm. EXAMPLES:: sage: EllipticCurve('11a1').isogeny_class('mwrank',use_tuple=False).matrix() # indirect doctest [ 1  5  5] [ 5  1 25] [ 5 25  1] """ pass @abstract_method def _compute_matrix(self): """ For algorithms that don't compute the isogeny matrix at first, this function should fill in ``self._mat``. EXAMPLES:: sage: EllipticCurve('11a1').isogeny_class('database',use_tuple=False).matrix() # indirect doctest [ 1  5  5] [ 5  1 25] [ 5 25  1] """ pass @abstract_method def _compute_isogenies(self): """ For algorithms that don't compute the isogenies at first, this function should fill in ``self._maps``. EXAMPLES:: sage: f = EllipticCurve('11a1').isogeny_class('mwrank',use_tuple=False).isogenies() # indirect doctest sage: f.domain() Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field """ pass class IsogenyClass_EC_Rational(IsogenyClass_EC): """ Isogeny classes for elliptic curves over Q. """ def __init__(self, E, algorithm="sage", verbose=False, label=None, empty=False): """ INPUT: - ``E`` -- an elliptic curve over Q. - ``algorithm`` -- a string (default "sage").  One of the following: - "sage" -- Use sage's implementation to compute the curves, matrix and isogenies - "mwrank" -- Use the mwrank C++ library - "database" -- Use the Cremona database (only works if the curve is in the database) - ``verbose`` -- boolean (default False).  Only relevant for algorithm="mwrank", controls verbosity of output while running mwrank. - ``label`` -- a string, the label of this isogeny class (e.g. '15a' or '37.b').  Used in printing. - ``empty`` -- don't compute the curves right now (used when reordering) EXAMPLES:: sage: isocls = EllipticCurve('389a1').isogeny_class(use_tuple=False); isocls Elliptic curve isogeny class 389a sage: TestSuite(isocls).run() """ self._algorithm = algorithm self._verbose = verbose IsogenyClass_EC.__init__(self, E, label=label, empty=empty) def copy(self): """ Returns a copy (mostly used in reordering). EXAMPLES:: sage: isocls = EllipticCurve('389a1').isogeny_class(use_tuple=False) sage: isocls2 = isocls.copy() sage: isocls is isocls2 False sage: isocls == isocls2 True """ ans = IsogenyClass_EC_Rational(self.E, self._algorithm, self._verbose, self._label, empty=True) # The following isn't needed internally, but it will keep # things from breaking if this is used for something other # than reordering. ans.curves = self.curves ans._mat = None ans._maps = None return ans def _compute(self): """ Computes the list of curves, and possibly the matrix and prime-degree isogenies (depending on the algorithm selected). EXAMPLES:: sage: isocls = EllipticCurve('48a1').isogeny_class('sage',use_tuple=False).copy() sage: isocls._mat sage: isocls._compute(); isocls._mat [0 2 2 2 0 0] [2 0 0 0 2 2] [2 0 0 0 0 0] [2 0 0 0 0 0] [0 2 0 0 0 0] [0 2 0 0 0 0] """ algorithm = self._algorithm from sage.schemes.elliptic_curves.ell_curve_isogeny import fill_isogeny_matrix, unfill_isogeny_matrix from sage.matrix.all import MatrixSpace self._maps = None if algorithm == "mwrank": try: E = self.E.mwrank_curve() except ValueError: E = self.E.minimal_model().mwrank_curve() I, A = E.isogeny_class(verbose=self._verbose) self._mat = MatrixSpace(ZZ, len(A))(A) self.curves = tuple([constructor.EllipticCurve(ainvs) for ainvs in I]) elif algorithm == "database": try: label = self.E.cremona_label(space=False) except RuntimeError: raise RuntimeError("unable to to find %s in the database"%self) db = sage.databases.cremona.CremonaDatabase() curves = db.isogeny_class(label) if len(curves) == 0: raise RuntimeError("unable to to find %s in the database"%self) # All curves will have the same conductor and isogeny class, # and there are are most 8 of them, so lexicographic sorting is okay. self.curves = tuple(sorted(curves, key = lambda E: E.cremona_label())) self._mat = None elif algorithm == "sage": curves = [self.E.minimal_model()] ijl_triples = [] l_list = None i = 0 while i