diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index decf0a3d0b5..ab790116637 100755 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -4,13 +4,13 @@ This module defines the class :class:`EllipticCurve_field`, based on :class:`EllipticCurve_generic`, for elliptic curves over general fields. """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2006 William Stein # # Distributed under the terms of the GNU General Public License (GPL) # # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** import sage.rings.abc from sage.categories.number_fields import NumberFields @@ -1732,9 +1732,9 @@ def kernel_polynomial_from_divisor(self, f, l, *, check=True): def isogenies_prime_degree(self, l=None, max_l=31): """ - Return a list of all separable isogenies of given prime degree(s) - with domain equal to ``self``, which are defined over the base - field of ``self``. + Return a list of all separable isogenies (up to post-composition with + isomorphisms) of given prime degree(s) with domain equal to ``self``, + which are defined over the base field of ``self``. INPUT: @@ -2016,6 +2016,162 @@ def isogenies_prime_degree(self, l=None, max_l=31): from .isogeny_small_degree import isogenies_prime_degree return sum([isogenies_prime_degree(self, d) for d in L], []) + def isogenies_degree(self, n, *, _intermediate=False): + r""" + Return an iterator of all separable isogenies of given degree (up to + post-composition with isomorphisms) with domain equal to ``self``, + which are defined over the base field of ``self``. + + ALGORITHM: + + The prime factors `p` of `n` are processed one by one in decreasing + order, each time "branching" out by taking isogenies of degree `p`. + + INPUT: + + - ``n`` -- integer, or its + :class:`~sage.structure.factorization.Factorization`. + + - ``_intermediate`` -- (bool, default: False): If set, the isogenies + from this curve to the curves traversed within the depth-first search + are returned. This is for internal use only. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(11), [1, 1]) + sage: list(E.isogenies_degree(23 * 19)) + [Composite morphism of degree 437 = 23*19: + From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 11 + To: Elliptic Curve defined by y^2 = x^3 + 8*x + 7 over Finite Field of size 11, + Composite morphism of degree 437 = 23*19: + From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 11 + To: Elliptic Curve defined by y^2 = x^3 + 6*x + 2 over Finite Field of size 11, + Composite morphism of degree 437 = 23*19: + From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 11 + To: Elliptic Curve defined by y^2 = x^3 + 2*x + 6 over Finite Field of size 11, + Composite morphism of degree 437 = 23*19: + From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 11 + To: Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 11] + + :: + + sage: E = EllipticCurve(GF(next_prime(2^32)), j=1728) + sage: sorted([phi.codomain().j_invariant() for phi in E.isogenies_degree(11 * 17 * 19^2)]) + [1348157279, 1348157279, 1713365879, 1713365879, 3153894341, 3153894341, + 3225140514, 3225140514, 3673460198, 3673460198, 3994312564, 3994312564] + sage: it = E.isogenies_degree(2^2); it + + sage: all(phi.degree() == 2^2 for phi in it) + True + + We verify that the isogenies outputted are distinct. Note that we do + not use a ``set`` or any hash-based data structure, as hashing + isogenies is slow:: + + sage: import itertools + sage: all_distinct = lambda arr: all(x != y for x, y in itertools.combinations(arr, 2)) + sage: K. = GF((19, 2)) + sage: E = EllipticCurve(K, [11*z+5, 14*z+3]) + sage: S = list(E.isogenies_degree(5^2)); len(S), all_distinct(S) + (3, True) + sage: S = list(E.isogenies_degree(5^2*11)); len(S), all_distinct(S) + (6, True) + sage: S = list(E.isogenies_degree(5^2*11^4)); len(S), all_distinct(S) # long time (2s) + (15, True) + + :: + + sage: pol = PolynomialRing(QQ, 'x')([1, -3, 5, -5, 5, -3, 1]) + sage: L. = NumberField(pol) + sage: js = hilbert_class_polynomial(-23).roots(L, multiplicities=False) + sage: len(js) + 3 + sage: E = EllipticCurve(j=js[0]) + sage: len(list(E.isogenies_degree(2**2))) + 6 + sage: len(list(E.isogenies_degree(2**5))) # long time (15s) + 99 + + TESTS:: + + sage: E = EllipticCurve(GF(next_prime(2^32)), j=1728) + sage: list(E.isogenies_degree(2^2, _intermediate=True)) + [Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 4294967311 + Via: (u,r,s,t) = (1, 0, 0, 0), + Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 4294967311 + to Elliptic Curve defined by y^2 = x^3 + 4294967307*x over Finite Field of size 4294967311, + Composite morphism of degree 4 = 2^2: + From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 4294967311 + To: Elliptic Curve defined by y^2 = x^3 + 16*x over Finite Field of size 4294967311, + Composite morphism of degree 4 = 2^2: + From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 4294967311 + To: Elliptic Curve defined by y^2 = x^3 + 4294967267*x + 4294967199 over Finite Field of size 4294967311, + Composite morphism of degree 4 = 2^2: + From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 4294967311 + To: Elliptic Curve defined by y^2 = x^3 + 4294967267*x + 112 over Finite Field of size 4294967311] + sage: all(isog.domain() is E for isog in _) + True + sage: all(isog.domain() is E for isog in E.isogenies_degree(2^5, _intermediate=True)) + True + + The following curve has no degree-`53` isogenies, so the code is quick:: + + sage: E = EllipticCurve(GF(103), [3, 5]) + sage: E.isogenies_prime_degree(53) + [] + sage: list(E.isogenies_degree(product(prime_range(3, 53)) * 53)) + [] + """ + def compute_key(phi): + """ + Data used in ``hash(phi)`` excluding the expensive `.kernel_polynomial`. + """ + return (phi.domain(), phi.codomain(), phi.scaling_factor()) + + from sage.schemes.elliptic_curves.weierstrass_morphism import identity_morphism + from sage.structure.factorization import Factorization + + if not isinstance(n, Factorization): + n = Integer(n).factor() + + if n.value() == 1: + yield identity_morphism(self) + return + + p = n[-1][0] + seen = {} + + def insert_seen(phi): + nonlocal seen + key = compute_key(phi) + if key not in seen: + seen[key] = [phi] + return phi + for psi in seen[key]: + if psi == phi: + return + seen[key].append(phi) + return phi + + if _intermediate: + yield identity_morphism(self) + + # isog: self -> E1 + for isog in self.isogenies_prime_degree(p): + if _intermediate: + if insert_seen(isog): + # self -> E1 + yield isog + + Eiso = isog.codomain() + # next_isog : E1 -> E2 + for next_isog in Eiso.isogenies_degree(n / p, _intermediate=_intermediate): + # psi: self -> E2 + psi = next_isog * isog + if insert_seen(psi): + # self -> E2 + yield psi + def is_isogenous(self, other, field=None): """ Return whether or not ``self`` is isogenous to ``other``. diff --git a/tags b/tags new file mode 100644 index 00000000000..be52b140999 --- /dev/null +++ b/tags @@ -0,0 +1,94 @@ +!_TAG_EXTRA_DESCRIPTION anonymous /Include tags for non-named objects like lambda/ +!_TAG_EXTRA_DESCRIPTION fileScope /Include tags of file scope/ +!_TAG_EXTRA_DESCRIPTION pseudo /Include pseudo tags/ +!_TAG_EXTRA_DESCRIPTION subparser /Include tags generated by subparsers/ +!_TAG_FIELD_DESCRIPTION epoch /the last modified time of the input file (only for F\/file kind tag)/ +!_TAG_FIELD_DESCRIPTION file /File-restricted scoping/ +!_TAG_FIELD_DESCRIPTION input /input file/ +!_TAG_FIELD_DESCRIPTION name /tag name/ +!_TAG_FIELD_DESCRIPTION pattern /pattern/ +!_TAG_FIELD_DESCRIPTION typeref /Type and name of a variable or typedef/ +!_TAG_FIELD_DESCRIPTION!Python nameref /the original name for the tag/ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_KIND_DESCRIPTION!Python I,namespace /name referring a module defined in other file/ +!_TAG_KIND_DESCRIPTION!Python Y,unknown /name referring a class\/variable\/function\/module defined in other module/ +!_TAG_KIND_DESCRIPTION!Python c,class /classes/ +!_TAG_KIND_DESCRIPTION!Python f,function /functions/ +!_TAG_KIND_DESCRIPTION!Python i,module /modules/ +!_TAG_KIND_DESCRIPTION!Python m,member /class members/ +!_TAG_KIND_DESCRIPTION!Python v,variable /variables/ +!_TAG_KIND_DESCRIPTION!Tex B,bibitem /bibliography items/ +!_TAG_KIND_DESCRIPTION!Tex C,command /command created with \\newcommand/ +!_TAG_KIND_DESCRIPTION!Tex G,subparagraph /subparagraphs/ +!_TAG_KIND_DESCRIPTION!Tex N,counter /counter created with \\newcounter/ +!_TAG_KIND_DESCRIPTION!Tex P,paragraph /paragraphs/ +!_TAG_KIND_DESCRIPTION!Tex b,subsubsection /subsubsections/ +!_TAG_KIND_DESCRIPTION!Tex c,chapter /chapters/ +!_TAG_KIND_DESCRIPTION!Tex e,environment /environment created with \\newenvironment/ +!_TAG_KIND_DESCRIPTION!Tex i,xinput /external input files/ +!_TAG_KIND_DESCRIPTION!Tex l,label /labels/ +!_TAG_KIND_DESCRIPTION!Tex o,operator /math operator created with \\DeclareMathOperator/ +!_TAG_KIND_DESCRIPTION!Tex p,part /parts/ +!_TAG_KIND_DESCRIPTION!Tex s,section /sections/ +!_TAG_KIND_DESCRIPTION!Tex t,theorem /theorem created with \\newtheorem/ +!_TAG_KIND_DESCRIPTION!Tex u,subsection /subsections/ +!_TAG_OUTPUT_EXCMD mixed /number, pattern, mixed, or combineV2/ +!_TAG_OUTPUT_FILESEP slash /slash or backslash/ +!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/ +!_TAG_OUTPUT_VERSION 0.0 /current.age/ +!_TAG_PARSER_VERSION!Python 0.0 /current.age/ +!_TAG_PARSER_VERSION!Tex 0.0 /current.age/ +!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/ +!_TAG_PROC_CWD /home/grhkm/git/sage/ // +!_TAG_PROGRAM_AUTHOR Universal Ctags Team // +!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/ +!_TAG_PROGRAM_URL https://ctags.io/ /official site/ +!_TAG_PROGRAM_VERSION 6.0.0 // +!_TAG_ROLE_DESCRIPTION!Python!module imported /imported modules/ +!_TAG_ROLE_DESCRIPTION!Python!module indirectlyImported /module imported in alternative name/ +!_TAG_ROLE_DESCRIPTION!Python!module namespace /namespace from where classes\/variables\/functions are imported/ +!_TAG_ROLE_DESCRIPTION!Python!unknown imported /imported from the other module/ +!_TAG_ROLE_DESCRIPTION!Python!unknown indirectlyImported /classes\/variables\/functions\/modules imported in alternative name/ +!_TAG_ROLE_DESCRIPTION!Tex!xinput bibliography /bibliography (.bib) file/ +!_TAG_ROLE_DESCRIPTION!Tex!xinput included /external input file specified with \\include/ +!_TAG_ROLE_DESCRIPTION!Tex!xinput input /external input file specified with \\input/ +EllipticCurve_field src/sage/schemes/elliptic_curves/ell_field.py /^class EllipticCurve_field(ell_generic.EllipticCurve_generic, ProjectivePlaneCurve_field):$/;" c +Further improvements? src/sage/misc/notes/bernoulli_mod_p.tex /^\\section*{Further improvements?}$/;" s +GraphType src/sage/schemes/elliptic_curves/ell_field.py /^ from sage.graphs.digraph import DiGraph as GraphType$/;" Y member:EllipticCurve_field.isogeny_ell_graph file: nameref:unknown:DiGraph +GraphType src/sage/schemes/elliptic_curves/ell_field.py /^ from sage.graphs.graph import Graph as GraphType$/;" Y member:EllipticCurve_field.isogeny_ell_graph file: nameref:unknown:Graph +\\FF src/sage/misc/notes/bernoulli_mod_p.tex /^\\newcommand{\\FF}{\\mathbf{F}}$/;" C +\\Z src/sage/misc/notes/bernoulli_mod_p.tex /^\\newcommand{\\Z}{\\mathbf{Z}}$/;" C +\\ZZ src/sage/misc/notes/bernoulli_mod_p.tex /^\\newcommand{\\ZZ}{\\mathbf{Z}}$/;" C +_Hom_ src/sage/schemes/elliptic_curves/ell_field.py /^ def _Hom_(self, other, category=None):$/;" m class:EllipticCurve_field +__init__ src/sage/schemes/elliptic_curves/ell_field.py /^ def __init__(self, R, data, category=None):$/;" m class:EllipticCurve_field +_point src/sage/schemes/elliptic_curves/ell_field.py /^ _point = EllipticCurvePoint_field$/;" v class:EllipticCurve_field +base_field src/sage/schemes/elliptic_curves/ell_field.py /^ base_field = ell_generic.EllipticCurve_generic.base_ring$/;" v class:EllipticCurve_field +compute_key src/sage/schemes/elliptic_curves/ell_field.py /^ def compute_key(phi):$/;" f member:EllipticCurve_field.isogenies_degree file: +compute_model src/sage/schemes/elliptic_curves/ell_field.py /^def compute_model(E, name):$/;" f +descend_to src/sage/schemes/elliptic_curves/ell_field.py /^ def descend_to(self, K, f=None):$/;" m class:EllipticCurve_field +division_field src/sage/schemes/elliptic_curves/ell_field.py /^ def division_field(self, n, names='t', map=False, **kwds):$/;" m class:EllipticCurve_field +endomorphism_ring_is_commutative src/sage/schemes/elliptic_curves/ell_field.py /^ def endomorphism_ring_is_commutative(self):$/;" m class:EllipticCurve_field +ffext src/sage/schemes/elliptic_curves/ell_field.py /^ def ffext(poly):$/;" f function:point_of_order file: +genus src/sage/schemes/elliptic_curves/ell_field.py /^ def genus(self):$/;" m class:EllipticCurve_field +hasse_invariant src/sage/schemes/elliptic_curves/ell_field.py /^ def hasse_invariant(self):$/;" m class:EllipticCurve_field +insert_seen src/sage/schemes/elliptic_curves/ell_field.py /^ def insert_seen(phi):$/;" f member:EllipticCurve_field.isogenies_degree file: +is_isogenous src/sage/schemes/elliptic_curves/ell_field.py /^ def is_isogenous(self, other, field=None):$/;" m class:EllipticCurve_field +is_quadratic_twist src/sage/schemes/elliptic_curves/ell_field.py /^ def is_quadratic_twist(self, other):$/;" m class:EllipticCurve_field +is_quartic_twist src/sage/schemes/elliptic_curves/ell_field.py /^ def is_quartic_twist(self, other):$/;" m class:EllipticCurve_field +is_sextic_twist src/sage/schemes/elliptic_curves/ell_field.py /^ def is_sextic_twist(self, other):$/;" m class:EllipticCurve_field +isogenies_degree src/sage/schemes/elliptic_curves/ell_field.py /^ def isogenies_degree(self, n, *, _intermediate=False):$/;" m class:EllipticCurve_field +isogenies_prime_degree src/sage/schemes/elliptic_curves/ell_field.py /^ def isogenies_prime_degree(self, l=None, max_l=31):$/;" m class:EllipticCurve_field +isogeny src/sage/schemes/elliptic_curves/ell_field.py /^ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, algorithm=None/;" m class:EllipticCurve_field +isogeny_codomain src/sage/schemes/elliptic_curves/ell_field.py /^ def isogeny_codomain(self, kernel):$/;" m class:EllipticCurve_field +isogeny_ell_graph src/sage/schemes/elliptic_curves/ell_field.py /^ def isogeny_ell_graph(self, l, directed=True, label_by_j=False):$/;" m class:EllipticCurve_field +kernel_polynomial_from_divisor src/sage/schemes/elliptic_curves/ell_field.py /^ def kernel_polynomial_from_divisor(self, f, l, *, check=True):$/;" m class:EllipticCurve_field +kernel_polynomial_from_point src/sage/schemes/elliptic_curves/ell_field.py /^ def kernel_polynomial_from_point(self, P, *, algorithm=None):$/;" m class:EllipticCurve_field +mul_a src/sage/schemes/elliptic_curves/ell_field.py /^ mul_a = lambda x: self._multiple_x_numerator(a, x=x) \/ self._multiple_x_denominator(a, /;" f member:EllipticCurve_field.kernel_polynomial_from_divisor file: +point_of_order src/sage/schemes/elliptic_curves/ell_field.py /^def point_of_order(E, n):$/;" f +quadratic_twist src/sage/schemes/elliptic_curves/ell_field.py /^ def quadratic_twist(self, D=None):$/;" m class:EllipticCurve_field +quartic_twist src/sage/schemes/elliptic_curves/ell_field.py /^ def quartic_twist(self, D):$/;" m class:EllipticCurve_field +sextic_twist src/sage/schemes/elliptic_curves/ell_field.py /^ def sextic_twist(self, D):$/;" m class:EllipticCurve_field +two_torsion_rank src/sage/schemes/elliptic_curves/ell_field.py /^ def two_torsion_rank(self):$/;" m class:EllipticCurve_field +weierstrass_p src/sage/schemes/elliptic_curves/ell_field.py /^ def weierstrass_p(self, prec=20, algorithm=None):$/;" m class:EllipticCurve_field +x_mod src/sage/schemes/elliptic_curves/ell_field.py /^ x_mod = lambda g: g.parent().quotient(g).gen()$/;" f member:EllipticCurve_field.kernel_polynomial_from_divisor file: