passagemath-schemes 10.6.38__cp314-cp314t-macosx_13_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-schemes might be problematic. Click here for more details.
- passagemath_schemes/.dylibs/libflint.21.0.dylib +0 -0
- passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
- passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
- passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
- passagemath_schemes/__init__.py +3 -0
- passagemath_schemes-10.6.38.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.38.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.38.dist-info/RECORD +314 -0
- passagemath_schemes-10.6.38.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.38.dist-info/top_level.txt +3 -0
- sage/all__sagemath_schemes.py +23 -0
- sage/databases/all__sagemath_schemes.py +7 -0
- sage/databases/cremona.py +1723 -0
- sage/dynamics/all__sagemath_schemes.py +2 -0
- sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
- sage/dynamics/arithmetic_dynamics/all.py +14 -0
- sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
- sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
- sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
- sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
- sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
- sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
- sage/dynamics/arithmetic_dynamics/projective_ds.py +9558 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314t-darwin.so +0 -0
- sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
- sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
- sage/lfunctions/all.py +18 -0
- sage/lfunctions/dokchitser.py +745 -0
- sage/lfunctions/pari.py +818 -0
- sage/lfunctions/zero_sums.cpython-314t-darwin.so +0 -0
- sage/lfunctions/zero_sums.pyx +1847 -0
- sage/modular/abvar/abvar.py +5135 -0
- sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
- sage/modular/abvar/abvar_newform.py +244 -0
- sage/modular/abvar/all.py +8 -0
- sage/modular/abvar/constructor.py +186 -0
- sage/modular/abvar/cuspidal_subgroup.py +371 -0
- sage/modular/abvar/finite_subgroup.py +896 -0
- sage/modular/abvar/homology.py +720 -0
- sage/modular/abvar/homspace.py +998 -0
- sage/modular/abvar/lseries.py +415 -0
- sage/modular/abvar/morphism.py +935 -0
- sage/modular/abvar/torsion_point.py +274 -0
- sage/modular/abvar/torsion_subgroup.py +740 -0
- sage/modular/all.py +43 -0
- sage/modular/arithgroup/all.py +20 -0
- sage/modular/arithgroup/arithgroup_element.cpython-314t-darwin.so +0 -0
- sage/modular/arithgroup/arithgroup_element.pyx +474 -0
- sage/modular/arithgroup/arithgroup_generic.py +1402 -0
- sage/modular/arithgroup/arithgroup_perm.py +2692 -0
- sage/modular/arithgroup/congroup.cpython-314t-darwin.so +0 -0
- sage/modular/arithgroup/congroup.pyx +334 -0
- sage/modular/arithgroup/congroup_gamma.py +363 -0
- sage/modular/arithgroup/congroup_gamma0.py +692 -0
- sage/modular/arithgroup/congroup_gamma1.py +653 -0
- sage/modular/arithgroup/congroup_gammaH.py +1469 -0
- sage/modular/arithgroup/congroup_generic.py +628 -0
- sage/modular/arithgroup/congroup_sl2z.py +267 -0
- sage/modular/arithgroup/farey_symbol.cpython-314t-darwin.so +0 -0
- sage/modular/arithgroup/farey_symbol.pyx +1066 -0
- sage/modular/arithgroup/tests.py +418 -0
- sage/modular/btquotients/all.py +4 -0
- sage/modular/btquotients/btquotient.py +3753 -0
- sage/modular/btquotients/pautomorphicform.py +2570 -0
- sage/modular/buzzard.py +100 -0
- sage/modular/congroup.py +29 -0
- sage/modular/congroup_element.py +13 -0
- sage/modular/cusps.py +1109 -0
- sage/modular/cusps_nf.py +1270 -0
- sage/modular/dims.py +569 -0
- sage/modular/dirichlet.py +3310 -0
- sage/modular/drinfeld_modform/all.py +2 -0
- sage/modular/drinfeld_modform/element.py +446 -0
- sage/modular/drinfeld_modform/ring.py +773 -0
- sage/modular/drinfeld_modform/tutorial.py +236 -0
- sage/modular/etaproducts.py +1065 -0
- sage/modular/hecke/algebra.py +746 -0
- sage/modular/hecke/all.py +20 -0
- sage/modular/hecke/ambient_module.py +1019 -0
- sage/modular/hecke/degenmap.py +119 -0
- sage/modular/hecke/element.py +325 -0
- sage/modular/hecke/hecke_operator.py +780 -0
- sage/modular/hecke/homspace.py +206 -0
- sage/modular/hecke/module.py +1767 -0
- sage/modular/hecke/morphism.py +174 -0
- sage/modular/hecke/submodule.py +989 -0
- sage/modular/hypergeometric_misc.cpython-314t-darwin.so +0 -0
- sage/modular/hypergeometric_misc.pxd +4 -0
- sage/modular/hypergeometric_misc.pyx +166 -0
- sage/modular/hypergeometric_motive.py +2017 -0
- sage/modular/local_comp/all.py +2 -0
- sage/modular/local_comp/liftings.py +292 -0
- sage/modular/local_comp/local_comp.py +1071 -0
- sage/modular/local_comp/smoothchar.py +1825 -0
- sage/modular/local_comp/type_space.py +748 -0
- sage/modular/modform/all.py +30 -0
- sage/modular/modform/ambient.py +815 -0
- sage/modular/modform/ambient_R.py +177 -0
- sage/modular/modform/ambient_eps.py +306 -0
- sage/modular/modform/ambient_g0.py +124 -0
- sage/modular/modform/ambient_g1.py +204 -0
- sage/modular/modform/constructor.py +545 -0
- sage/modular/modform/cuspidal_submodule.py +708 -0
- sage/modular/modform/defaults.py +14 -0
- sage/modular/modform/eis_series.py +505 -0
- sage/modular/modform/eisenstein_submodule.py +663 -0
- sage/modular/modform/element.py +4131 -0
- sage/modular/modform/find_generators.py +59 -0
- sage/modular/modform/half_integral.py +154 -0
- sage/modular/modform/hecke_operator_on_qexp.py +247 -0
- sage/modular/modform/j_invariant.py +47 -0
- sage/modular/modform/l_series_gross_zagier.py +133 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314t-darwin.so +0 -0
- sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
- sage/modular/modform/notes.py +45 -0
- sage/modular/modform/numerical.py +514 -0
- sage/modular/modform/periods.py +14 -0
- sage/modular/modform/ring.py +1257 -0
- sage/modular/modform/space.py +1860 -0
- sage/modular/modform/submodule.py +118 -0
- sage/modular/modform/tests.py +64 -0
- sage/modular/modform/theta.py +110 -0
- sage/modular/modform/vm_basis.py +381 -0
- sage/modular/modform/weight1.py +220 -0
- sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
- sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
- sage/modular/modform_hecketriangle/all.py +30 -0
- sage/modular/modform_hecketriangle/analytic_type.py +590 -0
- sage/modular/modform_hecketriangle/constructor.py +416 -0
- sage/modular/modform_hecketriangle/element.py +351 -0
- sage/modular/modform_hecketriangle/functors.py +752 -0
- sage/modular/modform_hecketriangle/graded_ring.py +541 -0
- sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
- sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
- sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
- sage/modular/modform_hecketriangle/readme.py +1214 -0
- sage/modular/modform_hecketriangle/series_constructor.py +580 -0
- sage/modular/modform_hecketriangle/space.py +1037 -0
- sage/modular/modform_hecketriangle/subspace.py +423 -0
- sage/modular/modsym/all.py +17 -0
- sage/modular/modsym/ambient.py +3846 -0
- sage/modular/modsym/boundary.py +1420 -0
- sage/modular/modsym/element.py +336 -0
- sage/modular/modsym/g1list.py +178 -0
- sage/modular/modsym/ghlist.py +182 -0
- sage/modular/modsym/hecke_operator.py +73 -0
- sage/modular/modsym/manin_symbol.cpython-314t-darwin.so +0 -0
- sage/modular/modsym/manin_symbol.pxd +5 -0
- sage/modular/modsym/manin_symbol.pyx +497 -0
- sage/modular/modsym/manin_symbol_list.py +1295 -0
- sage/modular/modsym/modsym.py +400 -0
- sage/modular/modsym/modular_symbols.py +384 -0
- sage/modular/modsym/p1list.cpython-314t-darwin.so +0 -0
- sage/modular/modsym/p1list.pxd +29 -0
- sage/modular/modsym/p1list.pyx +1372 -0
- sage/modular/modsym/p1list_nf.py +1241 -0
- sage/modular/modsym/relation_matrix.py +591 -0
- sage/modular/modsym/relation_matrix_pyx.cpython-314t-darwin.so +0 -0
- sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
- sage/modular/modsym/space.py +2468 -0
- sage/modular/modsym/subspace.py +455 -0
- sage/modular/modsym/tests.py +375 -0
- sage/modular/multiple_zeta.py +2632 -0
- sage/modular/multiple_zeta_F_algebra.py +786 -0
- sage/modular/overconvergent/all.py +6 -0
- sage/modular/overconvergent/genus0.py +1878 -0
- sage/modular/overconvergent/hecke_series.py +1187 -0
- sage/modular/overconvergent/weightspace.py +778 -0
- sage/modular/pollack_stevens/all.py +4 -0
- sage/modular/pollack_stevens/distributions.py +874 -0
- sage/modular/pollack_stevens/fund_domain.py +1572 -0
- sage/modular/pollack_stevens/manin_map.py +859 -0
- sage/modular/pollack_stevens/modsym.py +1593 -0
- sage/modular/pollack_stevens/padic_lseries.py +417 -0
- sage/modular/pollack_stevens/sigma0.py +534 -0
- sage/modular/pollack_stevens/space.py +1076 -0
- sage/modular/quasimodform/all.py +3 -0
- sage/modular/quasimodform/element.py +845 -0
- sage/modular/quasimodform/ring.py +828 -0
- sage/modular/quatalg/all.py +3 -0
- sage/modular/quatalg/brandt.py +1642 -0
- sage/modular/ssmod/all.py +8 -0
- sage/modular/ssmod/ssmod.py +827 -0
- sage/rings/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/all__sagemath_schemes.py +1 -0
- sage/rings/polynomial/binary_form_reduce.py +585 -0
- sage/schemes/all.py +41 -0
- sage/schemes/berkovich/all.py +6 -0
- sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
- sage/schemes/berkovich/berkovich_space.py +748 -0
- sage/schemes/curves/affine_curve.py +2928 -0
- sage/schemes/curves/all.py +33 -0
- sage/schemes/curves/closed_point.py +434 -0
- sage/schemes/curves/constructor.py +381 -0
- sage/schemes/curves/curve.py +542 -0
- sage/schemes/curves/plane_curve_arrangement.py +1283 -0
- sage/schemes/curves/point.py +463 -0
- sage/schemes/curves/projective_curve.py +3026 -0
- sage/schemes/curves/zariski_vankampen.py +1932 -0
- sage/schemes/cyclic_covers/all.py +2 -0
- sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
- sage/schemes/cyclic_covers/constructor.py +137 -0
- sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
- sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
- sage/schemes/elliptic_curves/BSD.py +1036 -0
- sage/schemes/elliptic_curves/Qcurves.py +592 -0
- sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
- sage/schemes/elliptic_curves/all.py +49 -0
- sage/schemes/elliptic_curves/cardinality.py +609 -0
- sage/schemes/elliptic_curves/cm.py +1102 -0
- sage/schemes/elliptic_curves/constructor.py +1552 -0
- sage/schemes/elliptic_curves/ec_database.py +175 -0
- sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
- sage/schemes/elliptic_curves/ell_egros.py +459 -0
- sage/schemes/elliptic_curves/ell_field.py +2836 -0
- sage/schemes/elliptic_curves/ell_finite_field.py +3359 -0
- sage/schemes/elliptic_curves/ell_generic.py +3760 -0
- sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
- sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
- sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
- sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
- sage/schemes/elliptic_curves/ell_point.py +4787 -0
- sage/schemes/elliptic_curves/ell_rational_field.py +7368 -0
- sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
- sage/schemes/elliptic_curves/ell_torsion.py +436 -0
- sage/schemes/elliptic_curves/ell_wp.py +352 -0
- sage/schemes/elliptic_curves/formal_group.py +760 -0
- sage/schemes/elliptic_curves/gal_reps.py +1459 -0
- sage/schemes/elliptic_curves/gal_reps_number_field.py +1669 -0
- sage/schemes/elliptic_curves/gp_simon.py +152 -0
- sage/schemes/elliptic_curves/heegner.py +7335 -0
- sage/schemes/elliptic_curves/height.py +2109 -0
- sage/schemes/elliptic_curves/hom.py +1406 -0
- sage/schemes/elliptic_curves/hom_composite.py +934 -0
- sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
- sage/schemes/elliptic_curves/hom_scalar.py +531 -0
- sage/schemes/elliptic_curves/hom_sum.py +682 -0
- sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
- sage/schemes/elliptic_curves/homset.py +271 -0
- sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
- sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
- sage/schemes/elliptic_curves/jacobian.py +237 -0
- sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
- sage/schemes/elliptic_curves/kraus.py +1014 -0
- sage/schemes/elliptic_curves/lseries_ell.py +943 -0
- sage/schemes/elliptic_curves/mod5family.py +105 -0
- sage/schemes/elliptic_curves/mod_poly.py +197 -0
- sage/schemes/elliptic_curves/mod_sym_num.cpython-314t-darwin.so +0 -0
- sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
- sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
- sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
- sage/schemes/elliptic_curves/padics.py +1816 -0
- sage/schemes/elliptic_curves/period_lattice.py +2234 -0
- sage/schemes/elliptic_curves/period_lattice_region.cpython-314t-darwin.so +0 -0
- sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
- sage/schemes/elliptic_curves/saturation.py +715 -0
- sage/schemes/elliptic_curves/sha_tate.py +1158 -0
- sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
- sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
- sage/schemes/hyperelliptic_curves/all.py +6 -0
- sage/schemes/hyperelliptic_curves/constructor.py +291 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
- sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
- sage/schemes/hyperelliptic_curves/invariants.py +410 -0
- sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
- sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
- sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
- sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
- sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
- sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
- sage/schemes/hyperelliptic_curves/mestre.py +302 -0
- sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
- sage/schemes/jacobians/abstract_jacobian.py +277 -0
- sage/schemes/jacobians/all.py +2 -0
- sage/schemes/overview.py +161 -0
- sage/schemes/plane_conics/all.py +22 -0
- sage/schemes/plane_conics/con_field.py +1296 -0
- sage/schemes/plane_conics/con_finite_field.py +158 -0
- sage/schemes/plane_conics/con_number_field.py +456 -0
- sage/schemes/plane_conics/con_rational_field.py +406 -0
- sage/schemes/plane_conics/con_rational_function_field.py +580 -0
- sage/schemes/plane_conics/constructor.py +249 -0
- sage/schemes/plane_quartics/all.py +2 -0
- sage/schemes/plane_quartics/quartic_constructor.py +71 -0
- sage/schemes/plane_quartics/quartic_generic.py +73 -0
- sage/schemes/riemann_surfaces/all.py +1 -0
- sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
- sage_wheels/share/cremona/cremona_mini.db +0 -0
- sage_wheels/share/ellcurves/rank0 +30427 -0
- sage_wheels/share/ellcurves/rank1 +31871 -0
- sage_wheels/share/ellcurves/rank10 +6 -0
- sage_wheels/share/ellcurves/rank11 +6 -0
- sage_wheels/share/ellcurves/rank12 +1 -0
- sage_wheels/share/ellcurves/rank14 +1 -0
- sage_wheels/share/ellcurves/rank15 +1 -0
- sage_wheels/share/ellcurves/rank17 +1 -0
- sage_wheels/share/ellcurves/rank19 +1 -0
- sage_wheels/share/ellcurves/rank2 +2388 -0
- sage_wheels/share/ellcurves/rank20 +1 -0
- sage_wheels/share/ellcurves/rank21 +1 -0
- sage_wheels/share/ellcurves/rank22 +1 -0
- sage_wheels/share/ellcurves/rank23 +1 -0
- sage_wheels/share/ellcurves/rank24 +1 -0
- sage_wheels/share/ellcurves/rank28 +1 -0
- sage_wheels/share/ellcurves/rank3 +836 -0
- sage_wheels/share/ellcurves/rank4 +10 -0
- sage_wheels/share/ellcurves/rank5 +5 -0
- sage_wheels/share/ellcurves/rank6 +5 -0
- sage_wheels/share/ellcurves/rank7 +5 -0
- sage_wheels/share/ellcurves/rank8 +6 -0
- sage_wheels/share/ellcurves/rank9 +7 -0
|
@@ -0,0 +1,2836 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
r"""
|
|
3
|
+
Elliptic curves over a general field
|
|
4
|
+
|
|
5
|
+
This module defines the class :class:`EllipticCurve_field`, based on
|
|
6
|
+
:class:`EllipticCurve_generic`, for elliptic curves over general fields.
|
|
7
|
+
"""
|
|
8
|
+
# *****************************************************************************
|
|
9
|
+
# Copyright (C) 2006 William Stein <wstein@gmail.com>
|
|
10
|
+
#
|
|
11
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
12
|
+
#
|
|
13
|
+
# https://www.gnu.org/licenses/
|
|
14
|
+
# *****************************************************************************
|
|
15
|
+
|
|
16
|
+
import sage.rings.abc
|
|
17
|
+
from sage.categories.number_fields import NumberFields
|
|
18
|
+
from sage.categories.finite_fields import FiniteFields
|
|
19
|
+
from sage.rings.integer import Integer
|
|
20
|
+
from sage.rings.integer_ring import ZZ
|
|
21
|
+
from sage.rings.polynomial.polynomial_ring import polygen
|
|
22
|
+
from sage.rings.rational_field import QQ
|
|
23
|
+
from sage.misc.misc_c import prod
|
|
24
|
+
from sage.schemes.elliptic_curves.ell_point import EllipticCurvePoint_field
|
|
25
|
+
from sage.schemes.curves.projective_curve import ProjectivePlaneCurve_field
|
|
26
|
+
|
|
27
|
+
from .constructor import EllipticCurve
|
|
28
|
+
from .ell_curve_isogeny import EllipticCurveIsogeny, isogeny_codomain_from_kernel
|
|
29
|
+
from . import ell_generic
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class EllipticCurve_field(ell_generic.EllipticCurve_generic, ProjectivePlaneCurve_field):
|
|
33
|
+
|
|
34
|
+
def __init__(self, R, data, category=None) -> None:
|
|
35
|
+
r"""
|
|
36
|
+
Constructor for elliptic curves over fields.
|
|
37
|
+
|
|
38
|
+
Identical to the constructor for elliptic curves over
|
|
39
|
+
general rings, except for setting the default category
|
|
40
|
+
to :class:`AbelianVarieties`.
|
|
41
|
+
|
|
42
|
+
EXAMPLES::
|
|
43
|
+
|
|
44
|
+
sage: E = EllipticCurve(QQ, [1,1])
|
|
45
|
+
sage: E.category()
|
|
46
|
+
Category of abelian varieties over Rational Field
|
|
47
|
+
sage: E = EllipticCurve(GF(101), [1,1])
|
|
48
|
+
sage: E.category()
|
|
49
|
+
Category of abelian varieties over Finite Field of size 101
|
|
50
|
+
"""
|
|
51
|
+
from sage.categories.schemes import AbelianVarieties
|
|
52
|
+
if category is None:
|
|
53
|
+
category = AbelianVarieties(R)
|
|
54
|
+
super().__init__(R, data, category=category)
|
|
55
|
+
|
|
56
|
+
base_field = ell_generic.EllipticCurve_generic.base_ring
|
|
57
|
+
|
|
58
|
+
_point = EllipticCurvePoint_field
|
|
59
|
+
|
|
60
|
+
# Twists: rewritten by John Cremona as follows:
|
|
61
|
+
#
|
|
62
|
+
# Quadratic twist allowed except when char=2, j=0
|
|
63
|
+
# Quartic twist allowed only if j=1728!=0 (so char!=2,3)
|
|
64
|
+
# Sextic twist allowed only if j=0!=1728 (so char!=2,3)
|
|
65
|
+
#
|
|
66
|
+
# More complicated twists exist in theory for char=2,3 and
|
|
67
|
+
# j=0=1728, but I have never worked them out or seen them used!
|
|
68
|
+
#
|
|
69
|
+
|
|
70
|
+
def genus(self) -> Integer:
|
|
71
|
+
"""
|
|
72
|
+
Return 1 for elliptic curves.
|
|
73
|
+
|
|
74
|
+
EXAMPLES::
|
|
75
|
+
|
|
76
|
+
sage: E = EllipticCurve(GF(3), [0, -1, 0, -346, 2652])
|
|
77
|
+
sage: E.genus()
|
|
78
|
+
1
|
|
79
|
+
|
|
80
|
+
sage: R = FractionField(QQ['z'])
|
|
81
|
+
sage: E = EllipticCurve(R, [0, -1, 0, -346, 2652])
|
|
82
|
+
sage: E.genus()
|
|
83
|
+
1
|
|
84
|
+
"""
|
|
85
|
+
return ZZ.one()
|
|
86
|
+
|
|
87
|
+
r"""
|
|
88
|
+
Twists: rewritten by John Cremona as follows:
|
|
89
|
+
|
|
90
|
+
The following twists are implemented:
|
|
91
|
+
|
|
92
|
+
- Quadratic twist: except when char=2 and `j=0`.
|
|
93
|
+
- Quartic twist: only if `j=1728\not=0` (so not if char=2,3).
|
|
94
|
+
- Sextic twist: only if `j=0\not=1728` (so not if char=2,3).
|
|
95
|
+
|
|
96
|
+
More complicated twists exist in theory for char=2,3 and j=0=1728,
|
|
97
|
+
but are not implemented.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
def quadratic_twist(self, D=None):
|
|
101
|
+
r"""
|
|
102
|
+
Return the quadratic twist of this curve by ``D``.
|
|
103
|
+
|
|
104
|
+
INPUT:
|
|
105
|
+
|
|
106
|
+
- ``D`` -- (default: ``None``) the twisting parameter (see below)
|
|
107
|
+
|
|
108
|
+
In characteristics other than 2, `D` must be nonzero, and the
|
|
109
|
+
twist is isomorphic to ``self`` after adjoining `\sqrt(D)` to the
|
|
110
|
+
base.
|
|
111
|
+
|
|
112
|
+
In characteristic 2, `D` is arbitrary, and the twist is
|
|
113
|
+
isomorphic to ``self`` after adjoining a root of `x^2+x+D` to the
|
|
114
|
+
base.
|
|
115
|
+
|
|
116
|
+
In characteristic 2 when `j=0`, this is not implemented.
|
|
117
|
+
|
|
118
|
+
If the base field `F` is finite, `D` need not be specified,
|
|
119
|
+
and the curve returned is the unique curve (up to isomorphism)
|
|
120
|
+
defined over `F` isomorphic to the original curve over the
|
|
121
|
+
quadratic extension of `F` but not over `F` itself. Over
|
|
122
|
+
infinite fields, an error is raised if `D` is not given.
|
|
123
|
+
|
|
124
|
+
EXAMPLES::
|
|
125
|
+
|
|
126
|
+
sage: # needs sage.rings.finite_rings
|
|
127
|
+
sage: E = EllipticCurve([GF(1103)(1), 0, 0, 107, 340]); E
|
|
128
|
+
Elliptic Curve defined by y^2 + x*y = x^3 + 107*x + 340
|
|
129
|
+
over Finite Field of size 1103
|
|
130
|
+
sage: F = E.quadratic_twist(-1); F
|
|
131
|
+
Elliptic Curve defined by y^2 = x^3 + 1102*x^2 + 609*x + 300
|
|
132
|
+
over Finite Field of size 1103
|
|
133
|
+
sage: E.is_isomorphic(F)
|
|
134
|
+
False
|
|
135
|
+
sage: E.is_isomorphic(F, GF(1103^2,'a'))
|
|
136
|
+
True
|
|
137
|
+
|
|
138
|
+
A characteristic 2 example::
|
|
139
|
+
|
|
140
|
+
sage: E = EllipticCurve(GF(2), [1,0,1,1,1])
|
|
141
|
+
sage: E1 = E.quadratic_twist(1)
|
|
142
|
+
sage: E.is_isomorphic(E1)
|
|
143
|
+
False
|
|
144
|
+
sage: E.is_isomorphic(E1, GF(4,'a'))
|
|
145
|
+
True
|
|
146
|
+
|
|
147
|
+
Over finite fields, the twisting parameter may be omitted::
|
|
148
|
+
|
|
149
|
+
sage: # needs sage.rings.finite_rings
|
|
150
|
+
sage: k.<a> = GF(2^10)
|
|
151
|
+
sage: E = EllipticCurve(k, [a^2,a,1,a+1,1])
|
|
152
|
+
sage: Et = E.quadratic_twist()
|
|
153
|
+
sage: Et # random (only determined up to isomorphism)
|
|
154
|
+
Elliptic Curve defined
|
|
155
|
+
by y^2 + x*y = x^3 + (a^7+a^4+a^3+a^2+a+1)*x^2 + (a^8+a^6+a^4+1)
|
|
156
|
+
over Finite Field in a of size 2^10
|
|
157
|
+
sage: E.is_isomorphic(Et)
|
|
158
|
+
False
|
|
159
|
+
sage: E.j_invariant() == Et.j_invariant()
|
|
160
|
+
True
|
|
161
|
+
|
|
162
|
+
sage: # needs sage.rings.finite_rings
|
|
163
|
+
sage: p = next_prime(10^10)
|
|
164
|
+
sage: k = GF(p)
|
|
165
|
+
sage: E = EllipticCurve(k, [1,2,3,4,5])
|
|
166
|
+
sage: Et = E.quadratic_twist()
|
|
167
|
+
sage: Et # random (only determined up to isomorphism)
|
|
168
|
+
Elliptic Curve defined
|
|
169
|
+
by y^2 = x^3 + 7860088097*x^2 + 9495240877*x + 3048660957
|
|
170
|
+
over Finite Field of size 10000000019
|
|
171
|
+
sage: E.is_isomorphic(Et)
|
|
172
|
+
False
|
|
173
|
+
sage: k2 = GF(p^2,'a')
|
|
174
|
+
sage: E.change_ring(k2).is_isomorphic(Et.change_ring(k2))
|
|
175
|
+
True
|
|
176
|
+
"""
|
|
177
|
+
K = self.base_ring()
|
|
178
|
+
char = K.characteristic()
|
|
179
|
+
|
|
180
|
+
if D is None:
|
|
181
|
+
if K.is_finite():
|
|
182
|
+
x = polygen(K)
|
|
183
|
+
if char == 2:
|
|
184
|
+
# We find D such that x^2+x+D is irreducible. If the
|
|
185
|
+
# degree is odd we can take D=1; otherwise it suffices to
|
|
186
|
+
# consider odd powers of a generator.
|
|
187
|
+
D = K(1)
|
|
188
|
+
if K.degree() % 2 == 0:
|
|
189
|
+
D = K.gen()
|
|
190
|
+
a = D**2
|
|
191
|
+
while (x**2 + x + D).roots():
|
|
192
|
+
D *= a
|
|
193
|
+
else:
|
|
194
|
+
# We could take a multiplicative generator but
|
|
195
|
+
# that might be expensive to compute; otherwise
|
|
196
|
+
# half the elements will do, and testing squares
|
|
197
|
+
# is very fast.
|
|
198
|
+
D = K.random_element()
|
|
199
|
+
while D.is_square():
|
|
200
|
+
D = K.random_element()
|
|
201
|
+
else:
|
|
202
|
+
raise ValueError("twisting parameter D must be specified over infinite fields.")
|
|
203
|
+
else:
|
|
204
|
+
try:
|
|
205
|
+
D = K(D)
|
|
206
|
+
except ValueError:
|
|
207
|
+
raise ValueError("twisting parameter D must be in the base field.")
|
|
208
|
+
|
|
209
|
+
if char != 2 and D.is_zero():
|
|
210
|
+
raise ValueError("twisting parameter D must be nonzero when characteristic is not 2")
|
|
211
|
+
|
|
212
|
+
if char != 2:
|
|
213
|
+
b2, b4, b6, b8 = self.b_invariants()
|
|
214
|
+
# E is isomorphic to [0,b2,0,8*b4,16*b6]
|
|
215
|
+
return EllipticCurve(K, [0, b2*D, 0, 8*b4*D**2, 16*b6*D**3])
|
|
216
|
+
|
|
217
|
+
# now char==2
|
|
218
|
+
if self.j_invariant() != 0: # iff a1!=0
|
|
219
|
+
a1, a2, a3, a4, a6 = self.ainvs()
|
|
220
|
+
E0 = self.change_weierstrass_model(a1, a3/a1, 0, (a1**2*a4+a3**2)/a1**3)
|
|
221
|
+
# which has the form = [1,A2,0,0,A6]
|
|
222
|
+
assert E0.a1() == K(1)
|
|
223
|
+
assert E0.a3() == K(0)
|
|
224
|
+
assert E0.a4() == K(0)
|
|
225
|
+
return EllipticCurve(K, [1, E0.a2() + D, 0, 0, E0.a6()])
|
|
226
|
+
else:
|
|
227
|
+
raise ValueError("Quadratic twist not implemented in char 2 when j=0")
|
|
228
|
+
|
|
229
|
+
def two_torsion_rank(self):
|
|
230
|
+
r"""
|
|
231
|
+
Return the dimension of the 2-torsion subgroup of
|
|
232
|
+
`E(K)`.
|
|
233
|
+
|
|
234
|
+
This will be 0, 1 or 2.
|
|
235
|
+
|
|
236
|
+
EXAMPLES::
|
|
237
|
+
|
|
238
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
239
|
+
sage: E = EllipticCurve('11a1')
|
|
240
|
+
sage: E.two_torsion_rank()
|
|
241
|
+
0
|
|
242
|
+
sage: K.<alpha> = QQ.extension(E.division_polynomial(2).monic()) # needs sage.rings.number_field
|
|
243
|
+
sage: E.base_extend(K).two_torsion_rank() # needs sage.rings.number_field
|
|
244
|
+
1
|
|
245
|
+
sage: E.reduction(53).two_torsion_rank()
|
|
246
|
+
2
|
|
247
|
+
|
|
248
|
+
::
|
|
249
|
+
|
|
250
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
251
|
+
sage: E = EllipticCurve('14a1')
|
|
252
|
+
sage: E.two_torsion_rank()
|
|
253
|
+
1
|
|
254
|
+
sage: f = E.division_polynomial(2).monic().factor()[1][0]
|
|
255
|
+
sage: K.<alpha> = QQ.extension(f) # needs sage.rings.number_field
|
|
256
|
+
sage: E.base_extend(K).two_torsion_rank() # needs sage.rings.number_field
|
|
257
|
+
2
|
|
258
|
+
|
|
259
|
+
::
|
|
260
|
+
|
|
261
|
+
sage: EllipticCurve('15a1').two_torsion_rank() # needs database_cremona_mini_ellcurve
|
|
262
|
+
2
|
|
263
|
+
"""
|
|
264
|
+
f = self.division_polynomial(Integer(2))
|
|
265
|
+
n = len(f.roots()) + 1
|
|
266
|
+
return Integer(n).ord(Integer(2))
|
|
267
|
+
|
|
268
|
+
def quartic_twist(self, D):
|
|
269
|
+
r"""
|
|
270
|
+
Return the quartic twist of this curve by `D`.
|
|
271
|
+
|
|
272
|
+
INPUT:
|
|
273
|
+
|
|
274
|
+
- ``D`` -- (must be nonzero) the twisting parameter
|
|
275
|
+
|
|
276
|
+
.. NOTE::
|
|
277
|
+
|
|
278
|
+
The characteristic must not be 2 or 3, and the `j`-invariant must be 1728.
|
|
279
|
+
|
|
280
|
+
EXAMPLES::
|
|
281
|
+
|
|
282
|
+
sage: # needs sage.rings.finite_rings
|
|
283
|
+
sage: E = EllipticCurve_from_j(GF(13)(1728)); E
|
|
284
|
+
Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 13
|
|
285
|
+
sage: E1 = E.quartic_twist(2); E1
|
|
286
|
+
Elliptic Curve defined by y^2 = x^3 + 5*x over Finite Field of size 13
|
|
287
|
+
sage: E.is_isomorphic(E1)
|
|
288
|
+
False
|
|
289
|
+
sage: E.is_isomorphic(E1, GF(13^2,'a'))
|
|
290
|
+
False
|
|
291
|
+
sage: E.is_isomorphic(E1, GF(13^4,'a'))
|
|
292
|
+
True
|
|
293
|
+
"""
|
|
294
|
+
K = self.base_ring()
|
|
295
|
+
char = K.characteristic()
|
|
296
|
+
D = K(D)
|
|
297
|
+
|
|
298
|
+
if char == 2 or char == 3:
|
|
299
|
+
raise ValueError("Quartic twist not defined in chars 2,3")
|
|
300
|
+
|
|
301
|
+
if self.j_invariant() != K(1728):
|
|
302
|
+
raise ValueError("Quartic twist not defined when j!=1728")
|
|
303
|
+
|
|
304
|
+
if D.is_zero():
|
|
305
|
+
raise ValueError("quartic twist requires a nonzero argument")
|
|
306
|
+
|
|
307
|
+
c4, c6 = self.c_invariants()
|
|
308
|
+
# E is isomorphic to [0,0,0,-27*c4,0]
|
|
309
|
+
assert c6 == 0
|
|
310
|
+
return EllipticCurve(K, [0, 0, 0, -27 * c4 * D, 0])
|
|
311
|
+
|
|
312
|
+
def sextic_twist(self, D):
|
|
313
|
+
r"""
|
|
314
|
+
Return the sextic twist of this curve by `D`.
|
|
315
|
+
|
|
316
|
+
INPUT:
|
|
317
|
+
|
|
318
|
+
- ``D`` -- (must be nonzero) the twisting parameter
|
|
319
|
+
|
|
320
|
+
.. NOTE::
|
|
321
|
+
|
|
322
|
+
The characteristic must not be 2 or 3, and the `j`-invariant must be 0.
|
|
323
|
+
|
|
324
|
+
EXAMPLES::
|
|
325
|
+
|
|
326
|
+
sage: # needs sage.rings.finite_rings
|
|
327
|
+
sage: E = EllipticCurve_from_j(GF(13)(0)); E
|
|
328
|
+
Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 13
|
|
329
|
+
sage: E1 = E.sextic_twist(2); E1
|
|
330
|
+
Elliptic Curve defined by y^2 = x^3 + 11 over Finite Field of size 13
|
|
331
|
+
sage: E.is_isomorphic(E1)
|
|
332
|
+
False
|
|
333
|
+
sage: E.is_isomorphic(E1, GF(13^2,'a'))
|
|
334
|
+
False
|
|
335
|
+
sage: E.is_isomorphic(E1, GF(13^4,'a'))
|
|
336
|
+
False
|
|
337
|
+
sage: E.is_isomorphic(E1, GF(13^6,'a'))
|
|
338
|
+
True
|
|
339
|
+
"""
|
|
340
|
+
K = self.base_ring()
|
|
341
|
+
char = K.characteristic()
|
|
342
|
+
D = K(D)
|
|
343
|
+
|
|
344
|
+
if char == 2 or char == 3:
|
|
345
|
+
raise ValueError("Sextic twist not defined in chars 2,3")
|
|
346
|
+
|
|
347
|
+
if self.j_invariant() != K(0):
|
|
348
|
+
raise ValueError("Sextic twist not defined when j!=0")
|
|
349
|
+
|
|
350
|
+
if D.is_zero():
|
|
351
|
+
raise ValueError("Sextic twist requires a nonzero argument")
|
|
352
|
+
|
|
353
|
+
c4, c6 = self.c_invariants()
|
|
354
|
+
# E is isomorphic to [0,0,0,0,-54*c6]
|
|
355
|
+
assert c4 == 0
|
|
356
|
+
return EllipticCurve(K, [0, 0, 0, 0, -54 * c6 * D])
|
|
357
|
+
|
|
358
|
+
def is_quadratic_twist(self, other):
|
|
359
|
+
r"""
|
|
360
|
+
Determine whether this curve is a quadratic twist of another.
|
|
361
|
+
|
|
362
|
+
INPUT:
|
|
363
|
+
|
|
364
|
+
- ``other`` -- an elliptic curve with the same base field as ``self``
|
|
365
|
+
|
|
366
|
+
OUTPUT:
|
|
367
|
+
|
|
368
|
+
Either 0, if the curves are not quadratic twists, or `D` if
|
|
369
|
+
``other`` is ``self.quadratic_twist(D)`` (up to isomorphism).
|
|
370
|
+
If ``self`` and ``other`` are isomorphic, returns 1.
|
|
371
|
+
|
|
372
|
+
If the curves are defined over `\QQ`, the output `D` is
|
|
373
|
+
a squarefree integer.
|
|
374
|
+
|
|
375
|
+
.. NOTE::
|
|
376
|
+
|
|
377
|
+
Not fully implemented in characteristic 2, or in
|
|
378
|
+
characteristic 3 when both `j`-invariants are 0.
|
|
379
|
+
|
|
380
|
+
EXAMPLES::
|
|
381
|
+
|
|
382
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
383
|
+
sage: E = EllipticCurve('11a1')
|
|
384
|
+
sage: Et = E.quadratic_twist(-24)
|
|
385
|
+
sage: E.is_quadratic_twist(Et)
|
|
386
|
+
-6
|
|
387
|
+
|
|
388
|
+
sage: E1 = EllipticCurve([0,0,1,0,0])
|
|
389
|
+
sage: E1.j_invariant()
|
|
390
|
+
0
|
|
391
|
+
sage: E2 = EllipticCurve([0,0,0,0,2])
|
|
392
|
+
sage: E1.is_quadratic_twist(E2)
|
|
393
|
+
2
|
|
394
|
+
sage: E1.is_quadratic_twist(E1)
|
|
395
|
+
1
|
|
396
|
+
sage: type(E1.is_quadratic_twist(E1)) == type(E1.is_quadratic_twist(E2)) # Issue #6574
|
|
397
|
+
True
|
|
398
|
+
|
|
399
|
+
::
|
|
400
|
+
|
|
401
|
+
sage: E1 = EllipticCurve([0,0,0,1,0])
|
|
402
|
+
sage: E1.j_invariant()
|
|
403
|
+
1728
|
|
404
|
+
sage: E2 = EllipticCurve([0,0,0,2,0])
|
|
405
|
+
sage: E1.is_quadratic_twist(E2)
|
|
406
|
+
0
|
|
407
|
+
sage: E2 = EllipticCurve([0,0,0,25,0])
|
|
408
|
+
sage: E1.is_quadratic_twist(E2)
|
|
409
|
+
5
|
|
410
|
+
|
|
411
|
+
::
|
|
412
|
+
|
|
413
|
+
sage: # needs sage.rings.finite_rings
|
|
414
|
+
sage: F = GF(101)
|
|
415
|
+
sage: E1 = EllipticCurve(F, [4,7])
|
|
416
|
+
sage: E2 = E1.quadratic_twist()
|
|
417
|
+
sage: D = E1.is_quadratic_twist(E2); D != 0
|
|
418
|
+
True
|
|
419
|
+
sage: F = GF(101)
|
|
420
|
+
sage: E1 = EllipticCurve(F, [4,7])
|
|
421
|
+
sage: E2 = E1.quadratic_twist()
|
|
422
|
+
sage: D = E1.is_quadratic_twist(E2)
|
|
423
|
+
sage: E1.quadratic_twist(D).is_isomorphic(E2)
|
|
424
|
+
True
|
|
425
|
+
sage: E1.is_isomorphic(E2)
|
|
426
|
+
False
|
|
427
|
+
sage: F2 = GF(101^2,'a')
|
|
428
|
+
sage: E1.change_ring(F2).is_isomorphic(E2.change_ring(F2))
|
|
429
|
+
True
|
|
430
|
+
|
|
431
|
+
A characteristic 3 example::
|
|
432
|
+
|
|
433
|
+
sage: # needs sage.rings.finite_rings
|
|
434
|
+
sage: F = GF(3^5,'a')
|
|
435
|
+
sage: E1 = EllipticCurve_from_j(F(1))
|
|
436
|
+
sage: E2 = E1.quadratic_twist(-1)
|
|
437
|
+
sage: D = E1.is_quadratic_twist(E2); D != 0
|
|
438
|
+
True
|
|
439
|
+
sage: E1.quadratic_twist(D).is_isomorphic(E2)
|
|
440
|
+
True
|
|
441
|
+
|
|
442
|
+
::
|
|
443
|
+
|
|
444
|
+
sage: # needs sage.rings.finite_rings
|
|
445
|
+
sage: E1 = EllipticCurve_from_j(F(0))
|
|
446
|
+
sage: E2 = E1.quadratic_twist()
|
|
447
|
+
sage: D = E1.is_quadratic_twist(E2); D
|
|
448
|
+
1
|
|
449
|
+
sage: E1.is_isomorphic(E2)
|
|
450
|
+
True
|
|
451
|
+
"""
|
|
452
|
+
from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic
|
|
453
|
+
E = self
|
|
454
|
+
F = other
|
|
455
|
+
if not isinstance(E, EllipticCurve_generic) or not isinstance(F, EllipticCurve_generic):
|
|
456
|
+
raise ValueError("arguments are not elliptic curves")
|
|
457
|
+
K = E.base_ring()
|
|
458
|
+
zero = K.zero()
|
|
459
|
+
if not K == F.base_ring():
|
|
460
|
+
return zero
|
|
461
|
+
j = E.j_invariant()
|
|
462
|
+
if j != F.j_invariant():
|
|
463
|
+
return zero
|
|
464
|
+
|
|
465
|
+
if E.is_isomorphic(F):
|
|
466
|
+
if K is QQ:
|
|
467
|
+
return ZZ(1)
|
|
468
|
+
return K.one()
|
|
469
|
+
|
|
470
|
+
char = K.characteristic()
|
|
471
|
+
|
|
472
|
+
if char == 2:
|
|
473
|
+
raise NotImplementedError("not implemented in characteristic 2")
|
|
474
|
+
elif char == 3:
|
|
475
|
+
if j == 0:
|
|
476
|
+
raise NotImplementedError("not implemented in characteristic 3 for curves of j-invariant 0")
|
|
477
|
+
D = E.b2() / F.b2()
|
|
478
|
+
|
|
479
|
+
else:
|
|
480
|
+
# now char!=2,3:
|
|
481
|
+
c4E, c6E = E.c_invariants()
|
|
482
|
+
c4F, c6F = F.c_invariants()
|
|
483
|
+
|
|
484
|
+
if j == 0:
|
|
485
|
+
um = c6E/c6F
|
|
486
|
+
x = polygen(K)
|
|
487
|
+
ulist = (x**3-um).roots(multiplicities=False)
|
|
488
|
+
if not ulist:
|
|
489
|
+
D = zero
|
|
490
|
+
else:
|
|
491
|
+
D = ulist[0]
|
|
492
|
+
elif j == 1728:
|
|
493
|
+
um = c4E/c4F
|
|
494
|
+
x = polygen(K)
|
|
495
|
+
ulist = (x**2-um).roots(multiplicities=False)
|
|
496
|
+
if not ulist:
|
|
497
|
+
D = zero
|
|
498
|
+
else:
|
|
499
|
+
D = ulist[0]
|
|
500
|
+
else:
|
|
501
|
+
D = (c6E*c4F)/(c6F*c4E)
|
|
502
|
+
|
|
503
|
+
# Normalization of output:
|
|
504
|
+
|
|
505
|
+
if D.is_zero():
|
|
506
|
+
return D
|
|
507
|
+
|
|
508
|
+
if K is QQ:
|
|
509
|
+
D = D.squarefree_part()
|
|
510
|
+
|
|
511
|
+
assert E.quadratic_twist(D).is_isomorphic(F)
|
|
512
|
+
|
|
513
|
+
return D
|
|
514
|
+
|
|
515
|
+
def is_quartic_twist(self, other):
|
|
516
|
+
r"""
|
|
517
|
+
Determine whether this curve is a quartic twist of another.
|
|
518
|
+
|
|
519
|
+
INPUT:
|
|
520
|
+
|
|
521
|
+
- ``other`` -- an elliptic curves with the same base field as ``self``
|
|
522
|
+
|
|
523
|
+
OUTPUT:
|
|
524
|
+
|
|
525
|
+
Either 0, if the curves are not quartic twists, or `D` if
|
|
526
|
+
``other`` is ``self.quartic_twist(D)`` (up to isomorphism).
|
|
527
|
+
If ``self`` and ``other`` are isomorphic, returns 1.
|
|
528
|
+
|
|
529
|
+
.. NOTE::
|
|
530
|
+
|
|
531
|
+
Not fully implemented in characteristics 2 or 3.
|
|
532
|
+
|
|
533
|
+
EXAMPLES::
|
|
534
|
+
|
|
535
|
+
sage: E = EllipticCurve_from_j(GF(13)(1728))
|
|
536
|
+
sage: E1 = E.quartic_twist(2)
|
|
537
|
+
sage: D = E.is_quartic_twist(E1); D!=0
|
|
538
|
+
True
|
|
539
|
+
sage: E.quartic_twist(D).is_isomorphic(E1)
|
|
540
|
+
True
|
|
541
|
+
|
|
542
|
+
::
|
|
543
|
+
|
|
544
|
+
sage: E = EllipticCurve_from_j(1728)
|
|
545
|
+
sage: E1 = E.quartic_twist(12345)
|
|
546
|
+
sage: D = E.is_quartic_twist(E1); D
|
|
547
|
+
15999120
|
|
548
|
+
sage: (D/12345).is_perfect_power(4)
|
|
549
|
+
True
|
|
550
|
+
"""
|
|
551
|
+
from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic
|
|
552
|
+
E = self
|
|
553
|
+
F = other
|
|
554
|
+
if not isinstance(E, EllipticCurve_generic) or not isinstance(F, EllipticCurve_generic):
|
|
555
|
+
raise ValueError("arguments are not elliptic curves")
|
|
556
|
+
K = E.base_ring()
|
|
557
|
+
zero = K.zero()
|
|
558
|
+
if not K == F.base_ring():
|
|
559
|
+
return zero
|
|
560
|
+
j = E.j_invariant()
|
|
561
|
+
if j != F.j_invariant() or j != K(1728):
|
|
562
|
+
return zero
|
|
563
|
+
|
|
564
|
+
if E.is_isomorphic(F):
|
|
565
|
+
return K.one()
|
|
566
|
+
|
|
567
|
+
char = K.characteristic()
|
|
568
|
+
|
|
569
|
+
if char == 2:
|
|
570
|
+
raise NotImplementedError("not implemented in characteristic 2")
|
|
571
|
+
elif char == 3:
|
|
572
|
+
raise NotImplementedError("not implemented in characteristic 3")
|
|
573
|
+
else:
|
|
574
|
+
# now char!=2,3:
|
|
575
|
+
D = F.c4() / E.c4()
|
|
576
|
+
|
|
577
|
+
if D.is_zero():
|
|
578
|
+
return D
|
|
579
|
+
|
|
580
|
+
assert E.quartic_twist(D).is_isomorphic(F)
|
|
581
|
+
|
|
582
|
+
return D
|
|
583
|
+
|
|
584
|
+
def is_sextic_twist(self, other):
|
|
585
|
+
r"""
|
|
586
|
+
Determine whether this curve is a sextic twist of another.
|
|
587
|
+
|
|
588
|
+
INPUT:
|
|
589
|
+
|
|
590
|
+
- ``other`` -- an elliptic curves with the same base field as ``self``
|
|
591
|
+
|
|
592
|
+
OUTPUT:
|
|
593
|
+
|
|
594
|
+
Either 0, if the curves are not sextic twists, or `D` if
|
|
595
|
+
``other`` is ``self.sextic_twist(D)`` (up to isomorphism).
|
|
596
|
+
If ``self`` and ``other`` are isomorphic, returns 1.
|
|
597
|
+
|
|
598
|
+
.. NOTE::
|
|
599
|
+
|
|
600
|
+
Not fully implemented in characteristics 2 or 3.
|
|
601
|
+
|
|
602
|
+
EXAMPLES::
|
|
603
|
+
|
|
604
|
+
sage: E = EllipticCurve_from_j(GF(13)(0))
|
|
605
|
+
sage: E1 = E.sextic_twist(2)
|
|
606
|
+
sage: D = E.is_sextic_twist(E1); D != 0
|
|
607
|
+
True
|
|
608
|
+
sage: E.sextic_twist(D).is_isomorphic(E1)
|
|
609
|
+
True
|
|
610
|
+
|
|
611
|
+
::
|
|
612
|
+
|
|
613
|
+
sage: E = EllipticCurve_from_j(0)
|
|
614
|
+
sage: E1 = E.sextic_twist(12345)
|
|
615
|
+
sage: D = E.is_sextic_twist(E1); D
|
|
616
|
+
575968320
|
|
617
|
+
sage: (D/12345).is_perfect_power(6)
|
|
618
|
+
True
|
|
619
|
+
"""
|
|
620
|
+
from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic
|
|
621
|
+
E = self
|
|
622
|
+
F = other
|
|
623
|
+
if not isinstance(E, EllipticCurve_generic) or not isinstance(F, EllipticCurve_generic):
|
|
624
|
+
raise ValueError("arguments are not elliptic curves")
|
|
625
|
+
K = E.base_ring()
|
|
626
|
+
zero = K.zero()
|
|
627
|
+
if not K == F.base_ring():
|
|
628
|
+
return zero
|
|
629
|
+
j = E.j_invariant()
|
|
630
|
+
if j != F.j_invariant() or not j.is_zero():
|
|
631
|
+
return zero
|
|
632
|
+
|
|
633
|
+
if E.is_isomorphic(F):
|
|
634
|
+
return K.one()
|
|
635
|
+
|
|
636
|
+
char = K.characteristic()
|
|
637
|
+
|
|
638
|
+
if char == 2:
|
|
639
|
+
raise NotImplementedError("not implemented in characteristic 2")
|
|
640
|
+
elif char == 3:
|
|
641
|
+
raise NotImplementedError("not implemented in characteristic 3")
|
|
642
|
+
else:
|
|
643
|
+
# now char!=2,3:
|
|
644
|
+
D = F.c6() / E.c6()
|
|
645
|
+
|
|
646
|
+
if D.is_zero():
|
|
647
|
+
return D
|
|
648
|
+
|
|
649
|
+
assert E.sextic_twist(D).is_isomorphic(F)
|
|
650
|
+
|
|
651
|
+
return D
|
|
652
|
+
|
|
653
|
+
def descend_to(self, K, f=None) -> list:
|
|
654
|
+
r"""
|
|
655
|
+
Given an elliptic curve ``self`` defined over a field `L` and a
|
|
656
|
+
subfield `K` of `L`, return all elliptic curves over `K` which
|
|
657
|
+
are isomorphic over `L` to ``self``.
|
|
658
|
+
|
|
659
|
+
INPUT:
|
|
660
|
+
|
|
661
|
+
- ``K`` -- a field which embeds into the base field `L` of ``self``
|
|
662
|
+
|
|
663
|
+
- ``f`` -- (optional) an embedding of `K` into `L`; ignored if
|
|
664
|
+
`K` is `\QQ`
|
|
665
|
+
|
|
666
|
+
OUTPUT:
|
|
667
|
+
|
|
668
|
+
A list (possibly empty) of elliptic curves defined over `K`
|
|
669
|
+
which are isomorphic to ``self`` over `L`, up to isomorphism over `K`.
|
|
670
|
+
|
|
671
|
+
.. NOTE::
|
|
672
|
+
|
|
673
|
+
Currently only implemented over number fields. To extend
|
|
674
|
+
to other fields of characteristic not 2 or 3, what is
|
|
675
|
+
needed is a method giving the preimages in `K^*/(K^*)^m` of
|
|
676
|
+
an element of the base field, for `m=2,4,6`.
|
|
677
|
+
|
|
678
|
+
EXAMPLES::
|
|
679
|
+
|
|
680
|
+
sage: E = EllipticCurve([1,2,3,4,5])
|
|
681
|
+
sage: E.descend_to(ZZ)
|
|
682
|
+
Traceback (most recent call last):
|
|
683
|
+
...
|
|
684
|
+
TypeError: Input must be a field.
|
|
685
|
+
|
|
686
|
+
::
|
|
687
|
+
|
|
688
|
+
sage: # needs sage.rings.number_field
|
|
689
|
+
sage: F.<b> = QuadraticField(23)
|
|
690
|
+
sage: x = polygen(ZZ, 'x')
|
|
691
|
+
sage: G.<a> = F.extension(x^3 + 5)
|
|
692
|
+
sage: E = EllipticCurve(j=1728*b).change_ring(G)
|
|
693
|
+
sage: EF = E.descend_to(F); EF
|
|
694
|
+
[Elliptic Curve defined by y^2 = x^3 + (27*b-621)*x + (-1296*b+2484)
|
|
695
|
+
over Number Field in b with defining polynomial x^2 - 23
|
|
696
|
+
with b = 4.795831523312720?]
|
|
697
|
+
sage: all(Ei.change_ring(G).is_isomorphic(E) for Ei in EF)
|
|
698
|
+
True
|
|
699
|
+
|
|
700
|
+
::
|
|
701
|
+
|
|
702
|
+
sage: # needs sage.rings.number_field
|
|
703
|
+
sage: L.<a> = NumberField(x^4 - 7)
|
|
704
|
+
sage: K.<b> = NumberField(x^2 - 7, embedding=a^2)
|
|
705
|
+
sage: E = EllipticCurve([a^6, 0])
|
|
706
|
+
sage: EK = E.descend_to(K); EK
|
|
707
|
+
[Elliptic Curve defined by y^2 = x^3 + b*x over Number Field in b
|
|
708
|
+
with defining polynomial x^2 - 7 with b = a^2,
|
|
709
|
+
Elliptic Curve defined by y^2 = x^3 + 7*b*x over Number Field in b
|
|
710
|
+
with defining polynomial x^2 - 7 with b = a^2]
|
|
711
|
+
sage: all(Ei.change_ring(L).is_isomorphic(E) for Ei in EK)
|
|
712
|
+
True
|
|
713
|
+
|
|
714
|
+
::
|
|
715
|
+
|
|
716
|
+
sage: K.<a> = QuadraticField(17) # needs sage.rings.number_field
|
|
717
|
+
sage: E = EllipticCurve(j=2*a) # needs sage.rings.number_field
|
|
718
|
+
sage: E.descend_to(QQ) # needs sage.rings.number_field
|
|
719
|
+
[]
|
|
720
|
+
|
|
721
|
+
TESTS:
|
|
722
|
+
|
|
723
|
+
Check that :issue:`16456` is fixed::
|
|
724
|
+
|
|
725
|
+
sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
|
|
726
|
+
sage: K.<a> = NumberField(x^3 - 2)
|
|
727
|
+
sage: E = EllipticCurve('11a1').quadratic_twist(2)
|
|
728
|
+
sage: EK = E.change_ring(K)
|
|
729
|
+
sage: EK2 = EK.change_weierstrass_model((a,a,a,a+1))
|
|
730
|
+
sage: EK2.descend_to(QQ)
|
|
731
|
+
[Elliptic Curve defined by y^2 = x^3 + x^2 - 41*x - 199 over Rational Field]
|
|
732
|
+
|
|
733
|
+
sage: k.<i> = QuadraticField(-1) # needs sage.rings.number_field
|
|
734
|
+
sage: E = EllipticCurve(k,[0,0,0,1,0]) # needs sage.rings.number_field
|
|
735
|
+
sage: E.descend_to(QQ) # needs sage.rings.number_field
|
|
736
|
+
[Elliptic Curve defined by y^2 = x^3 + x over Rational Field,
|
|
737
|
+
Elliptic Curve defined by y^2 = x^3 - 4*x over Rational Field]
|
|
738
|
+
"""
|
|
739
|
+
if not K.is_field():
|
|
740
|
+
raise TypeError("Input must be a field.")
|
|
741
|
+
L = self.base_field()
|
|
742
|
+
if L is K:
|
|
743
|
+
return self
|
|
744
|
+
elif L == K: # number fields can be equal but not identical
|
|
745
|
+
return self.base_extend(K)
|
|
746
|
+
|
|
747
|
+
# Construct an embedding f of K in L, and check that the
|
|
748
|
+
# j-invariant is in the image, otherwise return an empty list:
|
|
749
|
+
|
|
750
|
+
j = self.j_invariant()
|
|
751
|
+
if K == QQ:
|
|
752
|
+
try:
|
|
753
|
+
jK = QQ(j)
|
|
754
|
+
except (ValueError, TypeError):
|
|
755
|
+
return []
|
|
756
|
+
elif f is None:
|
|
757
|
+
embeddings = K.embeddings(L)
|
|
758
|
+
if not embeddings:
|
|
759
|
+
raise TypeError("Input must be a subfield of the base field of the curve.")
|
|
760
|
+
for g in embeddings:
|
|
761
|
+
try:
|
|
762
|
+
jK = g.preimage(j)
|
|
763
|
+
f = g
|
|
764
|
+
break
|
|
765
|
+
except Exception:
|
|
766
|
+
pass
|
|
767
|
+
if f is None:
|
|
768
|
+
return []
|
|
769
|
+
else:
|
|
770
|
+
try:
|
|
771
|
+
if f.domain() != K:
|
|
772
|
+
raise ValueError("embedding has wrong domain")
|
|
773
|
+
if f.codomain() != L:
|
|
774
|
+
raise ValueError("embedding has wrong codomain")
|
|
775
|
+
except AttributeError:
|
|
776
|
+
raise ValueError("invalid embedding: {}".format(f))
|
|
777
|
+
try:
|
|
778
|
+
jK = f.preimage(j)
|
|
779
|
+
except Exception:
|
|
780
|
+
return []
|
|
781
|
+
|
|
782
|
+
# Now we have the j-invariant in K and must find all twists
|
|
783
|
+
# which work, separating the cases of j=0 and j=1728.
|
|
784
|
+
|
|
785
|
+
if L.characteristic():
|
|
786
|
+
raise NotImplementedError("Not implemented in positive characteristic")
|
|
787
|
+
|
|
788
|
+
if jK == 0:
|
|
789
|
+
t = -54 * self.c6()
|
|
790
|
+
try:
|
|
791
|
+
dlist = t.descend_mod_power(K, 6)
|
|
792
|
+
# list of d in K such that t/d is in L*^6
|
|
793
|
+
except AttributeError:
|
|
794
|
+
raise NotImplementedError("Not implemented over %s" % L)
|
|
795
|
+
Elist = [EllipticCurve([0, 0, 0, 0, d]) for d in dlist]
|
|
796
|
+
elif jK == 1728:
|
|
797
|
+
t = -27 * self.c4()
|
|
798
|
+
try:
|
|
799
|
+
dlist = t.descend_mod_power(K, 4)
|
|
800
|
+
# list of d in K such that t/d is in L*^4
|
|
801
|
+
except AttributeError:
|
|
802
|
+
raise NotImplementedError("Not implemented over %s" % L)
|
|
803
|
+
Elist = [EllipticCurve([0, 0, 0, d, 0]) for d in dlist]
|
|
804
|
+
else:
|
|
805
|
+
c4, c6 = self.c_invariants()
|
|
806
|
+
t = c6 / c4
|
|
807
|
+
try:
|
|
808
|
+
dlist = t.descend_mod_power(K, 2)
|
|
809
|
+
# list of d in K such that t/d is in L*^2
|
|
810
|
+
except AttributeError:
|
|
811
|
+
raise NotImplementedError("Not implemented over %s" % L)
|
|
812
|
+
c = -27*jK/(jK-1728) # =-27c4^3/c6^2
|
|
813
|
+
a4list = [c*d**2 for d in dlist]
|
|
814
|
+
a6list = [2*a4*d for a4, d in zip(a4list, dlist)]
|
|
815
|
+
Elist = [EllipticCurve([0, 0, 0, a4, a6]) for a4, a6 in zip(a4list, a6list)]
|
|
816
|
+
|
|
817
|
+
if K is QQ:
|
|
818
|
+
Elist = [E.minimal_model() for E in Elist]
|
|
819
|
+
return Elist
|
|
820
|
+
|
|
821
|
+
def division_field(self, n, names='t', map=False, **kwds):
|
|
822
|
+
r"""
|
|
823
|
+
Given an elliptic curve over a number field or finite field `F` and
|
|
824
|
+
a positive integer `n`, construct the `n`-division field `F(E[n])`.
|
|
825
|
+
|
|
826
|
+
The `n`-division field is the smallest extension of `F` over which
|
|
827
|
+
all `n`-torsion points of `E` are defined.
|
|
828
|
+
|
|
829
|
+
INPUT:
|
|
830
|
+
|
|
831
|
+
- ``n`` -- positive integer
|
|
832
|
+
- ``names`` -- (default: ``'t'``) a variable name for the division field
|
|
833
|
+
- ``map`` -- boolean (default: ``False``); also return an embedding of the
|
|
834
|
+
:meth:`base_field` into the resulting field
|
|
835
|
+
- ``kwds`` -- additional keyword arguments passed to
|
|
836
|
+
:func:`~sage.rings.polynomial.polynomial_element.Polynomial.splitting_field`
|
|
837
|
+
|
|
838
|
+
OUTPUT:
|
|
839
|
+
|
|
840
|
+
If ``map`` is ``False``, the division field `K` as an absolute
|
|
841
|
+
number field or a finite field.
|
|
842
|
+
If ``map`` is ``True``, a tuple `(K, \phi)` where `\phi` is an
|
|
843
|
+
embedding of the base field in the division field `K`.
|
|
844
|
+
|
|
845
|
+
.. WARNING::
|
|
846
|
+
|
|
847
|
+
This can take a very long time when the degree of the division
|
|
848
|
+
field is large (e.g. when `n` is large or when the Galois
|
|
849
|
+
representation is surjective). The ``simplify`` flag also
|
|
850
|
+
has a big influence on the running time over number fields:
|
|
851
|
+
sometimes ``simplify=False`` is faster, sometimes the default
|
|
852
|
+
``simplify=True`` is faster.
|
|
853
|
+
|
|
854
|
+
EXAMPLES:
|
|
855
|
+
|
|
856
|
+
The 2-division field is the same as the splitting field of
|
|
857
|
+
the 2-division polynomial (therefore, it has degree 1, 2, 3 or 6)::
|
|
858
|
+
|
|
859
|
+
sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
|
|
860
|
+
sage: E = EllipticCurve('15a1')
|
|
861
|
+
sage: K.<b> = E.division_field(2); K
|
|
862
|
+
Number Field in b with defining polynomial x
|
|
863
|
+
sage: E = EllipticCurve('14a1')
|
|
864
|
+
sage: K.<b> = E.division_field(2); K
|
|
865
|
+
Number Field in b with defining polynomial x^2 + 5*x + 92
|
|
866
|
+
sage: E = EllipticCurve('196b1')
|
|
867
|
+
sage: K.<b> = E.division_field(2); K
|
|
868
|
+
Number Field in b with defining polynomial x^3 + x^2 - 114*x - 127
|
|
869
|
+
sage: E = EllipticCurve('19a1')
|
|
870
|
+
sage: K.<b> = E.division_field(2); K
|
|
871
|
+
Number Field in b with defining polynomial
|
|
872
|
+
x^6 + 10*x^5 + 24*x^4 - 212*x^3 + 1364*x^2 + 24072*x + 104292
|
|
873
|
+
|
|
874
|
+
For odd primes `n`, the division field is either the splitting
|
|
875
|
+
field of the `n`-division polynomial, or a quadratic extension
|
|
876
|
+
of it. ::
|
|
877
|
+
|
|
878
|
+
sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
|
|
879
|
+
sage: E = EllipticCurve('50a1')
|
|
880
|
+
sage: F.<a> = E.division_polynomial(3).splitting_field(simplify_all=True); F
|
|
881
|
+
Number Field in a
|
|
882
|
+
with defining polynomial x^6 - 3*x^5 + 4*x^4 - 3*x^3 - 2*x^2 + 3*x + 3
|
|
883
|
+
sage: K.<b> = E.division_field(3, simplify_all=True); K
|
|
884
|
+
Number Field in b
|
|
885
|
+
with defining polynomial x^6 - 3*x^5 + 4*x^4 - 3*x^3 - 2*x^2 + 3*x + 3
|
|
886
|
+
|
|
887
|
+
If we take any quadratic twist, the splitting field of the
|
|
888
|
+
3-division polynomial remains the same, but the 3-division field
|
|
889
|
+
becomes a quadratic extension::
|
|
890
|
+
|
|
891
|
+
sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
|
|
892
|
+
sage: E = E.quadratic_twist(5) # 50b3
|
|
893
|
+
sage: F.<a> = E.division_polynomial(3).splitting_field(simplify_all=True); F
|
|
894
|
+
Number Field in a
|
|
895
|
+
with defining polynomial x^6 - 3*x^5 + 4*x^4 - 3*x^3 - 2*x^2 + 3*x + 3
|
|
896
|
+
sage: K.<b> = E.division_field(3, simplify_all=True); K
|
|
897
|
+
Number Field in b with defining polynomial x^12 - 3*x^11 + 8*x^10 - 15*x^9
|
|
898
|
+
+ 30*x^8 - 63*x^7 + 109*x^6 - 144*x^5 + 150*x^4 - 120*x^3 + 68*x^2 - 24*x + 4
|
|
899
|
+
|
|
900
|
+
Try another quadratic twist, this time over a subfield of `F`::
|
|
901
|
+
|
|
902
|
+
sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
|
|
903
|
+
sage: G.<c>,_,_ = F.subfields(3)[0]
|
|
904
|
+
sage: E = E.base_extend(G).quadratic_twist(c); E
|
|
905
|
+
Elliptic Curve defined
|
|
906
|
+
by y^2 = x^3 + 5*a0*x^2 + (-200*a0^2)*x + (-42000*a0^2+42000*a0+126000)
|
|
907
|
+
over Number Field in a0 with defining polynomial x^3 - 3*x^2 + 3*x + 9
|
|
908
|
+
sage: K.<b> = E.division_field(3, simplify_all=True); K
|
|
909
|
+
Number Field in b with defining polynomial x^12 + 5*x^10 + 40*x^8 + 315*x^6 + 750*x^4 + 675*x^2 + 2025
|
|
910
|
+
|
|
911
|
+
Some higher-degree examples::
|
|
912
|
+
|
|
913
|
+
sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
|
|
914
|
+
sage: E = EllipticCurve('11a1')
|
|
915
|
+
sage: K.<b> = E.division_field(2); K
|
|
916
|
+
Number Field in b with defining polynomial
|
|
917
|
+
x^6 + 2*x^5 - 48*x^4 - 436*x^3 + 1668*x^2 + 28792*x + 73844
|
|
918
|
+
sage: K.<b> = E.division_field(3); K # long time
|
|
919
|
+
Number Field in b with defining polynomial x^48 ...
|
|
920
|
+
sage: K.<b> = E.division_field(5); K
|
|
921
|
+
Number Field in b with defining polynomial x^4 - x^3 + x^2 - x + 1
|
|
922
|
+
sage: E.division_field(5, 'b', simplify=False)
|
|
923
|
+
Number Field in b with defining polynomial x^4 + x^3 + 11*x^2 + 41*x + 101
|
|
924
|
+
sage: E.base_extend(K).torsion_subgroup() # long time
|
|
925
|
+
Torsion Subgroup isomorphic to Z/5 + Z/5 associated to the Elliptic Curve
|
|
926
|
+
defined by y^2 + y = x^3 + (-1)*x^2 + (-10)*x + (-20)
|
|
927
|
+
over Number Field in b with defining polynomial x^4 - x^3 + x^2 - x + 1
|
|
928
|
+
|
|
929
|
+
sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
|
|
930
|
+
sage: E = EllipticCurve('27a1')
|
|
931
|
+
sage: K.<b> = E.division_field(3); K
|
|
932
|
+
Number Field in b with defining polynomial x^2 + 3*x + 9
|
|
933
|
+
sage: K.<b> = E.division_field(2); K
|
|
934
|
+
Number Field in b with defining polynomial
|
|
935
|
+
x^6 + 6*x^5 + 24*x^4 - 52*x^3 - 228*x^2 + 744*x + 3844
|
|
936
|
+
sage: K.<b> = E.division_field(2, simplify_all=True); K
|
|
937
|
+
Number Field in b with defining polynomial x^6 - 3*x^5 + 5*x^3 - 3*x + 1
|
|
938
|
+
sage: K.<b> = E.division_field(5); K # long time
|
|
939
|
+
Number Field in b with defining polynomial x^48 ...
|
|
940
|
+
sage: K.<b> = E.division_field(7); K # long time
|
|
941
|
+
Number Field in b with defining polynomial x^72 ...
|
|
942
|
+
|
|
943
|
+
Over a number field::
|
|
944
|
+
|
|
945
|
+
sage: # needs sage.rings.number_field
|
|
946
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
947
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
948
|
+
sage: E = EllipticCurve([0,0,0,0,i])
|
|
949
|
+
sage: L.<b> = E.division_field(2); L
|
|
950
|
+
Number Field in b with defining polynomial x^4 - x^2 + 1
|
|
951
|
+
sage: L.<b>, phi = E.division_field(2, map=True); phi
|
|
952
|
+
Ring morphism:
|
|
953
|
+
From: Number Field in i with defining polynomial x^2 + 1
|
|
954
|
+
To: Number Field in b with defining polynomial x^4 - x^2 + 1
|
|
955
|
+
Defn: i |--> -b^3
|
|
956
|
+
sage: L.<b>, phi = E.division_field(3, map=True)
|
|
957
|
+
sage: L
|
|
958
|
+
Number Field in b with defining polynomial x^24 - 6*x^22 - 12*x^21
|
|
959
|
+
- 21*x^20 + 216*x^19 + 48*x^18 + 804*x^17 + 1194*x^16 - 13488*x^15
|
|
960
|
+
+ 21222*x^14 + 44196*x^13 - 47977*x^12 - 102888*x^11 + 173424*x^10
|
|
961
|
+
- 172308*x^9 + 302046*x^8 + 252864*x^7 - 931182*x^6 + 180300*x^5
|
|
962
|
+
+ 879567*x^4 - 415896*x^3 + 1941012*x^2 + 650220*x + 443089
|
|
963
|
+
sage: phi
|
|
964
|
+
Ring morphism:
|
|
965
|
+
From: Number Field in i with defining polynomial x^2 + 1
|
|
966
|
+
To: Number Field in b with defining polynomial x^24 ...
|
|
967
|
+
Defn: i |--> -215621657062634529/183360797284413355040732*b^23 ...
|
|
968
|
+
|
|
969
|
+
Over a finite field::
|
|
970
|
+
|
|
971
|
+
sage: E = EllipticCurve(GF(431^2), [1,0]) # needs sage.rings.finite_rings
|
|
972
|
+
sage: E.division_field(5, map=True) # needs sage.rings.finite_rings
|
|
973
|
+
(Finite Field in t of size 431^4,
|
|
974
|
+
Ring morphism:
|
|
975
|
+
From: Finite Field in z2 of size 431^2
|
|
976
|
+
To: Finite Field in t of size 431^4
|
|
977
|
+
Defn: z2 |--> 52*t^3 + 222*t^2 + 78*t + 105)
|
|
978
|
+
|
|
979
|
+
::
|
|
980
|
+
|
|
981
|
+
sage: E = EllipticCurve(GF(433^2), [1,0]) # needs sage.rings.finite_rings
|
|
982
|
+
sage: K.<v> = E.division_field(7); K # needs sage.rings.finite_rings
|
|
983
|
+
Finite Field in v of size 433^16
|
|
984
|
+
|
|
985
|
+
It also works for composite orders::
|
|
986
|
+
|
|
987
|
+
sage: E = EllipticCurve(GF(11), [5,5])
|
|
988
|
+
sage: E.change_ring(E.division_field(8)).abelian_group().torsion_subgroup(8).invariants()
|
|
989
|
+
(8, 8)
|
|
990
|
+
sage: E.change_ring(E.division_field(9)).abelian_group().torsion_subgroup(9).invariants()
|
|
991
|
+
(9, 9)
|
|
992
|
+
sage: E.change_ring(E.division_field(10)).abelian_group().torsion_subgroup(10).invariants()
|
|
993
|
+
(10, 10)
|
|
994
|
+
sage: E.change_ring(E.division_field(36)).abelian_group().torsion_subgroup(36).invariants()
|
|
995
|
+
(36, 36)
|
|
996
|
+
sage: E.change_ring(E.division_field(11)).abelian_group().torsion_subgroup(11).invariants()
|
|
997
|
+
(11,)
|
|
998
|
+
sage: E.change_ring(E.division_field(66)).abelian_group().torsion_subgroup(66).invariants()
|
|
999
|
+
(6, 66)
|
|
1000
|
+
|
|
1001
|
+
...also over number fields::
|
|
1002
|
+
|
|
1003
|
+
sage: R.<x> = PolynomialRing(QQ)
|
|
1004
|
+
sage: K.<i> = NumberField(x^2 + 1)
|
|
1005
|
+
sage: E = EllipticCurve([0,0,0,0,i])
|
|
1006
|
+
sage: L,emb = E.division_field(6, names='b', map=True); L
|
|
1007
|
+
Number Field in b with defining polynomial x^24 + 12*x^23 + ...
|
|
1008
|
+
sage: E.change_ring(emb).torsion_subgroup().invariants()
|
|
1009
|
+
(6, 6)
|
|
1010
|
+
|
|
1011
|
+
.. SEEALSO::
|
|
1012
|
+
|
|
1013
|
+
To compute a basis of the `n`-torsion once the base field
|
|
1014
|
+
has been extended, you may use
|
|
1015
|
+
:meth:`sage.schemes.elliptic_curves.ell_number_field.EllipticCurve_number_field.torsion_subgroup`
|
|
1016
|
+
or
|
|
1017
|
+
:meth:`sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field.torsion_basis`.
|
|
1018
|
+
|
|
1019
|
+
TESTS:
|
|
1020
|
+
|
|
1021
|
+
Some random for prime orders::
|
|
1022
|
+
|
|
1023
|
+
sage: # needs sage.rings.finite_rings
|
|
1024
|
+
sage: def check(E, l, K):
|
|
1025
|
+
....: EE = E.change_ring(K)
|
|
1026
|
+
....: cof = EE.order().prime_to_m_part(l)
|
|
1027
|
+
....: pts = (cof * EE.random_point() for _ in iter(int, 1))
|
|
1028
|
+
....: mul = lambda P: P if not l*P else mul(l*P)
|
|
1029
|
+
....: pts = map(mul, filter(bool, pts))
|
|
1030
|
+
....: if l == EE.base_field().characteristic():
|
|
1031
|
+
....: if EE.is_supersingular():
|
|
1032
|
+
....: Ps = ()
|
|
1033
|
+
....: else:
|
|
1034
|
+
....: assert l.divides(EE.order())
|
|
1035
|
+
....: Ps = (next(pts),)
|
|
1036
|
+
....: else:
|
|
1037
|
+
....: assert l.divides(EE.order())
|
|
1038
|
+
....: for _ in range(9999):
|
|
1039
|
+
....: P,Q = next(pts), next(pts)
|
|
1040
|
+
....: if P.weil_pairing(Q,l) != 1:
|
|
1041
|
+
....: Ps = (P,Q)
|
|
1042
|
+
....: break
|
|
1043
|
+
....: else:
|
|
1044
|
+
....: assert False
|
|
1045
|
+
....: deg = lcm(el.minpoly().degree() for el in sum(map(list,Ps),[]))
|
|
1046
|
+
....: assert max(deg, E.base_field().degree()) == K.degree()
|
|
1047
|
+
sage: q = next_prime_power(randrange(1, 10^9))
|
|
1048
|
+
sage: F.<a> = GF(q)
|
|
1049
|
+
sage: while True:
|
|
1050
|
+
....: try:
|
|
1051
|
+
....: E = EllipticCurve([F.random_element() for _ in range(5)])
|
|
1052
|
+
....: except ArithmeticError:
|
|
1053
|
+
....: continue
|
|
1054
|
+
....: break
|
|
1055
|
+
sage: l = random_prime(8)
|
|
1056
|
+
sage: K = E.division_field(l)
|
|
1057
|
+
sage: n = E.cardinality(extension_degree=K.degree()//F.degree())
|
|
1058
|
+
sage: (l^2 if q%l else 0 + E.is_ordinary()).divides(n)
|
|
1059
|
+
True
|
|
1060
|
+
sage: check(E, l, K) # long time
|
|
1061
|
+
|
|
1062
|
+
AUTHORS:
|
|
1063
|
+
|
|
1064
|
+
- Jeroen Demeyer (2014-01-06): :issue:`11905`, use
|
|
1065
|
+
``splitting_field`` method, moved from ``gal_reps.py``, make
|
|
1066
|
+
it work over number fields.
|
|
1067
|
+
- Lorenz Panny (2022): extend to finite fields
|
|
1068
|
+
- Lorenz Panny (2023): extend to composite `n`.
|
|
1069
|
+
"""
|
|
1070
|
+
from sage.misc.verbose import verbose
|
|
1071
|
+
|
|
1072
|
+
n = Integer(n)
|
|
1073
|
+
if n <= 0:
|
|
1074
|
+
raise ValueError("n must be a positive integer")
|
|
1075
|
+
|
|
1076
|
+
verbose("Adjoining X-coordinates of %s-torsion points" % n)
|
|
1077
|
+
|
|
1078
|
+
F = self.base_ring()
|
|
1079
|
+
f = self.division_polynomial(n).radical()
|
|
1080
|
+
|
|
1081
|
+
if n == 2 or f.is_constant():
|
|
1082
|
+
# For n = 2, the division field is the splitting field of
|
|
1083
|
+
# the division polynomial.
|
|
1084
|
+
# If f is a nonzero constant, the n-torsion is trivial:
|
|
1085
|
+
# This means the curve must be supersingular and n == p.
|
|
1086
|
+
return f.splitting_field(names, map=map, **kwds)
|
|
1087
|
+
|
|
1088
|
+
# We divide out the part defining points of non-maximal order.
|
|
1089
|
+
# Clearly all points of non-maximal order are multiples of points
|
|
1090
|
+
# of maximal order, so they cannot be defined over a larger field.
|
|
1091
|
+
if not n.is_prime():
|
|
1092
|
+
for d in n.prime_divisors():
|
|
1093
|
+
g = self.division_polynomial(n // d)
|
|
1094
|
+
f //= f.gcd(g)
|
|
1095
|
+
|
|
1096
|
+
# Compute splitting field of X-coordinates.
|
|
1097
|
+
# The Galois group of the division field is a subgroup of GL(2,n).
|
|
1098
|
+
# The Galois group of the X-coordinates is a subgroup of GL(2,n)/{-1,+1}.
|
|
1099
|
+
if F in NumberFields():
|
|
1100
|
+
from sage.misc.misc_c import prod
|
|
1101
|
+
deg_mult = F.degree() * prod(l * (l+1) * (l-1)**2 * l**(4*(e-1))
|
|
1102
|
+
for l, e in n.factor()) // 2
|
|
1103
|
+
K, F_to_K = f.splitting_field(names, degree_multiple=deg_mult, map=True, **kwds)
|
|
1104
|
+
elif F in FiniteFields():
|
|
1105
|
+
K, F_to_K = f.splitting_field('u', map=True, **kwds)
|
|
1106
|
+
else:
|
|
1107
|
+
raise NotImplementedError('only number fields and finite fields are currently supported')
|
|
1108
|
+
|
|
1109
|
+
verbose("Adjoining Y-coordinates of %s-torsion points" % n)
|
|
1110
|
+
|
|
1111
|
+
# THEOREM
|
|
1112
|
+
# (Cremona, https://github.com/sagemath/sage/issues/11905#comment:21)
|
|
1113
|
+
# (Later generalized to composite n by Lorenz Panny)
|
|
1114
|
+
#
|
|
1115
|
+
# Let K be a field, E an elliptic curve over K and n a positive
|
|
1116
|
+
# integer. Assume that K contains all roots of the n-division
|
|
1117
|
+
# polynomial of E, and that at least one point P of full order n
|
|
1118
|
+
# is defined over K. Then K contains all n-torsion points on E.
|
|
1119
|
+
#
|
|
1120
|
+
# PROOF. Let G be the absolute Galois group of K (every element
|
|
1121
|
+
# in it fixes all elements of K). For any n-torsion point Q
|
|
1122
|
+
# over the algebraic closure and any sigma in G, we must have
|
|
1123
|
+
# either sigma(Q) = Q or sigma(Q) = -Q (since K contains the
|
|
1124
|
+
# X-coordinate of Q). Similarly, sigma(P+Q) must equal either
|
|
1125
|
+
# P+Q or -(P+Q). However, since sigma is a group homomorphism,
|
|
1126
|
+
# we have sigma(P+Q) = sigma(P) + sigma(Q) = P + sigma(Q),
|
|
1127
|
+
# so either P + sigma(Q) = P+Q, which implies sigma(Q) = Q,
|
|
1128
|
+
# or P + sigma(Q) = -(P+Q), which implies sigma(Q) = -2P-Q.
|
|
1129
|
+
# The latter is impossible except for the easier case n = 2.
|
|
1130
|
+
# Hence, sigma(Q) = Q in all cases.
|
|
1131
|
+
#
|
|
1132
|
+
# This implies that it suffices to adjoin the Y-coordinate
|
|
1133
|
+
# of just one full-order point.
|
|
1134
|
+
|
|
1135
|
+
x = f.change_ring(F_to_K).any_root(assume_squarefree=True)
|
|
1136
|
+
h = self.defining_polynomial().change_ring(F_to_K)(x, polygen(K), 1)
|
|
1137
|
+
L = h.splitting_field(names, map=map, **kwds)
|
|
1138
|
+
|
|
1139
|
+
if map:
|
|
1140
|
+
L, K_to_L = L
|
|
1141
|
+
L = L, F_to_K.post_compose(K_to_L)
|
|
1142
|
+
return L
|
|
1143
|
+
|
|
1144
|
+
def _Hom_(self, other, category=None):
|
|
1145
|
+
r"""
|
|
1146
|
+
Hook to make :class:`~sage.categories.homset.Hom`
|
|
1147
|
+
set the correct parent
|
|
1148
|
+
:class:`~sage.schemes.elliptic_curves.homset.EllipticCurveHomset`
|
|
1149
|
+
for
|
|
1150
|
+
:class:`~sage.schemes.elliptic_curves.hom.EllipticCurveHom`
|
|
1151
|
+
objects.
|
|
1152
|
+
|
|
1153
|
+
EXAMPLES::
|
|
1154
|
+
|
|
1155
|
+
sage: E = EllipticCurve(GF(19), [1,0])
|
|
1156
|
+
sage: type(E._Hom_(E))
|
|
1157
|
+
<class 'sage.schemes.elliptic_curves.homset.EllipticCurveHomset_with_category'>
|
|
1158
|
+
"""
|
|
1159
|
+
if isinstance(other, ell_generic.EllipticCurve_generic) and self.base_ring() == other.base_ring():
|
|
1160
|
+
from . import homset
|
|
1161
|
+
return homset.EllipticCurveHomset(self, other, category=category)
|
|
1162
|
+
from sage.schemes.generic.homset import SchemeHomset_generic
|
|
1163
|
+
return SchemeHomset_generic(self, other, category=category)
|
|
1164
|
+
|
|
1165
|
+
def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, algorithm=None, velu_sqrt_bound=None):
|
|
1166
|
+
r"""
|
|
1167
|
+
Return an elliptic-curve isogeny from this elliptic curve.
|
|
1168
|
+
|
|
1169
|
+
The isogeny can be specified in two ways, by passing either a
|
|
1170
|
+
polynomial or a set of torsion points. The methods used are:
|
|
1171
|
+
|
|
1172
|
+
- Factored Isogenies (see
|
|
1173
|
+
:mod:`~sage.schemes.elliptic_curves.hom_composite`):
|
|
1174
|
+
Given a point, or a list of points which generate a
|
|
1175
|
+
composite-order subgroup, decomposes the isogeny into
|
|
1176
|
+
prime-degree steps. This can be used to construct isogenies
|
|
1177
|
+
of extremely large, smooth degree. When applicable, this
|
|
1178
|
+
algorithm is selected as default (see below). After factoring
|
|
1179
|
+
the degree single isogenies are computed using the other
|
|
1180
|
+
methods.
|
|
1181
|
+
This algorithm is selected using ``algorithm="factored"``.
|
|
1182
|
+
|
|
1183
|
+
- Vélu's Formulas: Vélu's original formulas for computing
|
|
1184
|
+
isogenies. This algorithm is selected by giving as the
|
|
1185
|
+
``kernel`` parameter a single point generating a finite
|
|
1186
|
+
subgroup.
|
|
1187
|
+
|
|
1188
|
+
- Kohel's Formulas: Kohel's original formulas for computing
|
|
1189
|
+
isogenies. This algorithm is selected by giving as the
|
|
1190
|
+
``kernel`` parameter a monic polynomial (or a coefficient list
|
|
1191
|
+
in little endian) which will define the kernel of the isogeny.
|
|
1192
|
+
Kohel's algorithm is currently only implemented for cyclic
|
|
1193
|
+
isogenies, with the exception of `[2]`.
|
|
1194
|
+
|
|
1195
|
+
- Îlu Algorithm (see
|
|
1196
|
+
:mod:`~sage.schemes.elliptic_curves.hom_velusqrt`):
|
|
1197
|
+
A variant of Vélu's formulas with essentially square-root
|
|
1198
|
+
instead of linear complexity (in the degree). Currently only
|
|
1199
|
+
available over finite fields. The input must be a single
|
|
1200
|
+
kernel point of odd order `\geq 5`.
|
|
1201
|
+
This algorithm is selected using ``algorithm="velusqrt"``.
|
|
1202
|
+
|
|
1203
|
+
INPUT:
|
|
1204
|
+
|
|
1205
|
+
- ``kernel`` -- a kernel; either a point on this curve, a list of
|
|
1206
|
+
points on this curve, a monic kernel polynomial, or ``None``.
|
|
1207
|
+
If initializing from a codomain, this must be ``None``.
|
|
1208
|
+
|
|
1209
|
+
- ``codomain`` -- an elliptic curve (default: ``None``).
|
|
1210
|
+
|
|
1211
|
+
- If ``kernel`` is ``None``, then ``degree`` must be given as well
|
|
1212
|
+
and the given ``codomain`` must be the codomain of a cyclic,
|
|
1213
|
+
separable, normalized isogeny of the given degree.
|
|
1214
|
+
|
|
1215
|
+
- If ``kernel`` is not ``None``, then this must be isomorphic to
|
|
1216
|
+
the codomain of the separable isogeny defined by ``kernel``; in
|
|
1217
|
+
this case, the isogeny is post-composed with an isomorphism so
|
|
1218
|
+
that the codomain equals the given curve.
|
|
1219
|
+
|
|
1220
|
+
- ``degree`` -- integer (default: ``None``).
|
|
1221
|
+
|
|
1222
|
+
- If ``kernel`` is ``None``, then this is the degree of the isogeny
|
|
1223
|
+
from this curve to ``codomain``.
|
|
1224
|
+
|
|
1225
|
+
- If ``kernel`` is not ``None``, then this is used to determine
|
|
1226
|
+
whether or not to skip a `\gcd` of the given kernel polynomial
|
|
1227
|
+
with the two-torsion polynomial of this curve.
|
|
1228
|
+
|
|
1229
|
+
- ``model`` -- string (default: ``None``); supported values
|
|
1230
|
+
(cf. :func:`~sage.schemes.elliptic_curves.ell_field.compute_model`):
|
|
1231
|
+
|
|
1232
|
+
- ``'minimal'``: if ``self`` is a curve over the rationals or
|
|
1233
|
+
over a number field, then the codomain is a global minimal
|
|
1234
|
+
model where this exists.
|
|
1235
|
+
|
|
1236
|
+
- ``'short_weierstrass'``: the codomain is a short Weierstrass curve,
|
|
1237
|
+
assuming one exists.
|
|
1238
|
+
|
|
1239
|
+
- ``'montgomery'``: the codomain is an (untwisted) Montgomery
|
|
1240
|
+
curve, assuming one exists over this field.
|
|
1241
|
+
|
|
1242
|
+
- ``check`` -- boolean (default: ``True``); check whether the input is valid.
|
|
1243
|
+
Setting this to ``False`` can lead to significant speedups.
|
|
1244
|
+
|
|
1245
|
+
- ``algorithm`` -- string (optional); the possible choices are:
|
|
1246
|
+
|
|
1247
|
+
- ``'velusqrt'``: Use
|
|
1248
|
+
:class:`~sage.schemes.elliptic_curves.hom_velusqrt.EllipticCurveHom_velusqrt`.
|
|
1249
|
+
|
|
1250
|
+
- ``'factored'``: Use
|
|
1251
|
+
:class:`~sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite`
|
|
1252
|
+
to decompose the isogeny into prime-degree steps.
|
|
1253
|
+
|
|
1254
|
+
- ``'traditional'``: Use
|
|
1255
|
+
:class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny`.
|
|
1256
|
+
|
|
1257
|
+
When ``algorithm`` is not specified, and ``kernel`` is not ``None``, an
|
|
1258
|
+
algorithm is selected using the following criteria:
|
|
1259
|
+
|
|
1260
|
+
- if ``kernel`` is a list of multiple points, ``'factored'`` is selected.
|
|
1261
|
+
|
|
1262
|
+
- If ``kernel`` is a single point, or a list containing a single point:
|
|
1263
|
+
|
|
1264
|
+
- if the order of the point is unknown, ``'traditional'`` is selected.
|
|
1265
|
+
|
|
1266
|
+
- If the order is known and composite, ``'factored'`` is selected.
|
|
1267
|
+
|
|
1268
|
+
- If the order is known and prime, a choice between ``'velusqrt'`` and
|
|
1269
|
+
``'traditional'`` is done according to the ``velu_sqrt_bound``
|
|
1270
|
+
parameter (see below).
|
|
1271
|
+
|
|
1272
|
+
If none of the previous apply, ``'traditional'`` is selected.
|
|
1273
|
+
|
|
1274
|
+
- ``velu_sqrt_bound`` -- integer (default: ``None``); establish the highest
|
|
1275
|
+
(prime) degree for which the ``'traditional'`` algorithm should be selected
|
|
1276
|
+
instead of ``'velusqrt'``. If ``None``, the default value from
|
|
1277
|
+
:class:`~sage.schemes.elliptic_curves.hom_velusqrt._VeluBoundObj` is used.
|
|
1278
|
+
This value is initially set to 1000, but can be modified by the user.
|
|
1279
|
+
If an integer is supplied and the isogeny computation goes through the
|
|
1280
|
+
``'factored'`` algorithm, the same integer is supplied to each factor.
|
|
1281
|
+
|
|
1282
|
+
The ``degree`` parameter is not supported when an ``algorithm`` is
|
|
1283
|
+
specified.
|
|
1284
|
+
|
|
1285
|
+
OUTPUT:
|
|
1286
|
+
|
|
1287
|
+
An isogeny between elliptic curves. This is a morphism of curves.
|
|
1288
|
+
(In all cases, the returned object will be an instance of
|
|
1289
|
+
:class:`~sage.schemes.elliptic_curves.hom.EllipticCurveHom`.)
|
|
1290
|
+
|
|
1291
|
+
EXAMPLES::
|
|
1292
|
+
|
|
1293
|
+
sage: # needs sage.rings.finite_rings
|
|
1294
|
+
sage: F = GF(2^5, 'alpha'); alpha = F.gen()
|
|
1295
|
+
sage: E = EllipticCurve(F, [1,0,1,1,1])
|
|
1296
|
+
sage: R.<x> = F[]
|
|
1297
|
+
sage: phi = E.isogeny(x + 1)
|
|
1298
|
+
sage: phi.rational_maps()
|
|
1299
|
+
((x^2 + x + 1)/(x + 1), (x^2*y + x)/(x^2 + 1))
|
|
1300
|
+
|
|
1301
|
+
::
|
|
1302
|
+
|
|
1303
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
1304
|
+
sage: E = EllipticCurve('11a1')
|
|
1305
|
+
sage: P = E.torsion_points()[1]
|
|
1306
|
+
sage: E.isogeny(P)
|
|
1307
|
+
Isogeny of degree 5
|
|
1308
|
+
from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20
|
|
1309
|
+
over Rational Field
|
|
1310
|
+
to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580
|
|
1311
|
+
over Rational Field
|
|
1312
|
+
|
|
1313
|
+
::
|
|
1314
|
+
|
|
1315
|
+
sage: E = EllipticCurve(GF(19),[1,1])
|
|
1316
|
+
sage: P = E(15,3); Q = E(2,12)
|
|
1317
|
+
sage: (P.order(), Q.order())
|
|
1318
|
+
(7, 3)
|
|
1319
|
+
sage: phi = E.isogeny([P,Q]); phi
|
|
1320
|
+
Composite morphism of degree 21 = 7*3:
|
|
1321
|
+
From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 19
|
|
1322
|
+
To: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 19
|
|
1323
|
+
sage: phi(E.random_point()) # all points defined over GF(19) are in the kernel
|
|
1324
|
+
(0 : 1 : 0)
|
|
1325
|
+
|
|
1326
|
+
::
|
|
1327
|
+
|
|
1328
|
+
sage: E = EllipticCurve(GF(2^32 - 5), [170246996, 2036646110]) # needs sage.rings.finite_rings
|
|
1329
|
+
sage: P = E.lift_x(2) # needs sage.rings.finite_rings
|
|
1330
|
+
sage: E.isogeny(P, algorithm='factored') # needs sage.rings.finite_rings
|
|
1331
|
+
Composite morphism of degree 1073721825 = 3^4*5^2*11*19*43*59:
|
|
1332
|
+
From: Elliptic Curve defined by y^2 = x^3 + 170246996*x + 2036646110
|
|
1333
|
+
over Finite Field of size 4294967291
|
|
1334
|
+
To: Elliptic Curve defined by y^2 = x^3 + 272790262*x + 1903695400
|
|
1335
|
+
over Finite Field of size 4294967291
|
|
1336
|
+
|
|
1337
|
+
Not all polynomials define a finite subgroup (:issue:`6384`)::
|
|
1338
|
+
|
|
1339
|
+
sage: E = EllipticCurve(GF(31), [1,0,0,1,2])
|
|
1340
|
+
sage: phi = E.isogeny([14,27,4,1])
|
|
1341
|
+
Traceback (most recent call last):
|
|
1342
|
+
...
|
|
1343
|
+
ValueError: the polynomial x^3 + 4*x^2 + 27*x + 14 does not define a finite
|
|
1344
|
+
subgroup of Elliptic Curve defined by y^2 + x*y = x^3 + x + 2
|
|
1345
|
+
over Finite Field of size 31
|
|
1346
|
+
|
|
1347
|
+
Order of the point known and composite::
|
|
1348
|
+
|
|
1349
|
+
sage: E = EllipticCurve(GF(31), [1,0,0,1,2])
|
|
1350
|
+
sage: P = E(26, 4)
|
|
1351
|
+
sage: assert P.order() == 12
|
|
1352
|
+
sage: print(P._order)
|
|
1353
|
+
12
|
|
1354
|
+
sage: E.isogeny(P)
|
|
1355
|
+
Composite morphism of degree 12 = 2^2*3:
|
|
1356
|
+
From: Elliptic Curve defined by y^2 + x*y = x^3 + x + 2 over Finite Field of size 31
|
|
1357
|
+
To: Elliptic Curve defined by y^2 + x*y = x^3 + 26*x + 8 over Finite Field of size 31
|
|
1358
|
+
|
|
1359
|
+
``kernel`` is a list of points::
|
|
1360
|
+
|
|
1361
|
+
sage: E = EllipticCurve(GF(31), [1,0,0,1,2])
|
|
1362
|
+
sage: P = E(21,2)
|
|
1363
|
+
sage: Q = E(7, 12)
|
|
1364
|
+
sage: print(P.order())
|
|
1365
|
+
6
|
|
1366
|
+
sage: print(Q.order())
|
|
1367
|
+
2
|
|
1368
|
+
sage: E.isogeny([P, Q])
|
|
1369
|
+
Composite morphism of degree 12 = 2*3*2:
|
|
1370
|
+
From: Elliptic Curve defined by y^2 + x*y = x^3 + x + 2 over Finite Field of size 31
|
|
1371
|
+
To: Elliptic Curve defined by y^2 + x*y = x^3 + 2*x + 26 over Finite Field of size 31
|
|
1372
|
+
|
|
1373
|
+
Multiple ways to set the ``velu_sqrt_bound``::
|
|
1374
|
+
|
|
1375
|
+
sage: E = EllipticCurve_from_j(GF(97)(42))
|
|
1376
|
+
sage: P = E.gens()[0]*4
|
|
1377
|
+
sage: print(P.order())
|
|
1378
|
+
23
|
|
1379
|
+
sage: E.isogeny(P)
|
|
1380
|
+
Isogeny of degree 23 from Elliptic Curve defined by y^2 = x^3 + 6*x + 46 over Finite Field of size 97 to Elliptic Curve defined by y^2 = x^3 + 72*x + 29 over Finite Field of size 97
|
|
1381
|
+
sage: E.isogeny(P, velu_sqrt_bound=10)
|
|
1382
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 23:
|
|
1383
|
+
From: Elliptic Curve defined by y^2 = x^3 + 6*x + 46 over Finite Field of size 97
|
|
1384
|
+
To: Elliptic Curve defined by y^2 = x^3 + 95*x + 68 over Finite Field of size 97
|
|
1385
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import _velu_sqrt_bound
|
|
1386
|
+
sage: _velu_sqrt_bound.set(10)
|
|
1387
|
+
sage: E.isogeny(P)
|
|
1388
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 23:
|
|
1389
|
+
From: Elliptic Curve defined by y^2 = x^3 + 6*x + 46 over Finite Field of size 97
|
|
1390
|
+
To: Elliptic Curve defined by y^2 = x^3 + 95*x + 68 over Finite Field of size 97
|
|
1391
|
+
sage: _velu_sqrt_bound.set(1000) # Reset bound
|
|
1392
|
+
|
|
1393
|
+
If the order of the point is unknown, fall back to ``'traditional'``::
|
|
1394
|
+
|
|
1395
|
+
sage: E = EllipticCurve_from_j(GF(97)(42))
|
|
1396
|
+
sage: P = E(2, 39)
|
|
1397
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import _velu_sqrt_bound
|
|
1398
|
+
sage: _velu_sqrt_bound.set(1)
|
|
1399
|
+
sage: E.isogeny(P)
|
|
1400
|
+
Isogeny of degree 46 from Elliptic Curve defined by y^2 = x^3 + 6*x + 46 over Finite Field of size 97 to Elliptic Curve defined by y^2 = x^3 + 87*x + 47 over Finite Field of size 97
|
|
1401
|
+
sage: _velu_sqrt_bound.set(1000) # Reset bound
|
|
1402
|
+
|
|
1403
|
+
.. SEEALSO::
|
|
1404
|
+
|
|
1405
|
+
- :class:`~sage.schemes.elliptic_curves.hom.EllipticCurveHom`
|
|
1406
|
+
- :class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny`
|
|
1407
|
+
- :class:`~sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite`
|
|
1408
|
+
|
|
1409
|
+
TESTS:
|
|
1410
|
+
|
|
1411
|
+
Until the checking of kernel polynomials was implemented in
|
|
1412
|
+
:issue:`23222`, the following raised no error but returned an
|
|
1413
|
+
invalid morphism. See also :issue:`11578`::
|
|
1414
|
+
|
|
1415
|
+
sage: # needs sage.rings.number_field
|
|
1416
|
+
sage: R.<x> = QQ[]
|
|
1417
|
+
sage: K.<a> = NumberField(x^2 - x - 1)
|
|
1418
|
+
sage: E = EllipticCurve(K, [-13392, -1080432])
|
|
1419
|
+
sage: R.<x> = K[]
|
|
1420
|
+
sage: phi = E.isogeny( (x-564)*(x - 396/5*a + 348/5) )
|
|
1421
|
+
Traceback (most recent call last):
|
|
1422
|
+
...
|
|
1423
|
+
ValueError: the polynomial x^2 + (-396/5*a - 2472/5)*x + 223344/5*a - 196272/5 does not
|
|
1424
|
+
define a finite subgroup of Elliptic Curve defined by y^2 = x^3 + (-13392)*x + (-1080432)
|
|
1425
|
+
over Number Field in a with defining polynomial x^2 - x - 1
|
|
1426
|
+
|
|
1427
|
+
We check that the cached order is correctly copied over::
|
|
1428
|
+
|
|
1429
|
+
sage: # needs sage.rings.finite_rings
|
|
1430
|
+
sage: E = EllipticCurve(GF(2^127 - 1), [1,2,3,4,5])
|
|
1431
|
+
sage: E.set_order(170141183460469231746191640949390434666)
|
|
1432
|
+
sage: phi = E.isogeny(E.lift_x(77347718128277853096420969229987528666))
|
|
1433
|
+
sage: phi.codomain()._order
|
|
1434
|
+
170141183460469231746191640949390434666
|
|
1435
|
+
|
|
1436
|
+
Check that ``factored`` recursively apply ``velu_sqrt_bound``::
|
|
1437
|
+
|
|
1438
|
+
sage: from sage.schemes.elliptic_curves.hom_velusqrt import _velu_sqrt_bound
|
|
1439
|
+
sage: _velu_sqrt_bound.get()
|
|
1440
|
+
1000
|
|
1441
|
+
sage: _velu_sqrt_bound.set(50)
|
|
1442
|
+
sage: _velu_sqrt_bound.get()
|
|
1443
|
+
50
|
|
1444
|
+
sage: from sage.schemes.elliptic_curves import hom_composite
|
|
1445
|
+
sage: p = 3217
|
|
1446
|
+
sage: E = EllipticCurve_from_j(GF(p)(42))
|
|
1447
|
+
sage: P = E.gens()[0]
|
|
1448
|
+
sage: phis = hom_composite._compute_factored_isogeny_single_generator(P, velu_sqrt_bound=50)
|
|
1449
|
+
sage: for phi in phis:
|
|
1450
|
+
....: print(phi)
|
|
1451
|
+
....:
|
|
1452
|
+
Isogeny of degree 31 from Elliptic Curve defined by y^2 = x^3 + 114*x + 544 over Finite Field of size 3217 to Elliptic Curve defined by y^2 = x^3 + 277*x + 1710 over Finite Field of size 3217
|
|
1453
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 103:
|
|
1454
|
+
From: Elliptic Curve defined by y^2 = x^3 + 277*x + 1710 over Finite Field of size 3217
|
|
1455
|
+
To: Elliptic Curve defined by y^2 = x^3 + 2979*x + 1951 over Finite Field of size 3217
|
|
1456
|
+
"""
|
|
1457
|
+
if algorithm is not None and degree is not None:
|
|
1458
|
+
raise TypeError('cannot pass "degree" and "algorithm" parameters simultaneously')
|
|
1459
|
+
if algorithm == "velusqrt":
|
|
1460
|
+
from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt
|
|
1461
|
+
return EllipticCurveHom_velusqrt(self, kernel, codomain=codomain, model=model)
|
|
1462
|
+
if algorithm == "factored":
|
|
1463
|
+
from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
1464
|
+
return EllipticCurveHom_composite(self, kernel, codomain=codomain, model=model, velu_sqrt_bound=velu_sqrt_bound)
|
|
1465
|
+
if algorithm == "traditional":
|
|
1466
|
+
return EllipticCurveIsogeny(self, kernel, codomain, degree, model, check=check)
|
|
1467
|
+
|
|
1468
|
+
if kernel is not None:
|
|
1469
|
+
# Check for multiple points or point of known order
|
|
1470
|
+
kernel_is_list = isinstance(kernel, (list, tuple))
|
|
1471
|
+
if kernel_is_list and kernel[0] in self and len(kernel) > 1:
|
|
1472
|
+
from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
1473
|
+
return EllipticCurveHom_composite(self, kernel, codomain=codomain, model=model, velu_sqrt_bound=velu_sqrt_bound)
|
|
1474
|
+
|
|
1475
|
+
if not kernel_is_list or (len(kernel) == 1 and kernel[0] in self):
|
|
1476
|
+
# Single point on the curve; unpack the list for compatibility with velusqrt
|
|
1477
|
+
if kernel_is_list:
|
|
1478
|
+
kernel = kernel[0]
|
|
1479
|
+
|
|
1480
|
+
known_order = hasattr(kernel, "_order")
|
|
1481
|
+
|
|
1482
|
+
if known_order and kernel._order.is_pseudoprime():
|
|
1483
|
+
if not velu_sqrt_bound:
|
|
1484
|
+
from sage.schemes.elliptic_curves.hom_velusqrt import _velu_sqrt_bound
|
|
1485
|
+
velu_sqrt_bound = _velu_sqrt_bound.get()
|
|
1486
|
+
|
|
1487
|
+
if kernel._order > velu_sqrt_bound:
|
|
1488
|
+
from sage.schemes.elliptic_curves.hom_velusqrt import EllipticCurveHom_velusqrt
|
|
1489
|
+
return EllipticCurveHom_velusqrt(self, kernel, codomain=codomain, model=model)
|
|
1490
|
+
# Otherwise fall back to the standard case
|
|
1491
|
+
elif known_order:
|
|
1492
|
+
from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
1493
|
+
return EllipticCurveHom_composite(self, kernel, codomain=codomain, model=model, velu_sqrt_bound=velu_sqrt_bound)
|
|
1494
|
+
try:
|
|
1495
|
+
return EllipticCurveIsogeny(self, kernel, codomain, degree, model, check=check)
|
|
1496
|
+
except AttributeError as e:
|
|
1497
|
+
raise RuntimeError("Unable to construct isogeny: %s" % e)
|
|
1498
|
+
|
|
1499
|
+
def isogeny_codomain(self, kernel):
|
|
1500
|
+
r"""
|
|
1501
|
+
Return the codomain of the isogeny from ``self`` with given kernel.
|
|
1502
|
+
|
|
1503
|
+
INPUT:
|
|
1504
|
+
|
|
1505
|
+
- ``kernel`` -- either a list of points in the kernel of the isogeny,
|
|
1506
|
+
or a kernel polynomial (specified as either a univariate polynomial
|
|
1507
|
+
or a coefficient list)
|
|
1508
|
+
|
|
1509
|
+
OUTPUT:
|
|
1510
|
+
|
|
1511
|
+
An elliptic curve, the codomain of the separable normalized
|
|
1512
|
+
isogeny defined by this kernel.
|
|
1513
|
+
|
|
1514
|
+
EXAMPLES::
|
|
1515
|
+
|
|
1516
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
1517
|
+
sage: E = EllipticCurve('17a1')
|
|
1518
|
+
sage: R.<x> = QQ[]
|
|
1519
|
+
sage: E2 = E.isogeny_codomain(x - 11/4); E2
|
|
1520
|
+
Elliptic Curve defined by y^2 + x*y + y = x^3 - x^2 - 1461/16*x - 19681/64
|
|
1521
|
+
over Rational Field
|
|
1522
|
+
|
|
1523
|
+
TESTS:
|
|
1524
|
+
|
|
1525
|
+
We check that the cached order is correctly copied over::
|
|
1526
|
+
|
|
1527
|
+
sage: # needs sage.rings.finite_rings
|
|
1528
|
+
sage: E = EllipticCurve(GF(2^127 - 1), [1,2,3,4,5])
|
|
1529
|
+
sage: E.set_order(170141183460469231746191640949390434666)
|
|
1530
|
+
sage: E2 = E.isogeny_codomain(E.lift_x(77347718128277853096420969229987528666))
|
|
1531
|
+
sage: E2._order
|
|
1532
|
+
170141183460469231746191640949390434666
|
|
1533
|
+
"""
|
|
1534
|
+
E = isogeny_codomain_from_kernel(self, kernel)
|
|
1535
|
+
if self.base_field().is_finite():
|
|
1536
|
+
E._fetch_cached_order(self)
|
|
1537
|
+
return E
|
|
1538
|
+
|
|
1539
|
+
def period_lattice(self):
|
|
1540
|
+
r"""
|
|
1541
|
+
Return the period lattice of the elliptic curve for the given
|
|
1542
|
+
embedding of its base field with respect to the differential
|
|
1543
|
+
`dx/(2y + a_1x + a_3)`.
|
|
1544
|
+
|
|
1545
|
+
Only supported for some base rings.
|
|
1546
|
+
|
|
1547
|
+
EXAMPLES::
|
|
1548
|
+
|
|
1549
|
+
sage: EllipticCurve(RR, [1, 6]).period_lattice()
|
|
1550
|
+
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 6.00000000000000 over Real Field with 53 bits of precision
|
|
1551
|
+
|
|
1552
|
+
TESTS::
|
|
1553
|
+
|
|
1554
|
+
sage: EllipticCurve(QQ, [1, 6]).period_lattice()
|
|
1555
|
+
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x + 6 over Rational Field
|
|
1556
|
+
sage: EllipticCurve(RR, [1, 6]).period_lattice()
|
|
1557
|
+
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 6.00000000000000 over Real Field with 53 bits of precision
|
|
1558
|
+
sage: EllipticCurve(RDF, [1, 6]).period_lattice()
|
|
1559
|
+
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.0*x + 6.0 over Real Double Field
|
|
1560
|
+
sage: EllipticCurve(RealField(100), [1, 6]).period_lattice()
|
|
1561
|
+
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.0000000000000000000000000000*x + 6.0000000000000000000000000000 over Real Field with 100 bits of precision
|
|
1562
|
+
sage: EllipticCurve(CC, [1, 6]).period_lattice()
|
|
1563
|
+
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 6.00000000000000 over Complex Field with 53 bits of precision
|
|
1564
|
+
sage: EllipticCurve(CDF, [1, 6]).period_lattice()
|
|
1565
|
+
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.0*x + 6.0 over Complex Double Field
|
|
1566
|
+
sage: EllipticCurve(ComplexField(100), [1, 6]).period_lattice()
|
|
1567
|
+
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.0000000000000000000000000000*x + 6.0000000000000000000000000000 over Complex Field with 100 bits of precision
|
|
1568
|
+
sage: EllipticCurve(AA, [1, 6]).period_lattice()
|
|
1569
|
+
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x + 6 over Algebraic Real Field
|
|
1570
|
+
sage: EllipticCurve(QQbar, [1, 6]).period_lattice()
|
|
1571
|
+
Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x + 6 over Algebraic Field
|
|
1572
|
+
|
|
1573
|
+
Unsupported cases (the exact error being raised may change in the future)::
|
|
1574
|
+
|
|
1575
|
+
sage: EllipticCurve(ZZ, [1, 6]).period_lattice()
|
|
1576
|
+
Traceback (most recent call last):
|
|
1577
|
+
...
|
|
1578
|
+
AttributeError: 'EllipticCurve_generic_with_category' object has no attribute 'period_lattice'
|
|
1579
|
+
sage: QQt.<t> = QQ[]
|
|
1580
|
+
sage: EllipticCurve(QQt.fraction_field(), [1, 6]).period_lattice()
|
|
1581
|
+
Traceback (most recent call last):
|
|
1582
|
+
...
|
|
1583
|
+
AttributeError: 'FractionField_1poly_field_with_category' object has no attribute ...
|
|
1584
|
+
sage: EllipticCurve(GF(7), [1, 6]).period_lattice()
|
|
1585
|
+
Traceback (most recent call last):
|
|
1586
|
+
...
|
|
1587
|
+
IndexError: list index out of range
|
|
1588
|
+
"""
|
|
1589
|
+
from sage.schemes.elliptic_curves.period_lattice import PeriodLattice_ell
|
|
1590
|
+
return PeriodLattice_ell(self)
|
|
1591
|
+
|
|
1592
|
+
def kernel_polynomial_from_point(self, P, *, algorithm=None):
|
|
1593
|
+
r"""
|
|
1594
|
+
Given a point `P` on this curve which generates a rational subgroup,
|
|
1595
|
+
return the kernel polynomial of that subgroup as a polynomial over
|
|
1596
|
+
the base field of the curve.
|
|
1597
|
+
|
|
1598
|
+
The point `P` itself may be defined over an extension.
|
|
1599
|
+
|
|
1600
|
+
EXAMPLES::
|
|
1601
|
+
|
|
1602
|
+
sage: E = EllipticCurve(GF(101), [1,1])
|
|
1603
|
+
sage: F = GF(101^3)
|
|
1604
|
+
sage: EE = E.change_ring(F)
|
|
1605
|
+
sage: xK = F([77, 28, 8]); xK
|
|
1606
|
+
8*z3^2 + 28*z3 + 77
|
|
1607
|
+
sage: K = EE.lift_x(xK); K.order()
|
|
1608
|
+
43
|
|
1609
|
+
sage: E.kernel_polynomial_from_point(K)
|
|
1610
|
+
x^21 + 7*x^20 + 22*x^19 + 4*x^18 + 7*x^17 + 81*x^16 + 41*x^15 + 68*x^14 + 18*x^13 + 58*x^12 + 31*x^11 + 26*x^10 + 62*x^9 + 20*x^8 + 73*x^7 + 23*x^6 + 66*x^5 + 79*x^4 + 12*x^3 + 40*x^2 + 50*x + 93
|
|
1611
|
+
|
|
1612
|
+
The ``'minpoly'`` algorithm is often much faster than the
|
|
1613
|
+
``'basic'`` algorithm::
|
|
1614
|
+
|
|
1615
|
+
sage: from sage.schemes.elliptic_curves.ell_field import EllipticCurve_field, point_of_order
|
|
1616
|
+
sage: p = 2^127 - 1
|
|
1617
|
+
sage: E = EllipticCurve(GF(p), [1,0])
|
|
1618
|
+
sage: P = point_of_order(E, 31) # long time (8.5s)
|
|
1619
|
+
sage: %timeit E.kernel_polynomial_from_point(P, algorithm='basic') # not tested
|
|
1620
|
+
4.38 ms ± 13.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
|
|
1621
|
+
sage: %timeit E.kernel_polynomial_from_point(P, algorithm='minpoly') # not tested
|
|
1622
|
+
854 µs ± 1.56 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
|
|
1623
|
+
|
|
1624
|
+
Example of finding all the rational isogenies using this method::
|
|
1625
|
+
|
|
1626
|
+
sage: E = EllipticCurve(GF(71), [1,2,3,4,5])
|
|
1627
|
+
sage: F = E.division_field(11)
|
|
1628
|
+
sage: EE = E.change_ring(F)
|
|
1629
|
+
sage: fs = set()
|
|
1630
|
+
sage: for K in EE(0).division_points(11):
|
|
1631
|
+
....: if not K:
|
|
1632
|
+
....: continue
|
|
1633
|
+
....: Kp = EE.frobenius_isogeny()(K)
|
|
1634
|
+
....: if Kp.weil_pairing(K, 11) == 1:
|
|
1635
|
+
....: fs.add(E.kernel_polynomial_from_point(K))
|
|
1636
|
+
sage: fs = sorted(fs); fs
|
|
1637
|
+
[x^5 + 10*x^4 + 18*x^3 + 10*x^2 + 43*x + 46,
|
|
1638
|
+
x^5 + 65*x^4 + 39*x^2 + 20*x + 63]
|
|
1639
|
+
sage: from sage.schemes.elliptic_curves.isogeny_small_degree import is_kernel_polynomial
|
|
1640
|
+
sage: {is_kernel_polynomial(E, 11, f) for f in fs}
|
|
1641
|
+
{True}
|
|
1642
|
+
sage: isogs = [E.isogeny(f) for f in fs]
|
|
1643
|
+
sage: isogs[0]
|
|
1644
|
+
Isogeny of degree 11 from Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field of size 71 to Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 34*x + 42 over Finite Field of size 71
|
|
1645
|
+
sage: isogs[1]
|
|
1646
|
+
Isogeny of degree 11 from Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5 over Finite Field of size 71 to Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 12*x + 40 over Finite Field of size 71
|
|
1647
|
+
sage: set(isogs) == set(E.isogenies_prime_degree(11))
|
|
1648
|
+
True
|
|
1649
|
+
|
|
1650
|
+
ALGORITHM:
|
|
1651
|
+
|
|
1652
|
+
- The ``'basic'`` algorithm is to multiply together all the linear
|
|
1653
|
+
factors `(X - x([i]P))` of the kernel polynomial using a product
|
|
1654
|
+
tree, then converting the result to the base field of the curve.
|
|
1655
|
+
Its complexity is `\widetilde O(\ell k)` where `k` is the
|
|
1656
|
+
extension degree.
|
|
1657
|
+
|
|
1658
|
+
- The ``'minpoly'`` algorithm is
|
|
1659
|
+
[EPSV2023]_, Algorithm 4 (``KernelPolynomialFromIrrationalX``).
|
|
1660
|
+
Over finite fields, its complexity is `O(\ell k) + \widetilde O(\ell)`
|
|
1661
|
+
where `k` is the extension degree.
|
|
1662
|
+
"""
|
|
1663
|
+
R = self.base_ring()
|
|
1664
|
+
|
|
1665
|
+
if not P:
|
|
1666
|
+
return R['x'].one()
|
|
1667
|
+
|
|
1668
|
+
S = P.base_ring()
|
|
1669
|
+
if not S.has_coerce_map_from(R):
|
|
1670
|
+
raise TypeError(f'{R} does not coerce into {S}')
|
|
1671
|
+
|
|
1672
|
+
EE = self.change_ring(S)
|
|
1673
|
+
if P.curve() is not EE:
|
|
1674
|
+
raise TypeError(f'{P} is not a point on {EE}')
|
|
1675
|
+
|
|
1676
|
+
l = P.order()
|
|
1677
|
+
|
|
1678
|
+
if algorithm is None:
|
|
1679
|
+
if R in FiniteFields():
|
|
1680
|
+
# In this case the minpoly approach is likely to be faster.
|
|
1681
|
+
if l & 1 and l.is_prime_power():
|
|
1682
|
+
algorithm = 'minpoly'
|
|
1683
|
+
if algorithm is None:
|
|
1684
|
+
algorithm = 'basic'
|
|
1685
|
+
|
|
1686
|
+
if algorithm == 'basic':
|
|
1687
|
+
from sage.groups.generic import multiples
|
|
1688
|
+
Qs = multiples(P, l//2, P)
|
|
1689
|
+
x = polygen(S)
|
|
1690
|
+
f = prod(x - Q.xy()[0] for Q in Qs)
|
|
1691
|
+
return f.change_ring(R)
|
|
1692
|
+
|
|
1693
|
+
if algorithm == 'minpoly':
|
|
1694
|
+
if not l & 1 or not l.is_prime_power():
|
|
1695
|
+
raise ValueError('algorithm "minpoly" only supports odd prime-power degrees')
|
|
1696
|
+
|
|
1697
|
+
xx = P.xy()[0]
|
|
1698
|
+
ext = xx.parent().over(self.base_ring())
|
|
1699
|
+
mu = ext(xx).minpoly()
|
|
1700
|
+
assert mu.base_ring() == self.base_ring()
|
|
1701
|
+
|
|
1702
|
+
return self.kernel_polynomial_from_divisor(mu, P.order(), check=False)
|
|
1703
|
+
|
|
1704
|
+
raise ValueError('unknown algorithm')
|
|
1705
|
+
|
|
1706
|
+
def kernel_polynomial_from_divisor(self, f, l, *, check=True):
|
|
1707
|
+
r"""
|
|
1708
|
+
Given an irreducible divisor `f` of the `l`-division polynomial
|
|
1709
|
+
on this curve, return the kernel polynomial defining the subgroup
|
|
1710
|
+
defined by `f`.
|
|
1711
|
+
|
|
1712
|
+
If the given polynomial does not define a rational subgroup, a
|
|
1713
|
+
:exc:`ValueError` is raised.
|
|
1714
|
+
|
|
1715
|
+
This method is currently only implemented for prime `l`.
|
|
1716
|
+
|
|
1717
|
+
EXAMPLES::
|
|
1718
|
+
|
|
1719
|
+
sage: E = EllipticCurve(GF(101^2), [0,1])
|
|
1720
|
+
sage: f,_ = E.division_polynomial(5).factor()[0]
|
|
1721
|
+
sage: ker = E.kernel_polynomial_from_divisor(f, 5); ker
|
|
1722
|
+
x^2 + (49*z2 + 10)*x + 30*z2 + 80
|
|
1723
|
+
sage: E.isogeny(ker)
|
|
1724
|
+
Isogeny of degree 5
|
|
1725
|
+
from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field in z2 of size 101^2
|
|
1726
|
+
to Elliptic Curve defined by y^2 = x^3 + (6*z2+16)*x + 18 over Finite Field in z2 of size 101^2
|
|
1727
|
+
|
|
1728
|
+
The method detects invalid inputs::
|
|
1729
|
+
|
|
1730
|
+
sage: E = EllipticCurve(GF(101), [0,1])
|
|
1731
|
+
sage: f,_ = E.division_polynomial(5).factor()[-1]
|
|
1732
|
+
sage: E.kernel_polynomial_from_divisor(f, 5)
|
|
1733
|
+
Traceback (most recent call last):
|
|
1734
|
+
...
|
|
1735
|
+
ValueError: given polynomial does not define a rational 5-isogeny
|
|
1736
|
+
|
|
1737
|
+
::
|
|
1738
|
+
|
|
1739
|
+
sage: E = EllipticCurve(GF(101), [1,1])
|
|
1740
|
+
sage: f,_ = E.division_polynomial(7).factor()[-1]
|
|
1741
|
+
sage: E.kernel_polynomial_from_divisor(f, 7)
|
|
1742
|
+
Traceback (most recent call last):
|
|
1743
|
+
...
|
|
1744
|
+
ValueError: given polynomial does not define a rational 7-isogeny
|
|
1745
|
+
|
|
1746
|
+
::
|
|
1747
|
+
|
|
1748
|
+
sage: x = polygen(QQ)
|
|
1749
|
+
sage: K.<t> = NumberField(x^12 - 2*x^10 + 3*x^8 + 228/13*x^6 + 235/13*x^4 + 22/13*x^2 + 1/13)
|
|
1750
|
+
sage: E = EllipticCurve(K, [1,0])
|
|
1751
|
+
sage: ker = E.kernel_polynomial_from_divisor(x - t, 13); ker
|
|
1752
|
+
x^6 + (-169/64*t^10 + 169/32*t^8 - 247/32*t^6 - 377/8*t^4 - 2977/64*t^2 - 105/32)*x^4 + (-169/32*t^10 + 169/16*t^8 - 247/16*t^6 - 377/4*t^4 - 2977/32*t^2 - 89/16)*x^2 - 13/64*t^10 + 13/32*t^8 - 19/32*t^6 - 29/8*t^4 - 229/64*t^2 - 13/32
|
|
1753
|
+
sage: phi = E.isogeny(ker, check=True); phi
|
|
1754
|
+
Isogeny of degree 13
|
|
1755
|
+
from Elliptic Curve defined by y^2 = x^3 + x
|
|
1756
|
+
over Number Field in t with defining polynomial x^12 - 2*x^10 + 3*x^8 + 228/13*x^6 + 235/13*x^4 + 22/13*x^2 + 1/13
|
|
1757
|
+
to Elliptic Curve defined by y^2 = x^3 + (-2535/16*t^10+2535/8*t^8-3705/8*t^6-5655/2*t^4-44655/16*t^2-2047/8)*x
|
|
1758
|
+
over Number Field in t with defining polynomial x^12 - 2*x^10 + 3*x^8 + 228/13*x^6 + 235/13*x^4 + 22/13*x^2 + 1/13
|
|
1759
|
+
|
|
1760
|
+
ALGORITHM: [EPSV2023]_, Algorithm 3 (``KernelPolynomialFromDivisor``).
|
|
1761
|
+
"""
|
|
1762
|
+
l = ZZ(l)
|
|
1763
|
+
if check:
|
|
1764
|
+
if not l.is_prime():
|
|
1765
|
+
raise NotImplementedError('currently, kernel_polynomial_from_divisor() only supports prime orders')
|
|
1766
|
+
if not f.is_irreducible():
|
|
1767
|
+
raise NotImplementedError('currently, kernel_polynomial_from_divisor() only supports irreducible polynomials')
|
|
1768
|
+
if f.parent().base_ring() != self.base_ring():
|
|
1769
|
+
raise TypeError('given polynomial is not defined over the base ring of the curve')
|
|
1770
|
+
if self.division_polynomial(l, x=f.parent().quotient_ring(f).gen()):
|
|
1771
|
+
raise ValueError(f'given polynomial does not divide the {l}-division polynomial')
|
|
1772
|
+
|
|
1773
|
+
if l == 2:
|
|
1774
|
+
return f
|
|
1775
|
+
|
|
1776
|
+
if not f.degree().divides(l//2):
|
|
1777
|
+
raise ValueError(f'given polynomial does not define a rational {l}-isogeny')
|
|
1778
|
+
|
|
1779
|
+
from sage.schemes.elliptic_curves.isogeny_small_degree import _least_semi_primitive
|
|
1780
|
+
a = _least_semi_primitive(l)
|
|
1781
|
+
|
|
1782
|
+
def mul_a(x):
|
|
1783
|
+
return self._multiple_x_numerator(a, x=x) / self._multiple_x_denominator(a, x=x)
|
|
1784
|
+
|
|
1785
|
+
def x_mod(g):
|
|
1786
|
+
return g.parent().quotient(g).gen()
|
|
1787
|
+
|
|
1788
|
+
fs = [f]
|
|
1789
|
+
m = l//2//f.degree()
|
|
1790
|
+
|
|
1791
|
+
for i in range(1, m):
|
|
1792
|
+
fs.append(mul_a(x_mod(fs[-1])).minpoly())
|
|
1793
|
+
|
|
1794
|
+
if fs[0](mul_a(x_mod(fs[-1]))):
|
|
1795
|
+
raise ValueError(f'given polynomial does not define a rational {l}-isogeny')
|
|
1796
|
+
|
|
1797
|
+
return prod(fs)
|
|
1798
|
+
|
|
1799
|
+
def isogenies_prime_degree(self, l=None, max_l=31) -> list:
|
|
1800
|
+
"""
|
|
1801
|
+
Return a list of all separable isogenies (up to post-composition with
|
|
1802
|
+
isomorphisms) of given prime degree(s) with domain equal to ``self``,
|
|
1803
|
+
which are defined over the base field of ``self``.
|
|
1804
|
+
|
|
1805
|
+
INPUT:
|
|
1806
|
+
|
|
1807
|
+
- ``l`` -- a prime or a list of primes
|
|
1808
|
+
|
|
1809
|
+
- ``max_l`` -- (default: 31) a bound on the primes to be tested.
|
|
1810
|
+
This is only used if ``l`` is ``None``.
|
|
1811
|
+
|
|
1812
|
+
OUTPUT:
|
|
1813
|
+
|
|
1814
|
+
(list) All separable `l`-isogenies for the given `l` with domain ``self``.
|
|
1815
|
+
|
|
1816
|
+
ALGORITHM:
|
|
1817
|
+
|
|
1818
|
+
Calls the generic function :func:`isogenies_prime_degree()`.
|
|
1819
|
+
This is generic code, valid for all fields. It requires that
|
|
1820
|
+
certain operations have been implemented over the base field,
|
|
1821
|
+
such as root-finding for univariate polynomials.
|
|
1822
|
+
|
|
1823
|
+
EXAMPLES:
|
|
1824
|
+
|
|
1825
|
+
Examples over finite fields::
|
|
1826
|
+
|
|
1827
|
+
sage: # needs sage.libs.pari
|
|
1828
|
+
sage: E = EllipticCurve(GF(next_prime(1000000)), [7,8])
|
|
1829
|
+
sage: E.isogenies_prime_degree(2)
|
|
1830
|
+
[Isogeny of degree 2
|
|
1831
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1832
|
+
to Elliptic Curve defined by y^2 = x^3 + 970389*x + 794257 over Finite Field of size 1000003,
|
|
1833
|
+
Isogeny of degree 2
|
|
1834
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1835
|
+
to Elliptic Curve defined by y^2 = x^3 + 29783*x + 206196 over Finite Field of size 1000003,
|
|
1836
|
+
Isogeny of degree 2
|
|
1837
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1838
|
+
to Elliptic Curve defined by y^2 = x^3 + 999960*x + 78 over Finite Field of size 1000003]
|
|
1839
|
+
sage: E.isogenies_prime_degree(3)
|
|
1840
|
+
[]
|
|
1841
|
+
sage: E.isogenies_prime_degree(5)
|
|
1842
|
+
[]
|
|
1843
|
+
sage: E.isogenies_prime_degree(7)
|
|
1844
|
+
[]
|
|
1845
|
+
sage: E.isogenies_prime_degree(11)
|
|
1846
|
+
[]
|
|
1847
|
+
sage: E.isogenies_prime_degree(13)
|
|
1848
|
+
[Isogeny of degree 13
|
|
1849
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1850
|
+
to Elliptic Curve defined by y^2 = x^3 + 878063*x + 845666 over Finite Field of size 1000003,
|
|
1851
|
+
Isogeny of degree 13
|
|
1852
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1853
|
+
to Elliptic Curve defined by y^2 = x^3 + 375648*x + 342776 over Finite Field of size 1000003]
|
|
1854
|
+
sage: E.isogenies_prime_degree(max_l=13)
|
|
1855
|
+
[Isogeny of degree 2
|
|
1856
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1857
|
+
to Elliptic Curve defined by y^2 = x^3 + 970389*x + 794257 over Finite Field of size 1000003,
|
|
1858
|
+
Isogeny of degree 2
|
|
1859
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1860
|
+
to Elliptic Curve defined by y^2 = x^3 + 29783*x + 206196 over Finite Field of size 1000003,
|
|
1861
|
+
Isogeny of degree 2
|
|
1862
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1863
|
+
to Elliptic Curve defined by y^2 = x^3 + 999960*x + 78 over Finite Field of size 1000003,
|
|
1864
|
+
Isogeny of degree 13
|
|
1865
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1866
|
+
to Elliptic Curve defined by y^2 = x^3 + 878063*x + 845666 over Finite Field of size 1000003,
|
|
1867
|
+
Isogeny of degree 13
|
|
1868
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1869
|
+
to Elliptic Curve defined by y^2 = x^3 + 375648*x + 342776 over Finite Field of size 1000003]
|
|
1870
|
+
sage: E.isogenies_prime_degree() # Default limit of 31
|
|
1871
|
+
[Isogeny of degree 2
|
|
1872
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1873
|
+
to Elliptic Curve defined by y^2 = x^3 + 970389*x + 794257 over Finite Field of size 1000003,
|
|
1874
|
+
Isogeny of degree 2
|
|
1875
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1876
|
+
to Elliptic Curve defined by y^2 = x^3 + 29783*x + 206196 over Finite Field of size 1000003,
|
|
1877
|
+
Isogeny of degree 2
|
|
1878
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1879
|
+
to Elliptic Curve defined by y^2 = x^3 + 999960*x + 78 over Finite Field of size 1000003,
|
|
1880
|
+
Isogeny of degree 13
|
|
1881
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1882
|
+
to Elliptic Curve defined by y^2 = x^3 + 878063*x + 845666 over Finite Field of size 1000003,
|
|
1883
|
+
Isogeny of degree 13
|
|
1884
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1885
|
+
to Elliptic Curve defined by y^2 = x^3 + 375648*x + 342776 over Finite Field of size 1000003,
|
|
1886
|
+
Isogeny of degree 17
|
|
1887
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1888
|
+
to Elliptic Curve defined by y^2 = x^3 + 347438*x + 594729 over Finite Field of size 1000003,
|
|
1889
|
+
Isogeny of degree 17
|
|
1890
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1891
|
+
to Elliptic Curve defined by y^2 = x^3 + 674846*x + 7392 over Finite Field of size 1000003,
|
|
1892
|
+
Isogeny of degree 23
|
|
1893
|
+
from Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 1000003
|
|
1894
|
+
to Elliptic Curve defined by y^2 = x^3 + 390065*x + 605596 over Finite Field of size 1000003]
|
|
1895
|
+
|
|
1896
|
+
sage: E = EllipticCurve(GF(17), [2,0])
|
|
1897
|
+
sage: E.isogenies_prime_degree(3)
|
|
1898
|
+
[]
|
|
1899
|
+
sage: E.isogenies_prime_degree(2)
|
|
1900
|
+
[Isogeny of degree 2
|
|
1901
|
+
from Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 17
|
|
1902
|
+
to Elliptic Curve defined by y^2 = x^3 + 9*x over Finite Field of size 17,
|
|
1903
|
+
Isogeny of degree 2
|
|
1904
|
+
from Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 17
|
|
1905
|
+
to Elliptic Curve defined by y^2 = x^3 + 5*x + 9 over Finite Field of size 17,
|
|
1906
|
+
Isogeny of degree 2
|
|
1907
|
+
from Elliptic Curve defined by y^2 = x^3 + 2*x over Finite Field of size 17
|
|
1908
|
+
to Elliptic Curve defined by y^2 = x^3 + 5*x + 8 over Finite Field of size 17]
|
|
1909
|
+
|
|
1910
|
+
The base field matters, over a field extension we find more
|
|
1911
|
+
isogenies::
|
|
1912
|
+
|
|
1913
|
+
sage: E = EllipticCurve(GF(13), [2,8])
|
|
1914
|
+
sage: E.isogenies_prime_degree(max_l=3)
|
|
1915
|
+
[Isogeny of degree 2
|
|
1916
|
+
from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field of size 13
|
|
1917
|
+
to Elliptic Curve defined by y^2 = x^3 + 7*x + 4 over Finite Field of size 13,
|
|
1918
|
+
Isogeny of degree 3
|
|
1919
|
+
from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field of size 13
|
|
1920
|
+
to Elliptic Curve defined by y^2 = x^3 + 9*x + 11 over Finite Field of size 13]
|
|
1921
|
+
|
|
1922
|
+
sage: # needs sage.rings.finite_rings
|
|
1923
|
+
sage: E = EllipticCurve(GF(13^6), [2,8])
|
|
1924
|
+
sage: E.isogenies_prime_degree(max_l=3)
|
|
1925
|
+
[Isogeny of degree 2
|
|
1926
|
+
from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6
|
|
1927
|
+
to Elliptic Curve defined by y^2 = x^3 + 7*x + 4 over Finite Field in z6 of size 13^6,
|
|
1928
|
+
Isogeny of degree 2
|
|
1929
|
+
from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6
|
|
1930
|
+
to Elliptic Curve defined by y^2 = x^3 + (2*z6^5+6*z6^4+9*z6^3+8*z6+7)*x + (3*z6^5+9*z6^4+7*z6^3+12*z6+7) over Finite Field in z6 of size 13^6,
|
|
1931
|
+
Isogeny of degree 2
|
|
1932
|
+
from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6
|
|
1933
|
+
to Elliptic Curve defined by y^2 = x^3 + (11*z6^5+7*z6^4+4*z6^3+5*z6+9)*x + (10*z6^5+4*z6^4+6*z6^3+z6+10) over Finite Field in z6 of size 13^6,
|
|
1934
|
+
Isogeny of degree 3
|
|
1935
|
+
from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6
|
|
1936
|
+
to Elliptic Curve defined by y^2 = x^3 + 9*x + 11 over Finite Field in z6 of size 13^6,
|
|
1937
|
+
Isogeny of degree 3
|
|
1938
|
+
from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6
|
|
1939
|
+
to Elliptic Curve defined by y^2 = x^3 + (3*z6^5+5*z6^4+8*z6^3+11*z6^2+5*z6+12)*x + (12*z6^5+6*z6^4+8*z6^3+4*z6^2+7*z6+6) over Finite Field in z6 of size 13^6,
|
|
1940
|
+
Isogeny of degree 3
|
|
1941
|
+
from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6
|
|
1942
|
+
to Elliptic Curve defined by y^2 = x^3 + (7*z6^4+12*z6^3+7*z6^2+4)*x + (6*z6^5+10*z6^3+12*z6^2+10*z6+8) over Finite Field in z6 of size 13^6,
|
|
1943
|
+
Isogeny of degree 3
|
|
1944
|
+
from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field in z6 of size 13^6
|
|
1945
|
+
to Elliptic Curve defined by y^2 = x^3 + (10*z6^5+z6^4+6*z6^3+8*z6^2+8*z6)*x + (8*z6^5+7*z6^4+8*z6^3+10*z6^2+9*z6+7) over Finite Field in z6 of size 13^6]
|
|
1946
|
+
|
|
1947
|
+
If the degree equals the characteristic, we find only separable
|
|
1948
|
+
isogenies::
|
|
1949
|
+
|
|
1950
|
+
sage: E = EllipticCurve(GF(13), [2,8])
|
|
1951
|
+
sage: E.isogenies_prime_degree(13)
|
|
1952
|
+
[Isogeny of degree 13
|
|
1953
|
+
from Elliptic Curve defined by y^2 = x^3 + 2*x + 8 over Finite Field of size 13
|
|
1954
|
+
to Elliptic Curve defined by y^2 = x^3 + 6*x + 5 over Finite Field of size 13]
|
|
1955
|
+
sage: E = EllipticCurve(GF(5), [1,1])
|
|
1956
|
+
sage: E.isogenies_prime_degree(5)
|
|
1957
|
+
[Isogeny of degree 5
|
|
1958
|
+
from Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 5
|
|
1959
|
+
to Elliptic Curve defined by y^2 = x^3 + x + 4 over Finite Field of size 5]
|
|
1960
|
+
|
|
1961
|
+
sage: # needs sage.rings.finite_rings
|
|
1962
|
+
sage: k.<a> = GF(3^4)
|
|
1963
|
+
sage: E = EllipticCurve(k, [0,1,0,0,a])
|
|
1964
|
+
sage: E.isogenies_prime_degree(3)
|
|
1965
|
+
[Isogeny of degree 3
|
|
1966
|
+
from Elliptic Curve defined by y^2 = x^3 + x^2 + a
|
|
1967
|
+
over Finite Field in a of size 3^4
|
|
1968
|
+
to Elliptic Curve defined by y^2 = x^3 + x^2 + (2*a^3+a^2+2)*x + (a^2+2)
|
|
1969
|
+
over Finite Field in a of size 3^4]
|
|
1970
|
+
|
|
1971
|
+
In the supersingular case, there are no separable isogenies of
|
|
1972
|
+
degree equal to the characteristic::
|
|
1973
|
+
|
|
1974
|
+
sage: E = EllipticCurve(GF(5), [0,1])
|
|
1975
|
+
sage: E.isogenies_prime_degree(5)
|
|
1976
|
+
[]
|
|
1977
|
+
|
|
1978
|
+
An example over a rational function field::
|
|
1979
|
+
|
|
1980
|
+
sage: R.<t> = GF(5)[]
|
|
1981
|
+
sage: K = R.fraction_field()
|
|
1982
|
+
sage: E = EllipticCurve(K, [1, t^5])
|
|
1983
|
+
sage: E.isogenies_prime_degree(5)
|
|
1984
|
+
[Isogeny of degree 5
|
|
1985
|
+
from Elliptic Curve defined by y^2 = x^3 + x + t^5 over Fraction Field
|
|
1986
|
+
of Univariate Polynomial Ring in t over Finite Field of size 5
|
|
1987
|
+
to Elliptic Curve defined by y^2 = x^3 + x + 4*t over Fraction Field
|
|
1988
|
+
of Univariate Polynomial Ring in t over Finite Field of size 5]
|
|
1989
|
+
|
|
1990
|
+
Examples over number fields (other than QQ)::
|
|
1991
|
+
|
|
1992
|
+
sage: # needs sage.rings.number_field
|
|
1993
|
+
sage: x = polygen(ZZ, 'x')
|
|
1994
|
+
sage: QQroot2.<e> = NumberField(x^2 - 2)
|
|
1995
|
+
sage: E = EllipticCurve(QQroot2, j=8000)
|
|
1996
|
+
sage: E.isogenies_prime_degree()
|
|
1997
|
+
[Isogeny of degree 2
|
|
1998
|
+
from Elliptic Curve defined by y^2 = x^3 + (-150528000)*x + (-629407744000)
|
|
1999
|
+
over Number Field in e with defining polynomial x^2 - 2
|
|
2000
|
+
to Elliptic Curve defined by y^2 = x^3 + (-36750)*x + 2401000
|
|
2001
|
+
over Number Field in e with defining polynomial x^2 - 2,
|
|
2002
|
+
Isogeny of degree 2
|
|
2003
|
+
from Elliptic Curve defined by y^2 = x^3 + (-150528000)*x + (-629407744000)
|
|
2004
|
+
over Number Field in e with defining polynomial x^2 - 2
|
|
2005
|
+
to Elliptic Curve defined by y^2 = x^3 + (220500*e-257250)*x + (54022500*e-88837000)
|
|
2006
|
+
over Number Field in e with defining polynomial x^2 - 2,
|
|
2007
|
+
Isogeny of degree 2
|
|
2008
|
+
from Elliptic Curve defined by y^2 = x^3 + (-150528000)*x + (-629407744000)
|
|
2009
|
+
over Number Field in e with defining polynomial x^2 - 2
|
|
2010
|
+
to Elliptic Curve defined by y^2 = x^3 + (-220500*e-257250)*x + (-54022500*e-88837000)
|
|
2011
|
+
over Number Field in e with defining polynomial x^2 - 2]
|
|
2012
|
+
sage: E = EllipticCurve(QQroot2, [1,0,1,4, -6]); E
|
|
2013
|
+
Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + (-6)
|
|
2014
|
+
over Number Field in e with defining polynomial x^2 - 2
|
|
2015
|
+
sage: E.isogenies_prime_degree(2)
|
|
2016
|
+
[Isogeny of degree 2
|
|
2017
|
+
from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + (-6)
|
|
2018
|
+
over Number Field in e with defining polynomial x^2 - 2
|
|
2019
|
+
to Elliptic Curve defined by y^2 + x*y + y = x^3 + (-36)*x + (-70)
|
|
2020
|
+
over Number Field in e with defining polynomial x^2 - 2]
|
|
2021
|
+
sage: E.isogenies_prime_degree(3)
|
|
2022
|
+
[Isogeny of degree 3
|
|
2023
|
+
from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + (-6)
|
|
2024
|
+
over Number Field in e with defining polynomial x^2 - 2
|
|
2025
|
+
to Elliptic Curve defined by y^2 + x*y + y = x^3 + (-1)*x
|
|
2026
|
+
over Number Field in e with defining polynomial x^2 - 2,
|
|
2027
|
+
Isogeny of degree 3
|
|
2028
|
+
from Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + (-6)
|
|
2029
|
+
over Number Field in e with defining polynomial x^2 - 2
|
|
2030
|
+
to Elliptic Curve defined by y^2 + x*y + y = x^3 + (-171)*x + (-874)
|
|
2031
|
+
over Number Field in e with defining polynomial x^2 - 2]
|
|
2032
|
+
|
|
2033
|
+
These are not implemented yet::
|
|
2034
|
+
|
|
2035
|
+
sage: E = EllipticCurve(QQbar, [1,18]); E # needs sage.rings.number_field
|
|
2036
|
+
Elliptic Curve defined by y^2 = x^3 + x + 18 over Algebraic Field
|
|
2037
|
+
sage: E.isogenies_prime_degree() # needs sage.rings.number_field
|
|
2038
|
+
Traceback (most recent call last):
|
|
2039
|
+
...
|
|
2040
|
+
NotImplementedError: This code could be implemented for QQbar, but has not been yet.
|
|
2041
|
+
|
|
2042
|
+
sage: E = EllipticCurve(CC, [1,18]); E
|
|
2043
|
+
Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 18.0000000000000
|
|
2044
|
+
over Complex Field with 53 bits of precision
|
|
2045
|
+
sage: E.isogenies_prime_degree(11)
|
|
2046
|
+
Traceback (most recent call last):
|
|
2047
|
+
...
|
|
2048
|
+
NotImplementedError: This code could be implemented for general complex fields,
|
|
2049
|
+
but has not been yet.
|
|
2050
|
+
|
|
2051
|
+
TESTS::
|
|
2052
|
+
|
|
2053
|
+
sage: E = EllipticCurve(QQ, [1,1])
|
|
2054
|
+
sage: E.isogenies_prime_degree([2, 4])
|
|
2055
|
+
Traceback (most recent call last):
|
|
2056
|
+
...
|
|
2057
|
+
ValueError: 4 is not prime.
|
|
2058
|
+
sage: E.isogenies_prime_degree(4)
|
|
2059
|
+
Traceback (most recent call last):
|
|
2060
|
+
...
|
|
2061
|
+
ValueError: 4 is not prime.
|
|
2062
|
+
"""
|
|
2063
|
+
F = self.base_ring()
|
|
2064
|
+
if isinstance(F, sage.rings.abc.RealField):
|
|
2065
|
+
raise NotImplementedError("This code could be implemented for general real fields, but has not been yet.")
|
|
2066
|
+
if isinstance(F, sage.rings.abc.ComplexField):
|
|
2067
|
+
raise NotImplementedError("This code could be implemented for general complex fields, but has not been yet.")
|
|
2068
|
+
if isinstance(F, sage.rings.abc.AlgebraicField):
|
|
2069
|
+
raise NotImplementedError("This code could be implemented for QQbar, but has not been yet.")
|
|
2070
|
+
|
|
2071
|
+
if l is None:
|
|
2072
|
+
from sage.rings.fast_arith import prime_range
|
|
2073
|
+
L = prime_range(max_l + 1)
|
|
2074
|
+
else:
|
|
2075
|
+
try:
|
|
2076
|
+
l = list(l)
|
|
2077
|
+
except TypeError:
|
|
2078
|
+
L = [ZZ(l)]
|
|
2079
|
+
else:
|
|
2080
|
+
L = [ZZ(d) for d in l]
|
|
2081
|
+
|
|
2082
|
+
from .isogeny_small_degree import isogenies_prime_degree
|
|
2083
|
+
return sum([isogenies_prime_degree(self, d) for d in L], [])
|
|
2084
|
+
|
|
2085
|
+
def isogenies_degree(self, n, *, _intermediate=False):
|
|
2086
|
+
r"""
|
|
2087
|
+
Return an iterator of all separable isogenies of given degree (up to
|
|
2088
|
+
post-composition with isomorphisms) with domain equal to ``self``,
|
|
2089
|
+
which are defined over the base field of ``self``.
|
|
2090
|
+
|
|
2091
|
+
ALGORITHM:
|
|
2092
|
+
|
|
2093
|
+
The prime factors `p` of `n` are processed one by one in decreasing
|
|
2094
|
+
order, each time "branching" out by taking isogenies of degree `p`.
|
|
2095
|
+
|
|
2096
|
+
INPUT:
|
|
2097
|
+
|
|
2098
|
+
- ``n`` -- integer, or its
|
|
2099
|
+
:class:`~sage.structure.factorization.Factorization`.
|
|
2100
|
+
|
|
2101
|
+
- ``_intermediate`` -- (bool, default: False): If set, the isogenies
|
|
2102
|
+
from this curve to the curves traversed within the depth-first search
|
|
2103
|
+
are returned. This is for internal use only.
|
|
2104
|
+
|
|
2105
|
+
EXAMPLES::
|
|
2106
|
+
|
|
2107
|
+
sage: E = EllipticCurve(GF(11), [1, 1])
|
|
2108
|
+
sage: list(E.isogenies_degree(23 * 19))
|
|
2109
|
+
[Composite morphism of degree 437 = 23*19:
|
|
2110
|
+
From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 11
|
|
2111
|
+
To: Elliptic Curve defined by y^2 = x^3 + 8*x + 7 over Finite Field of size 11,
|
|
2112
|
+
Composite morphism of degree 437 = 23*19:
|
|
2113
|
+
From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 11
|
|
2114
|
+
To: Elliptic Curve defined by y^2 = x^3 + 6*x + 2 over Finite Field of size 11,
|
|
2115
|
+
Composite morphism of degree 437 = 23*19:
|
|
2116
|
+
From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 11
|
|
2117
|
+
To: Elliptic Curve defined by y^2 = x^3 + 2*x + 6 over Finite Field of size 11,
|
|
2118
|
+
Composite morphism of degree 437 = 23*19:
|
|
2119
|
+
From: Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 11
|
|
2120
|
+
To: Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 11]
|
|
2121
|
+
|
|
2122
|
+
::
|
|
2123
|
+
|
|
2124
|
+
sage: # needs sage.symbolic
|
|
2125
|
+
sage: E = EllipticCurve(GF(next_prime(2^32)), j=1728)
|
|
2126
|
+
sage: sorted([phi.codomain().j_invariant() for phi in E.isogenies_degree(11 * 17 * 19^2)])
|
|
2127
|
+
[1348157279, 1348157279, 1713365879, 1713365879, 3153894341, 3153894341,
|
|
2128
|
+
3225140514, 3225140514, 3673460198, 3673460198, 3994312564, 3994312564]
|
|
2129
|
+
sage: it = E.isogenies_degree(2^2); it
|
|
2130
|
+
<generator object EllipticCurve_field.isogenies_degree at 0x...>
|
|
2131
|
+
sage: all(phi.degree() == 2^2 for phi in it)
|
|
2132
|
+
True
|
|
2133
|
+
|
|
2134
|
+
We verify that the isogenies outputted are distinct. Note that we do
|
|
2135
|
+
not use a ``set`` or any hash-based data structure, as hashing
|
|
2136
|
+
isogenies is slow::
|
|
2137
|
+
|
|
2138
|
+
sage: # needs sage.symbolic
|
|
2139
|
+
sage: import itertools
|
|
2140
|
+
sage: all_distinct = lambda arr: all(x != y for x, y in itertools.combinations(arr, 2))
|
|
2141
|
+
sage: K.<z> = GF((19, 2))
|
|
2142
|
+
sage: E = EllipticCurve(K, [11*z+5, 14*z+3])
|
|
2143
|
+
sage: S = list(E.isogenies_degree(5^2)); len(S), all_distinct(S)
|
|
2144
|
+
(3, True)
|
|
2145
|
+
sage: S = list(E.isogenies_degree(5^2*11)); len(S), all_distinct(S)
|
|
2146
|
+
(6, True)
|
|
2147
|
+
sage: S = list(E.isogenies_degree(5^2*11^4)); len(S), all_distinct(S) # long time (2s)
|
|
2148
|
+
(15, True)
|
|
2149
|
+
|
|
2150
|
+
For curves over number fields, the number of distinct isogenies will usually be small::
|
|
2151
|
+
|
|
2152
|
+
sage: E = EllipticCurve(QQ, [0, 1, 0, -2, 0])
|
|
2153
|
+
sage: len(list(E.isogenies_degree(2**1)))
|
|
2154
|
+
3
|
|
2155
|
+
sage: len(list(E.isogenies_degree(2**5)))
|
|
2156
|
+
3
|
|
2157
|
+
sage: len(list(E.isogenies_degree(2**8))) # long time (8s)
|
|
2158
|
+
1
|
|
2159
|
+
|
|
2160
|
+
::
|
|
2161
|
+
|
|
2162
|
+
sage: pol = PolynomialRing(QQ, 'x')([529, 782, 1])
|
|
2163
|
+
sage: L.<a> = NumberField(pol)
|
|
2164
|
+
sage: E = EllipticCurve(j=-7072/1127*a + 2016)
|
|
2165
|
+
sage: len(list(E.isogenies_degree(2)))
|
|
2166
|
+
3
|
|
2167
|
+
sage: len(list(E.isogenies_degree(2**5)))
|
|
2168
|
+
3
|
|
2169
|
+
|
|
2170
|
+
::
|
|
2171
|
+
|
|
2172
|
+
sage: pol = PolynomialRing(QQ, 'x')([1, -3, 5, -5, 5, -3, 1])
|
|
2173
|
+
sage: L.<a> = NumberField(pol)
|
|
2174
|
+
sage: js = hilbert_class_polynomial(-23).roots(L, multiplicities=False)
|
|
2175
|
+
sage: E = EllipticCurve(j=choice(js))
|
|
2176
|
+
sage: len(list(E.isogenies_degree(2^3))) # long time (9s)
|
|
2177
|
+
10
|
|
2178
|
+
|
|
2179
|
+
TESTS::
|
|
2180
|
+
|
|
2181
|
+
sage: E = EllipticCurve(GF(next_prime(2^32)), j=1728)
|
|
2182
|
+
sage: list(E.isogenies_degree(2^2, _intermediate=True))
|
|
2183
|
+
[Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 4294967311
|
|
2184
|
+
Via: (u,r,s,t) = (1, 0, 0, 0),
|
|
2185
|
+
Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 4294967311
|
|
2186
|
+
to Elliptic Curve defined by y^2 = x^3 + 4294967307*x over Finite Field of size 4294967311,
|
|
2187
|
+
Composite morphism of degree 4 = 2^2:
|
|
2188
|
+
From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 4294967311
|
|
2189
|
+
To: Elliptic Curve defined by y^2 = x^3 + 16*x over Finite Field of size 4294967311,
|
|
2190
|
+
Composite morphism of degree 4 = 2^2:
|
|
2191
|
+
From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 4294967311
|
|
2192
|
+
To: Elliptic Curve defined by y^2 = x^3 + 4294967267*x + 4294967199 over Finite Field of size 4294967311,
|
|
2193
|
+
Composite morphism of degree 4 = 2^2:
|
|
2194
|
+
From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 4294967311
|
|
2195
|
+
To: Elliptic Curve defined by y^2 = x^3 + 4294967267*x + 112 over Finite Field of size 4294967311]
|
|
2196
|
+
sage: all(isog.domain() is E for isog in _)
|
|
2197
|
+
True
|
|
2198
|
+
sage: all(isog.domain() is E for isog in E.isogenies_degree(2^5, _intermediate=True)) # needs sage.symbolic
|
|
2199
|
+
True
|
|
2200
|
+
|
|
2201
|
+
The following curve has no degree-`53` isogenies, so the code is quick::
|
|
2202
|
+
|
|
2203
|
+
sage: E = EllipticCurve(GF(103), [3, 5])
|
|
2204
|
+
sage: E.isogenies_prime_degree(53)
|
|
2205
|
+
[]
|
|
2206
|
+
sage: list(E.isogenies_degree(product(prime_range(3, 53)) * 53))
|
|
2207
|
+
[]
|
|
2208
|
+
"""
|
|
2209
|
+
def compute_key(phi):
|
|
2210
|
+
"""
|
|
2211
|
+
Data used in ``hash(phi)`` excluding the expensive ``.kernel_polynomial``.
|
|
2212
|
+
"""
|
|
2213
|
+
return (phi.domain(), phi.codomain(), phi.degree(), phi.scaling_factor())
|
|
2214
|
+
|
|
2215
|
+
from sage.schemes.elliptic_curves.weierstrass_morphism import identity_morphism
|
|
2216
|
+
from sage.structure.factorization import Factorization
|
|
2217
|
+
|
|
2218
|
+
if not isinstance(n, Factorization):
|
|
2219
|
+
n = Integer(n).factor()
|
|
2220
|
+
|
|
2221
|
+
if n.value() == 1:
|
|
2222
|
+
yield identity_morphism(self)
|
|
2223
|
+
return
|
|
2224
|
+
|
|
2225
|
+
p = n[-1][0]
|
|
2226
|
+
seen = {}
|
|
2227
|
+
|
|
2228
|
+
def insert_seen(phi) -> bool:
|
|
2229
|
+
key = compute_key(phi)
|
|
2230
|
+
if key not in seen:
|
|
2231
|
+
seen[key] = [phi]
|
|
2232
|
+
return True
|
|
2233
|
+
for psi in seen[key]:
|
|
2234
|
+
if psi == phi:
|
|
2235
|
+
return False
|
|
2236
|
+
seen[key].append(phi)
|
|
2237
|
+
return True
|
|
2238
|
+
|
|
2239
|
+
if _intermediate:
|
|
2240
|
+
yield identity_morphism(self)
|
|
2241
|
+
|
|
2242
|
+
# isog: self -> E1
|
|
2243
|
+
for isog in self.isogenies_prime_degree(p):
|
|
2244
|
+
if _intermediate:
|
|
2245
|
+
if insert_seen(isog):
|
|
2246
|
+
# self -> E1
|
|
2247
|
+
yield isog
|
|
2248
|
+
|
|
2249
|
+
Eiso = isog.codomain()
|
|
2250
|
+
# next_isog : E1 -> E2
|
|
2251
|
+
for next_isog in Eiso.isogenies_degree(n / p, _intermediate=_intermediate):
|
|
2252
|
+
# psi: self -> E2
|
|
2253
|
+
psi = next_isog * isog
|
|
2254
|
+
if insert_seen(psi):
|
|
2255
|
+
# self -> E2
|
|
2256
|
+
yield psi
|
|
2257
|
+
|
|
2258
|
+
def is_isogenous(self, other, field=None) -> bool:
|
|
2259
|
+
"""
|
|
2260
|
+
Return whether or not ``self`` is isogenous to ``other``.
|
|
2261
|
+
|
|
2262
|
+
INPUT:
|
|
2263
|
+
|
|
2264
|
+
- ``other`` -- another elliptic curve
|
|
2265
|
+
|
|
2266
|
+
- ``field`` -- (default: ``None``) currently not implemented. A
|
|
2267
|
+
field containing the base fields of the two elliptic curves
|
|
2268
|
+
onto which the two curves may be extended to test if they
|
|
2269
|
+
are isogenous over this field. By default ``is_isogenous`` will
|
|
2270
|
+
not try to find this field unless one of the curves can be
|
|
2271
|
+
be extended into the base field of the ``other``, in which case
|
|
2272
|
+
it will test over the larger base field.
|
|
2273
|
+
|
|
2274
|
+
OUTPUT: boolean; ``True`` if there is an isogeny from curve ``self`` to
|
|
2275
|
+
curve ``other`` defined over ``field``
|
|
2276
|
+
|
|
2277
|
+
METHOD:
|
|
2278
|
+
|
|
2279
|
+
Over general fields this is only implemented in trivial cases.
|
|
2280
|
+
|
|
2281
|
+
EXAMPLES::
|
|
2282
|
+
|
|
2283
|
+
sage: E1 = EllipticCurve(CC, [1,18]); E1
|
|
2284
|
+
Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 18.0000000000000
|
|
2285
|
+
over Complex Field with 53 bits of precision
|
|
2286
|
+
sage: E2 = EllipticCurve(CC, [2,7]); E2
|
|
2287
|
+
Elliptic Curve defined by y^2 = x^3 + 2.00000000000000*x + 7.00000000000000
|
|
2288
|
+
over Complex Field with 53 bits of precision
|
|
2289
|
+
sage: E1.is_isogenous(E2)
|
|
2290
|
+
Traceback (most recent call last):
|
|
2291
|
+
...
|
|
2292
|
+
NotImplementedError: Only implemented for isomorphic curves over general fields.
|
|
2293
|
+
|
|
2294
|
+
sage: E1 = EllipticCurve(Frac(PolynomialRing(ZZ,'t')), [2,19]); E1
|
|
2295
|
+
Elliptic Curve defined by y^2 = x^3 + 2*x + 19
|
|
2296
|
+
over Fraction Field of Univariate Polynomial Ring in t over Integer Ring
|
|
2297
|
+
sage: E2 = EllipticCurve(CC, [23,4]); E2
|
|
2298
|
+
Elliptic Curve defined by y^2 = x^3 + 23.0000000000000*x + 4.00000000000000
|
|
2299
|
+
over Complex Field with 53 bits of precision
|
|
2300
|
+
sage: E1.is_isogenous(E2)
|
|
2301
|
+
Traceback (most recent call last):
|
|
2302
|
+
...
|
|
2303
|
+
NotImplementedError: Only implemented for isomorphic curves over general fields.
|
|
2304
|
+
"""
|
|
2305
|
+
from .ell_generic import EllipticCurve_generic
|
|
2306
|
+
if not isinstance(other, EllipticCurve_generic):
|
|
2307
|
+
raise ValueError("Second argument is not an Elliptic Curve.")
|
|
2308
|
+
if self.is_isomorphic(other):
|
|
2309
|
+
return True
|
|
2310
|
+
else:
|
|
2311
|
+
raise NotImplementedError("Only implemented for isomorphic curves over general fields.")
|
|
2312
|
+
|
|
2313
|
+
def weierstrass_p(self, prec=20, algorithm=None):
|
|
2314
|
+
r"""
|
|
2315
|
+
Compute the Weierstrass `\wp`-function of this elliptic curve.
|
|
2316
|
+
|
|
2317
|
+
ALGORITHM: :func:`sage.schemes.elliptic_curves.ell_wp.weierstrass_p`
|
|
2318
|
+
|
|
2319
|
+
INPUT:
|
|
2320
|
+
|
|
2321
|
+
- ``prec`` -- precision
|
|
2322
|
+
|
|
2323
|
+
- ``algorithm`` -- string or ``None`` (default: ``None``);
|
|
2324
|
+
a choice of algorithm among ``'pari'``, ``'fast'``, ``'quadratic'``
|
|
2325
|
+
or ``None`` to let this function determine the best algorithm to use
|
|
2326
|
+
|
|
2327
|
+
OUTPUT:
|
|
2328
|
+
|
|
2329
|
+
A Laurent series in one variable `z` with coefficients in the
|
|
2330
|
+
base field `k` of `E`.
|
|
2331
|
+
|
|
2332
|
+
EXAMPLES::
|
|
2333
|
+
|
|
2334
|
+
sage: # needs database_cremona_mini_ellcurve
|
|
2335
|
+
sage: E = EllipticCurve('11a1')
|
|
2336
|
+
sage: E.weierstrass_p(prec=10)
|
|
2337
|
+
z^-2 + 31/15*z^2 + 2501/756*z^4 + 961/675*z^6 + 77531/41580*z^8 + O(z^10)
|
|
2338
|
+
sage: E.weierstrass_p(prec=8)
|
|
2339
|
+
z^-2 + 31/15*z^2 + 2501/756*z^4 + 961/675*z^6 + O(z^8)
|
|
2340
|
+
sage: Esh = E.short_weierstrass_model()
|
|
2341
|
+
sage: Esh.weierstrass_p(prec=8)
|
|
2342
|
+
z^-2 + 13392/5*z^2 + 1080432/7*z^4 + 59781888/25*z^6 + O(z^8)
|
|
2343
|
+
sage: E.weierstrass_p(prec=20, algorithm='fast')
|
|
2344
|
+
z^-2 + 31/15*z^2 + 2501/756*z^4 + 961/675*z^6 + 77531/41580*z^8
|
|
2345
|
+
+ 1202285717/928746000*z^10 + 2403461/2806650*z^12 + 30211462703/43418875500*z^14
|
|
2346
|
+
+ 3539374016033/7723451736000*z^16 + 413306031683977/1289540602350000*z^18 + O(z^20)
|
|
2347
|
+
sage: E.weierstrass_p(prec=20, algorithm='pari')
|
|
2348
|
+
z^-2 + 31/15*z^2 + 2501/756*z^4 + 961/675*z^6 + 77531/41580*z^8
|
|
2349
|
+
+ 1202285717/928746000*z^10 + 2403461/2806650*z^12 + 30211462703/43418875500*z^14
|
|
2350
|
+
+ 3539374016033/7723451736000*z^16 + 413306031683977/1289540602350000*z^18 + O(z^20)
|
|
2351
|
+
sage: E.weierstrass_p(prec=20, algorithm='quadratic')
|
|
2352
|
+
z^-2 + 31/15*z^2 + 2501/756*z^4 + 961/675*z^6 + 77531/41580*z^8
|
|
2353
|
+
+ 1202285717/928746000*z^10 + 2403461/2806650*z^12 + 30211462703/43418875500*z^14
|
|
2354
|
+
+ 3539374016033/7723451736000*z^16 + 413306031683977/1289540602350000*z^18 + O(z^20)
|
|
2355
|
+
"""
|
|
2356
|
+
from .ell_wp import weierstrass_p
|
|
2357
|
+
return weierstrass_p(self, prec=prec, algorithm=algorithm)
|
|
2358
|
+
|
|
2359
|
+
def hasse_invariant(self):
|
|
2360
|
+
r"""
|
|
2361
|
+
Return the Hasse invariant of this elliptic curve.
|
|
2362
|
+
|
|
2363
|
+
OUTPUT:
|
|
2364
|
+
|
|
2365
|
+
The Hasse invariant of this elliptic curve, as an element of
|
|
2366
|
+
the base field. This is only defined over fields of positive
|
|
2367
|
+
characteristic, and is an element of the field which is zero
|
|
2368
|
+
if and only if the curve is supersingular. Over a field of
|
|
2369
|
+
characteristic zero, where the Hasse invariant is undefined,
|
|
2370
|
+
a :exc:`ValueError` is raised.
|
|
2371
|
+
|
|
2372
|
+
EXAMPLES::
|
|
2373
|
+
|
|
2374
|
+
sage: E = EllipticCurve([Mod(1,2), Mod(1,2), 0, 0, Mod(1,2)])
|
|
2375
|
+
sage: E.hasse_invariant()
|
|
2376
|
+
1
|
|
2377
|
+
sage: E = EllipticCurve([0, 0, Mod(1,3), Mod(1,3), Mod(1,3)])
|
|
2378
|
+
sage: E.hasse_invariant()
|
|
2379
|
+
0
|
|
2380
|
+
sage: E = EllipticCurve([0, 0, Mod(1,5), 0, Mod(2,5)])
|
|
2381
|
+
sage: E.hasse_invariant()
|
|
2382
|
+
0
|
|
2383
|
+
sage: E = EllipticCurve([0, 0, Mod(1,5), Mod(1,5), Mod(2,5)])
|
|
2384
|
+
sage: E.hasse_invariant()
|
|
2385
|
+
2
|
|
2386
|
+
|
|
2387
|
+
Some examples over larger fields::
|
|
2388
|
+
|
|
2389
|
+
sage: # needs sage.rings.finite_rings
|
|
2390
|
+
sage: EllipticCurve(GF(101), [0,0,0,0,1]).hasse_invariant()
|
|
2391
|
+
0
|
|
2392
|
+
sage: EllipticCurve(GF(101), [0,0,0,1,1]).hasse_invariant()
|
|
2393
|
+
98
|
|
2394
|
+
sage: EllipticCurve(GF(103), [0,0,0,0,1]).hasse_invariant()
|
|
2395
|
+
20
|
|
2396
|
+
sage: EllipticCurve(GF(103), [0,0,0,1,1]).hasse_invariant()
|
|
2397
|
+
17
|
|
2398
|
+
sage: F.<a> = GF(107^2)
|
|
2399
|
+
sage: EllipticCurve(F, [0,0,0,a,1]).hasse_invariant()
|
|
2400
|
+
62*a + 75
|
|
2401
|
+
sage: EllipticCurve(F, [0,0,0,0,a]).hasse_invariant()
|
|
2402
|
+
0
|
|
2403
|
+
|
|
2404
|
+
Over fields of characteristic zero, the Hasse invariant is
|
|
2405
|
+
undefined::
|
|
2406
|
+
|
|
2407
|
+
sage: E = EllipticCurve([0,0,0,0,1])
|
|
2408
|
+
sage: E.hasse_invariant()
|
|
2409
|
+
Traceback (most recent call last):
|
|
2410
|
+
...
|
|
2411
|
+
ValueError: Hasse invariant only defined in positive characteristic
|
|
2412
|
+
"""
|
|
2413
|
+
k = self.base_field()
|
|
2414
|
+
p = k.characteristic()
|
|
2415
|
+
if p == 0:
|
|
2416
|
+
raise ValueError('Hasse invariant only defined in positive characteristic')
|
|
2417
|
+
elif p == 2:
|
|
2418
|
+
return self.a1()
|
|
2419
|
+
elif p == 3:
|
|
2420
|
+
return self.b2()
|
|
2421
|
+
elif p == 5:
|
|
2422
|
+
return self.c4()
|
|
2423
|
+
elif p == 7:
|
|
2424
|
+
return -self.c6()
|
|
2425
|
+
else:
|
|
2426
|
+
R = k['x']
|
|
2427
|
+
x = R.gen()
|
|
2428
|
+
E = self.short_weierstrass_model()
|
|
2429
|
+
f = (x**3+E.a4()*x+E.a6())**((p-1)//2)
|
|
2430
|
+
return f.coefficients(sparse=False)[p-1]
|
|
2431
|
+
|
|
2432
|
+
def isogeny_ell_graph(self, l, directed=True, label_by_j=False):
|
|
2433
|
+
"""
|
|
2434
|
+
Return a graph representing the ``l``-degree ``K``-isogenies between
|
|
2435
|
+
``K``-isomorphism classes of elliptic curves for ``K =
|
|
2436
|
+
self.base_field()``.
|
|
2437
|
+
|
|
2438
|
+
INPUT:
|
|
2439
|
+
|
|
2440
|
+
- ``l`` -- prime degree of isogenies
|
|
2441
|
+
|
|
2442
|
+
- ``directed`` -- boolean (default: ``True``); whether to return a
|
|
2443
|
+
directed or undirected graph. In the undirected case, the in-degrees
|
|
2444
|
+
and out-degrees of the vertices must be balanced and therefore the
|
|
2445
|
+
number of out-edges from the vertices corresponding to j-invariants 0
|
|
2446
|
+
and 1728 (if they are part of the graph) are reduced to match the
|
|
2447
|
+
number of in-edges.
|
|
2448
|
+
|
|
2449
|
+
- ``label_by_j`` -- boolean (default: ``False``); whether to label
|
|
2450
|
+
graph vertices by the j-invariant corresponding to the isomorphism
|
|
2451
|
+
class of curves. If the j-invariant is not unique in the isogeny
|
|
2452
|
+
class, append ``*`` to it to indicate a twist. Otherwise, if
|
|
2453
|
+
``False`` label vertices by the equation of a representative curve.
|
|
2454
|
+
|
|
2455
|
+
OUTPUT: a :class:`Graph` or :class:`DiGraph`
|
|
2456
|
+
|
|
2457
|
+
EXAMPLES:
|
|
2458
|
+
|
|
2459
|
+
Ordinary curve over finite extension field of degree 2::
|
|
2460
|
+
|
|
2461
|
+
sage: # needs sage.graphs sage.rings.finite_rings
|
|
2462
|
+
sage: x = polygen(ZZ, 'x')
|
|
2463
|
+
sage: E = EllipticCurve(GF(59^2, "i", x^2 + 1), j=5)
|
|
2464
|
+
sage: G = E.isogeny_ell_graph(5, directed=False, label_by_j=True); G
|
|
2465
|
+
Graph on 20 vertices
|
|
2466
|
+
sage: G.vertices(sort=True)
|
|
2467
|
+
['1',
|
|
2468
|
+
'12',
|
|
2469
|
+
...
|
|
2470
|
+
'i + 55']
|
|
2471
|
+
sage: G.edges(sort=True)
|
|
2472
|
+
[('1', '28*i + 11', None),
|
|
2473
|
+
('1', '31*i + 11', None),
|
|
2474
|
+
...
|
|
2475
|
+
('8', 'i + 1', None)]
|
|
2476
|
+
|
|
2477
|
+
Supersingular curve over prime field::
|
|
2478
|
+
|
|
2479
|
+
sage: # needs sage.graphs sage.rings.finite_rings
|
|
2480
|
+
sage: E = EllipticCurve(GF(419), j=1728)
|
|
2481
|
+
sage: G3 = E.isogeny_ell_graph(3, directed=False, label_by_j=True); G3
|
|
2482
|
+
Graph on 27 vertices
|
|
2483
|
+
sage: G3.vertices(sort=True)
|
|
2484
|
+
['0',
|
|
2485
|
+
'0*',
|
|
2486
|
+
...
|
|
2487
|
+
'98*']
|
|
2488
|
+
sage: G3.edges(sort=True)
|
|
2489
|
+
[('0', '0*', None),
|
|
2490
|
+
('0', '13', None),
|
|
2491
|
+
...
|
|
2492
|
+
('48*', '98*', None)]
|
|
2493
|
+
sage: G5 = E.isogeny_ell_graph(5, directed=False, label_by_j=True); G5
|
|
2494
|
+
Graph on 9 vertices
|
|
2495
|
+
sage: G5.vertices(sort=True)
|
|
2496
|
+
['13', '13*', '407', '407*', '52', '62', '62*', '98', '98*']
|
|
2497
|
+
sage: G5.edges(sort=True)
|
|
2498
|
+
[('13', '52', None),
|
|
2499
|
+
('13', '98', None),
|
|
2500
|
+
...
|
|
2501
|
+
('62*', '98*', None)]
|
|
2502
|
+
|
|
2503
|
+
Supersingular curve over finite extension field of degree 2::
|
|
2504
|
+
|
|
2505
|
+
sage: # needs sage.graphs sage.rings.finite_rings
|
|
2506
|
+
sage: K = GF(431^2, "i", x^2 + 1)
|
|
2507
|
+
sage: E = EllipticCurve(K, j=0)
|
|
2508
|
+
sage: E.is_supersingular()
|
|
2509
|
+
True
|
|
2510
|
+
sage: G = E.isogeny_ell_graph(2, directed=True, label_by_j=True); G
|
|
2511
|
+
Looped multi-digraph on 37 vertices
|
|
2512
|
+
sage: G.vertices(sort=True)
|
|
2513
|
+
['0',
|
|
2514
|
+
'102',
|
|
2515
|
+
...
|
|
2516
|
+
'87*i + 190']
|
|
2517
|
+
sage: G.edges(sort=True)
|
|
2518
|
+
[('0', '125', None),
|
|
2519
|
+
('0', '125', None),
|
|
2520
|
+
...
|
|
2521
|
+
'81*i + 65', None)]
|
|
2522
|
+
sage: H = E.isogeny_ell_graph(2, directed=False, label_by_j=True); H
|
|
2523
|
+
Looped multi-graph on 37 vertices
|
|
2524
|
+
sage: H.vertices(sort=True)
|
|
2525
|
+
['0',
|
|
2526
|
+
'102',
|
|
2527
|
+
...
|
|
2528
|
+
'87*i + 190']
|
|
2529
|
+
sage: H.edges(sort=True)
|
|
2530
|
+
[('0', '125', None),
|
|
2531
|
+
('102', '125', None),
|
|
2532
|
+
...
|
|
2533
|
+
('81*i + 65', '87*i + 190', None)]
|
|
2534
|
+
|
|
2535
|
+
Curve over a quadratic number field::
|
|
2536
|
+
|
|
2537
|
+
sage: # needs sage.graphs sage.rings.finite_rings sage.rings.number_field
|
|
2538
|
+
sage: K.<e> = NumberField(x^2 - 2)
|
|
2539
|
+
sage: E = EllipticCurve(K, [1, 0, 1, 4, -6])
|
|
2540
|
+
sage: G2 = E.isogeny_ell_graph(2, directed=False)
|
|
2541
|
+
sage: G2.vertices(sort=True)
|
|
2542
|
+
['y^2 + x*y + y = x^3 + (-130*e-356)*x + (-2000*e-2038)',
|
|
2543
|
+
'y^2 + x*y + y = x^3 + (-36)*x + (-70)',
|
|
2544
|
+
'y^2 + x*y + y = x^3 + (130*e-356)*x + (2000*e-2038)',
|
|
2545
|
+
'y^2 + x*y + y = x^3 + 4*x + (-6)']
|
|
2546
|
+
sage: G2.edges(sort=True)
|
|
2547
|
+
[('y^2 + x*y + y = x^3 + (-130*e-356)*x + (-2000*e-2038)',
|
|
2548
|
+
'y^2 + x*y + y = x^3 + (-36)*x + (-70)', None),
|
|
2549
|
+
('y^2 + x*y + y = x^3 + (-36)*x + (-70)',
|
|
2550
|
+
'y^2 + x*y + y = x^3 + (130*e-356)*x + (2000*e-2038)', None),
|
|
2551
|
+
('y^2 + x*y + y = x^3 + (-36)*x + (-70)',
|
|
2552
|
+
'y^2 + x*y + y = x^3 + 4*x + (-6)', None)]
|
|
2553
|
+
sage: G3 = E.isogeny_ell_graph(3, directed=False)
|
|
2554
|
+
sage: G3.vertices(sort=True)
|
|
2555
|
+
['y^2 + x*y + y = x^3 + (-1)*x',
|
|
2556
|
+
'y^2 + x*y + y = x^3 + (-171)*x + (-874)',
|
|
2557
|
+
'y^2 + x*y + y = x^3 + 4*x + (-6)']
|
|
2558
|
+
sage: G3.edges(sort=True)
|
|
2559
|
+
[('y^2 + x*y + y = x^3 + (-1)*x',
|
|
2560
|
+
'y^2 + x*y + y = x^3 + 4*x + (-6)', None),
|
|
2561
|
+
('y^2 + x*y + y = x^3 + (-171)*x + (-874)',
|
|
2562
|
+
'y^2 + x*y + y = x^3 + 4*x + (-6)', None)]
|
|
2563
|
+
|
|
2564
|
+
TESTS::
|
|
2565
|
+
|
|
2566
|
+
sage: # needs sage.graphs
|
|
2567
|
+
sage: E = EllipticCurve(GF(11), j=0)
|
|
2568
|
+
sage: G0 = E.isogeny_ell_graph(2, directed=False)
|
|
2569
|
+
sage: G0.is_directed()
|
|
2570
|
+
False
|
|
2571
|
+
sage: G1 = E.isogeny_ell_graph(2, directed=True)
|
|
2572
|
+
sage: G1.is_directed()
|
|
2573
|
+
True
|
|
2574
|
+
sage: G2 = E.isogeny_ell_graph(2, label_by_j=False)
|
|
2575
|
+
sage: G2.vertices(sort=True)
|
|
2576
|
+
['y^2 = x^3 + 1',
|
|
2577
|
+
'y^2 = x^3 + 2',
|
|
2578
|
+
'y^2 = x^3 + 5*x',
|
|
2579
|
+
'y^2 = x^3 + 7*x']
|
|
2580
|
+
sage: G3 = E.isogeny_ell_graph(2, label_by_j=True)
|
|
2581
|
+
sage: G3.vertices(sort=True)
|
|
2582
|
+
['0', '0*', '1', '1*']
|
|
2583
|
+
"""
|
|
2584
|
+
from warnings import warn
|
|
2585
|
+
from sage.matrix.constructor import Matrix
|
|
2586
|
+
|
|
2587
|
+
# warn users if things are getting big
|
|
2588
|
+
if l == 2:
|
|
2589
|
+
curve_max = 1000
|
|
2590
|
+
if l == 3:
|
|
2591
|
+
curve_max = 700
|
|
2592
|
+
elif l < 20:
|
|
2593
|
+
curve_max = 200
|
|
2594
|
+
else:
|
|
2595
|
+
curve_max = 50
|
|
2596
|
+
|
|
2597
|
+
Es = [self] # list of curves in graph
|
|
2598
|
+
A = [] # adjacency matrix
|
|
2599
|
+
labels = [] # list of vertex labels
|
|
2600
|
+
for i, E in enumerate(Es):
|
|
2601
|
+
if 0 < curve_max < len(Es):
|
|
2602
|
+
warn('Isogeny graph contains more than '
|
|
2603
|
+
+ str(curve_max) + ' curves.')
|
|
2604
|
+
curve_max = 0
|
|
2605
|
+
|
|
2606
|
+
r = [0] * len(Es) # adjacency matrix row
|
|
2607
|
+
for C in [I.codomain() for I in E.isogenies_prime_degree(l)]:
|
|
2608
|
+
j = next((k for k, F in enumerate(Es) if C.is_isomorphic(F)),
|
|
2609
|
+
-1) # index of curve isomorphic to codomain of isogeny
|
|
2610
|
+
if j >= 0:
|
|
2611
|
+
r[j] += 1
|
|
2612
|
+
else:
|
|
2613
|
+
Es.append(C)
|
|
2614
|
+
r.append(1)
|
|
2615
|
+
|
|
2616
|
+
# If the graph is undirected, non-symmetric values in the adjacency
|
|
2617
|
+
# matrix will result in Sage outputting different graphs depending
|
|
2618
|
+
# on the vertex ordering. Therefore, scale down the non-loop
|
|
2619
|
+
# out-edges of vertices corresponding to j-invariants 0 and 1728 so
|
|
2620
|
+
# that the same isogeny graphs output are isomorphic as graphs
|
|
2621
|
+
# regardless of the starting vertex.
|
|
2622
|
+
if not directed and E.j_invariant() in [0, 1728]:
|
|
2623
|
+
m = len(E.automorphisms()) / 2 # multiplicity of out-edges
|
|
2624
|
+
r = [v if k == i else v / m for k, v in enumerate(r)]
|
|
2625
|
+
|
|
2626
|
+
A.append(r)
|
|
2627
|
+
if label_by_j:
|
|
2628
|
+
s = str(E.j_invariant())
|
|
2629
|
+
while s in labels:
|
|
2630
|
+
s += "*"
|
|
2631
|
+
labels.append(s)
|
|
2632
|
+
else:
|
|
2633
|
+
labels.append(E._equation_string())
|
|
2634
|
+
|
|
2635
|
+
A = Matrix([r + [0] * (len(A) - len(r)) for r in A])
|
|
2636
|
+
if directed:
|
|
2637
|
+
from sage.graphs.digraph import DiGraph as GraphType
|
|
2638
|
+
else:
|
|
2639
|
+
from sage.graphs.graph import Graph as GraphType
|
|
2640
|
+
|
|
2641
|
+
G = GraphType(A, format='adjacency_matrix',
|
|
2642
|
+
data_structure='static_sparse')
|
|
2643
|
+
# inplace relabelling is necessary for static_sparse graphs
|
|
2644
|
+
GL = G.relabel(labels, inplace=False)
|
|
2645
|
+
return GL
|
|
2646
|
+
|
|
2647
|
+
def endomorphism_ring_is_commutative(self) -> bool:
|
|
2648
|
+
r"""
|
|
2649
|
+
Check whether the endomorphism ring of this elliptic curve
|
|
2650
|
+
*over its base field* is commutative.
|
|
2651
|
+
|
|
2652
|
+
ALGORITHM: The endomorphism ring is always commutative in
|
|
2653
|
+
characteristic zero. Over finite fields, it is commutative
|
|
2654
|
+
if and only if the Frobenius endomorphism is not in `\ZZ`.
|
|
2655
|
+
All elliptic curves with non-commutative endomorphism ring
|
|
2656
|
+
are supersingular. (The converse holds over the algebraic
|
|
2657
|
+
closure, but here we consider endomorphisms *over the field
|
|
2658
|
+
of definition*.)
|
|
2659
|
+
|
|
2660
|
+
EXAMPLES::
|
|
2661
|
+
|
|
2662
|
+
sage: EllipticCurve(QQ, [1,1]).endomorphism_ring_is_commutative()
|
|
2663
|
+
True
|
|
2664
|
+
sage: EllipticCurve(QQ, [1,0]).endomorphism_ring_is_commutative()
|
|
2665
|
+
True
|
|
2666
|
+
sage: EllipticCurve(GF(19), [1,1]).endomorphism_ring_is_commutative()
|
|
2667
|
+
True
|
|
2668
|
+
sage: EllipticCurve(GF(19^2), [1,1]).endomorphism_ring_is_commutative()
|
|
2669
|
+
True
|
|
2670
|
+
sage: EllipticCurve(GF(19), [1,0]).endomorphism_ring_is_commutative()
|
|
2671
|
+
True
|
|
2672
|
+
sage: EllipticCurve(GF(19^2), [1,0]).endomorphism_ring_is_commutative()
|
|
2673
|
+
False
|
|
2674
|
+
sage: EllipticCurve(GF(19^3), [1,0]).endomorphism_ring_is_commutative()
|
|
2675
|
+
True
|
|
2676
|
+
"""
|
|
2677
|
+
k = self.base()
|
|
2678
|
+
if k.characteristic() == 0 or self.is_ordinary():
|
|
2679
|
+
return True
|
|
2680
|
+
|
|
2681
|
+
if not k.is_finite():
|
|
2682
|
+
raise NotImplementedError
|
|
2683
|
+
|
|
2684
|
+
return self.frobenius() not in ZZ
|
|
2685
|
+
|
|
2686
|
+
|
|
2687
|
+
def compute_model(E, name):
|
|
2688
|
+
r"""
|
|
2689
|
+
Return a model of an elliptic curve ``E`` of the type specified
|
|
2690
|
+
in the ``name`` parameter.
|
|
2691
|
+
|
|
2692
|
+
Used as a helper function in
|
|
2693
|
+
:class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny`.
|
|
2694
|
+
|
|
2695
|
+
INPUT:
|
|
2696
|
+
|
|
2697
|
+
- ``E`` -- elliptic curve
|
|
2698
|
+
|
|
2699
|
+
- ``name`` -- string; current options:
|
|
2700
|
+
|
|
2701
|
+
- ``'minimal'``: Return a global minimal model of ``E`` if it
|
|
2702
|
+
exists, and a semi-global minimal model otherwise.
|
|
2703
|
+
For this choice, ``E`` must be defined over a number field.
|
|
2704
|
+
See :meth:`~sage.schemes.elliptic_curves.ell_number_field.EllipticCurve_number_field.global_minimal_model`.
|
|
2705
|
+
|
|
2706
|
+
- ``'short_weierstrass'``: Return a short Weierstrass model of ``E``
|
|
2707
|
+
assuming one exists.
|
|
2708
|
+
See :meth:`~sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic.short_weierstrass_model`.
|
|
2709
|
+
|
|
2710
|
+
- ``'montgomery'``: Return an (untwisted) Montgomery model of ``E``
|
|
2711
|
+
assuming one exists over this field.
|
|
2712
|
+
See :meth:`~sage.schemes.elliptic_curves.ell_generic.EllipticCurve_generic.montgomery_model`.
|
|
2713
|
+
|
|
2714
|
+
OUTPUT: an elliptic curve of the specified type isomorphic to `E`
|
|
2715
|
+
|
|
2716
|
+
EXAMPLES::
|
|
2717
|
+
|
|
2718
|
+
sage: from sage.schemes.elliptic_curves.ell_field import compute_model
|
|
2719
|
+
sage: E = EllipticCurve([12/7, 405/49, 0, -81/8, 135/64])
|
|
2720
|
+
sage: compute_model(E, 'minimal')
|
|
2721
|
+
Elliptic Curve defined by y^2 = x^3 - x^2 - 7*x + 10 over Rational Field
|
|
2722
|
+
sage: compute_model(E, 'short_weierstrass')
|
|
2723
|
+
Elliptic Curve defined by y^2 = x^3 - 48114*x + 4035015 over Rational Field
|
|
2724
|
+
sage: compute_model(E, 'montgomery')
|
|
2725
|
+
Elliptic Curve defined by y^2 = x^3 + 5*x^2 + x over Rational Field
|
|
2726
|
+
"""
|
|
2727
|
+
if not isinstance(E, ell_generic.EllipticCurve_generic):
|
|
2728
|
+
raise TypeError('not an elliptic curve')
|
|
2729
|
+
|
|
2730
|
+
if name == 'minimal':
|
|
2731
|
+
from sage.rings.number_field.number_field_base import NumberField
|
|
2732
|
+
if not isinstance(E.base_field(), NumberField):
|
|
2733
|
+
raise ValueError('can only compute minimal model for curves over number fields')
|
|
2734
|
+
return E.global_minimal_model(semi_global=True)
|
|
2735
|
+
|
|
2736
|
+
if name == 'short_weierstrass':
|
|
2737
|
+
return E.short_weierstrass_model()
|
|
2738
|
+
|
|
2739
|
+
if name == 'montgomery':
|
|
2740
|
+
return E.montgomery_model()
|
|
2741
|
+
|
|
2742
|
+
raise NotImplementedError(f'cannot compute {name} model')
|
|
2743
|
+
|
|
2744
|
+
|
|
2745
|
+
def point_of_order(E, n):
|
|
2746
|
+
r"""
|
|
2747
|
+
Given an elliptic curve `E` over a finite field or a number field
|
|
2748
|
+
and an integer `n \geq 1`, construct a point of order `n` on `E`,
|
|
2749
|
+
possibly defined over an extension of the base field of `E`.
|
|
2750
|
+
|
|
2751
|
+
Currently only prime powers `n` are supported.
|
|
2752
|
+
|
|
2753
|
+
EXAMPLES::
|
|
2754
|
+
|
|
2755
|
+
sage: from sage.schemes.elliptic_curves.ell_field import point_of_order
|
|
2756
|
+
sage: E = EllipticCurve(GF(101), [1,2,3,4,5])
|
|
2757
|
+
sage: P = point_of_order(E, 5); P # random
|
|
2758
|
+
(50*Y^5 + 48*Y^4 + 26*Y^3 + 37*Y^2 + 48*Y + 15 : 25*Y^5 + 31*Y^4 + 79*Y^3 + 39*Y^2 + 3*Y + 20 : 1)
|
|
2759
|
+
sage: P.base_ring()
|
|
2760
|
+
Finite Field in Y of size 101^6
|
|
2761
|
+
sage: P.order()
|
|
2762
|
+
5
|
|
2763
|
+
sage: P.curve().a_invariants()
|
|
2764
|
+
(1, 2, 3, 4, 5)
|
|
2765
|
+
|
|
2766
|
+
::
|
|
2767
|
+
|
|
2768
|
+
sage: Q = point_of_order(E, 8); Q # random
|
|
2769
|
+
(69*x^5 + 24*x^4 + 100*x^3 + 65*x^2 + 88*x + 97 : 65*x^5 + 28*x^4 + 5*x^3 + 45*x^2 + 42*x + 18 : 1)
|
|
2770
|
+
sage: 8*Q == 0 and 4*Q != 0
|
|
2771
|
+
True
|
|
2772
|
+
|
|
2773
|
+
::
|
|
2774
|
+
|
|
2775
|
+
sage: from sage.schemes.elliptic_curves.ell_field import point_of_order
|
|
2776
|
+
sage: E = EllipticCurve(QQ, [7,7])
|
|
2777
|
+
sage: P = point_of_order(E, 3); P # random
|
|
2778
|
+
(x : -Y : 1)
|
|
2779
|
+
sage: P.base_ring()
|
|
2780
|
+
Number Field in Y with defining polynomial Y^2 - x^3 - 7*x - 7 over its base field
|
|
2781
|
+
sage: P.base_ring().base_field()
|
|
2782
|
+
Number Field in x with defining polynomial x^4 + 14*x^2 + 28*x - 49/3
|
|
2783
|
+
sage: P.order()
|
|
2784
|
+
3
|
|
2785
|
+
sage: P.curve().a_invariants()
|
|
2786
|
+
(0, 0, 0, 7, 7)
|
|
2787
|
+
|
|
2788
|
+
::
|
|
2789
|
+
|
|
2790
|
+
sage: Q = point_of_order(E, 4); Q # random
|
|
2791
|
+
(x : Y : 1)
|
|
2792
|
+
sage: Q.base_ring()
|
|
2793
|
+
Number Field in Y with defining polynomial Y^2 - x^3 - 7*x - 7 over its base field
|
|
2794
|
+
sage: Q.base_ring().base_field()
|
|
2795
|
+
Number Field in x with defining polynomial x^6 + 35*x^4 + 140*x^3 - 245*x^2 - 196*x - 735
|
|
2796
|
+
sage: Q.order()
|
|
2797
|
+
4
|
|
2798
|
+
"""
|
|
2799
|
+
# Construct the field extension defined by the given polynomial,
|
|
2800
|
+
# in such a way that the result is recognized by Sage as a field.
|
|
2801
|
+
def ffext(poly):
|
|
2802
|
+
rng = poly.parent()
|
|
2803
|
+
fld = rng.base_ring()
|
|
2804
|
+
if fld in FiniteFields():
|
|
2805
|
+
# Workaround: .extension() would return a PolynomialQuotientRing
|
|
2806
|
+
# rather than another FiniteField.
|
|
2807
|
+
return poly.splitting_field(rng.variable_name())
|
|
2808
|
+
return fld.extension(poly, rng.variable_name())
|
|
2809
|
+
|
|
2810
|
+
n = ZZ(n)
|
|
2811
|
+
if n == 1:
|
|
2812
|
+
return E(0)
|
|
2813
|
+
|
|
2814
|
+
l, m = n.is_prime_power(get_data=True)
|
|
2815
|
+
if not m:
|
|
2816
|
+
raise NotImplementedError('only prime-power orders are currently supported')
|
|
2817
|
+
|
|
2818
|
+
xpoly = E.division_polynomial(n).radical()
|
|
2819
|
+
xpoly //= E.division_polynomial(n // l).radical()
|
|
2820
|
+
if xpoly.degree() < 1: # supersingular and l == p
|
|
2821
|
+
raise ValueError('curve does not have any points of the specified order')
|
|
2822
|
+
|
|
2823
|
+
mu = xpoly.factor()[0][0]
|
|
2824
|
+
FF = ffext(mu)
|
|
2825
|
+
xx = mu.any_root(ring=FF, assume_squarefree=True)
|
|
2826
|
+
|
|
2827
|
+
Y = polygen(FF, 'Y')
|
|
2828
|
+
ypoly = E.defining_polynomial()(xx, Y, 1)
|
|
2829
|
+
if ypoly.is_irreducible():
|
|
2830
|
+
FF = ffext(ypoly)
|
|
2831
|
+
xx = FF(xx)
|
|
2832
|
+
|
|
2833
|
+
EE = E.change_ring(FF)
|
|
2834
|
+
pt = EE.lift_x(xx)
|
|
2835
|
+
pt.set_order(n, check=False)
|
|
2836
|
+
return pt
|