passagemath-schemes 10.6.40__cp314-cp314-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.22.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.40.dist-info/METADATA +204 -0
- passagemath_schemes-10.6.40.dist-info/METADATA.bak +205 -0
- passagemath_schemes-10.6.40.dist-info/RECORD +314 -0
- passagemath_schemes-10.6.40.dist-info/WHEEL +6 -0
- passagemath_schemes-10.6.40.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-314-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-314-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-314-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-314-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-314-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-314-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-314-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-314-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-314-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-314-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-314-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-314-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,1406 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
"""
|
|
3
|
+
Elliptic-curve morphisms
|
|
4
|
+
|
|
5
|
+
This class serves as a common parent for various specializations of
|
|
6
|
+
morphisms between elliptic curves, with the aim of providing a common
|
|
7
|
+
interface regardless of implementation details.
|
|
8
|
+
|
|
9
|
+
Current implementations of elliptic-curve morphisms (child classes):
|
|
10
|
+
|
|
11
|
+
- :class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny`
|
|
12
|
+
- :class:`~sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism`
|
|
13
|
+
- :class:`~sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite`
|
|
14
|
+
- :class:`~sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_sum`
|
|
15
|
+
- :class:`~sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar`
|
|
16
|
+
- :class:`~sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius`
|
|
17
|
+
- :class:`~sage.schemes.elliptic_curves.hom_velusqrt.EllipticCurveHom_velusqrt`
|
|
18
|
+
|
|
19
|
+
AUTHORS:
|
|
20
|
+
|
|
21
|
+
- See authors of :class:`EllipticCurveIsogeny`. Some of the code
|
|
22
|
+
in this class was lifted from there.
|
|
23
|
+
|
|
24
|
+
- Lorenz Panny (2021): Refactor isogenies and isomorphisms into
|
|
25
|
+
the common :class:`EllipticCurveHom` interface.
|
|
26
|
+
|
|
27
|
+
- Lorenz Panny (2022): :meth:`~EllipticCurveHom.matrix_on_subgroup`
|
|
28
|
+
|
|
29
|
+
- Lorenz Panny (2023): :meth:`~EllipticCurveHom.trace`, :meth:`~EllipticCurveHom.characteristic_polynomial`
|
|
30
|
+
"""
|
|
31
|
+
from sage.misc.cachefunc import cached_method
|
|
32
|
+
from sage.structure.richcmp import richcmp_not_equal, richcmp, op_EQ, op_NE
|
|
33
|
+
|
|
34
|
+
from sage.categories.morphism import Morphism
|
|
35
|
+
|
|
36
|
+
from sage.arith.misc import integer_floor
|
|
37
|
+
|
|
38
|
+
from sage.rings.integer_ring import ZZ
|
|
39
|
+
from sage.rings.finite_rings import finite_field_base
|
|
40
|
+
from sage.rings.number_field import number_field_base
|
|
41
|
+
|
|
42
|
+
import sage.schemes.elliptic_curves.weierstrass_morphism as wm
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class EllipticCurveHom(Morphism):
|
|
46
|
+
"""
|
|
47
|
+
Base class for elliptic-curve morphisms.
|
|
48
|
+
"""
|
|
49
|
+
def __init__(self, *args, **kwds):
|
|
50
|
+
r"""
|
|
51
|
+
Constructor for elliptic-curve morphisms.
|
|
52
|
+
|
|
53
|
+
EXAMPLES::
|
|
54
|
+
|
|
55
|
+
sage: E = EllipticCurve(GF(257^2), [5,5])
|
|
56
|
+
sage: P = E.lift_x(1)
|
|
57
|
+
sage: E.isogeny(P) # indirect doctest
|
|
58
|
+
Isogeny of degree 127 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field in z2 of size 257^2 to Elliptic Curve defined by y^2 = x^3 + 151*x + 22 over Finite Field in z2 of size 257^2
|
|
59
|
+
sage: E.isogeny(P, algorithm='factored') # indirect doctest
|
|
60
|
+
Composite morphism of degree 127:
|
|
61
|
+
From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field in z2 of size 257^2
|
|
62
|
+
To: Elliptic Curve defined by y^2 = x^3 + 151*x + 22 over Finite Field in z2 of size 257^2
|
|
63
|
+
sage: E.isogeny(P, algorithm='velusqrt') # indirect doctest
|
|
64
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 127:
|
|
65
|
+
From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field in z2 of size 257^2
|
|
66
|
+
To: Elliptic Curve defined by y^2 = x^3 + 119*x + 231 over Finite Field in z2 of size 257^2
|
|
67
|
+
sage: E.montgomery_model(morphism=True) # indirect doctest
|
|
68
|
+
(Elliptic Curve defined by y^2 = x^3 + (199*z2+73)*x^2 + x over Finite Field in z2 of size 257^2,
|
|
69
|
+
Elliptic-curve morphism:
|
|
70
|
+
From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field in z2 of size 257^2
|
|
71
|
+
To: Elliptic Curve defined by y^2 = x^3 + (199*z2+73)*x^2 + x over Finite Field in z2 of size 257^2
|
|
72
|
+
Via: (u,r,s,t) = (88*z2 + 253, 208*z2 + 90, 0, 0))
|
|
73
|
+
"""
|
|
74
|
+
super().__init__(*args, **kwds)
|
|
75
|
+
|
|
76
|
+
# Over finite fields, isogenous curves have the same number of
|
|
77
|
+
# rational points, hence we copy over the cached curve orders.
|
|
78
|
+
if isinstance(self.base_ring(), finite_field_base.FiniteField) and self.degree():
|
|
79
|
+
self._codomain._fetch_cached_order(self._domain)
|
|
80
|
+
self._domain._fetch_cached_order(self._codomain)
|
|
81
|
+
|
|
82
|
+
def _repr_type(self):
|
|
83
|
+
r"""
|
|
84
|
+
Return a textual representation of what kind of morphism
|
|
85
|
+
this is. Used by :meth:`Morphism._repr_`.
|
|
86
|
+
|
|
87
|
+
TESTS::
|
|
88
|
+
|
|
89
|
+
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
|
|
90
|
+
sage: EllipticCurveHom._repr_type(None)
|
|
91
|
+
'Elliptic-curve'
|
|
92
|
+
"""
|
|
93
|
+
return 'Elliptic-curve'
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def _composition_impl(left, right):
|
|
97
|
+
r"""
|
|
98
|
+
Called by :meth:`_composition_`.
|
|
99
|
+
|
|
100
|
+
TESTS::
|
|
101
|
+
|
|
102
|
+
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
|
|
103
|
+
sage: EllipticCurveHom._composition_impl(None, None)
|
|
104
|
+
NotImplemented
|
|
105
|
+
"""
|
|
106
|
+
return NotImplemented
|
|
107
|
+
|
|
108
|
+
def _composition_(self, other, homset):
|
|
109
|
+
r"""
|
|
110
|
+
Return the composition of this elliptic-curve morphism
|
|
111
|
+
with another elliptic-curve morphism.
|
|
112
|
+
|
|
113
|
+
EXAMPLES::
|
|
114
|
+
|
|
115
|
+
sage: E = EllipticCurve(GF(19), [1,0])
|
|
116
|
+
sage: phi = E.isogeny(E(0,0))
|
|
117
|
+
sage: iso = E.change_weierstrass_model(5,0,0,0).isomorphism_to(E)
|
|
118
|
+
sage: phi * iso
|
|
119
|
+
Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 9*x over Finite Field of size 19 to Elliptic Curve defined by y^2 = x^3 + 15*x over Finite Field of size 19
|
|
120
|
+
sage: phi.dual() * phi
|
|
121
|
+
Composite morphism of degree 4 = 2^2:
|
|
122
|
+
From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 19
|
|
123
|
+
To: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 19
|
|
124
|
+
"""
|
|
125
|
+
if not isinstance(self, EllipticCurveHom) or not isinstance(other, EllipticCurveHom):
|
|
126
|
+
raise TypeError(f'cannot compose {type(self)} with {type(other)}')
|
|
127
|
+
|
|
128
|
+
ret = self._composition_impl(self, other)
|
|
129
|
+
if ret is not NotImplemented:
|
|
130
|
+
return ret
|
|
131
|
+
|
|
132
|
+
ret = other._composition_impl(self, other)
|
|
133
|
+
if ret is not NotImplemented:
|
|
134
|
+
return ret
|
|
135
|
+
|
|
136
|
+
from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
137
|
+
return EllipticCurveHom_composite.from_factors([other, self])
|
|
138
|
+
|
|
139
|
+
def _add_(self, other):
|
|
140
|
+
r"""
|
|
141
|
+
Add two :class:`EllipticCurveHom` objects by constructing a
|
|
142
|
+
formal :class:`EllipticCurveHom_sum`.
|
|
143
|
+
|
|
144
|
+
EXAMPLES::
|
|
145
|
+
|
|
146
|
+
sage: E = EllipticCurve(GF(101), [5,5])
|
|
147
|
+
sage: phi = E.isogenies_prime_degree(7)[0]
|
|
148
|
+
sage: phi + phi # indirect doctest
|
|
149
|
+
Sum morphism:
|
|
150
|
+
From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101
|
|
151
|
+
To: Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101
|
|
152
|
+
Via: (Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101, Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101)
|
|
153
|
+
"""
|
|
154
|
+
from sage.schemes.elliptic_curves.hom_sum import EllipticCurveHom_sum
|
|
155
|
+
phis = []
|
|
156
|
+
if isinstance(self, EllipticCurveHom_sum):
|
|
157
|
+
phis += self.summands()
|
|
158
|
+
else:
|
|
159
|
+
phis.append(self)
|
|
160
|
+
if isinstance(other, EllipticCurveHom_sum):
|
|
161
|
+
phis += other.summands()
|
|
162
|
+
else:
|
|
163
|
+
phis.append(other)
|
|
164
|
+
|
|
165
|
+
#TODO should probably try to simplify some more?
|
|
166
|
+
|
|
167
|
+
assert other.domain() == self.domain() and other.codomain() == self.codomain()
|
|
168
|
+
return EllipticCurveHom_sum(phis, domain=self.domain(), codomain=self.codomain())
|
|
169
|
+
|
|
170
|
+
def _sub_(self, other):
|
|
171
|
+
r"""
|
|
172
|
+
Subtract two :class:`EllipticCurveHom` objects by negating
|
|
173
|
+
and constructing a formal :class:`EllipticCurveHom_sum`.
|
|
174
|
+
|
|
175
|
+
EXAMPLES::
|
|
176
|
+
|
|
177
|
+
sage: E = EllipticCurve(GF(101), [5,5])
|
|
178
|
+
sage: phi = E.isogenies_prime_degree(7)[0]
|
|
179
|
+
sage: phi - phi # indirect doctest
|
|
180
|
+
Sum morphism:
|
|
181
|
+
From: Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101
|
|
182
|
+
To: Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101
|
|
183
|
+
Via: (Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101, Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 5*x + 5 over Finite Field of size 101 to Elliptic Curve defined by y^2 = x^3 + 12*x + 98 over Finite Field of size 101)
|
|
184
|
+
"""
|
|
185
|
+
return self + (-other)
|
|
186
|
+
|
|
187
|
+
@staticmethod
|
|
188
|
+
def _comparison_impl(left, right, op):
|
|
189
|
+
r"""
|
|
190
|
+
Called by :meth:`_richcmp_`.
|
|
191
|
+
|
|
192
|
+
TESTS::
|
|
193
|
+
|
|
194
|
+
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
|
|
195
|
+
sage: EllipticCurveHom._comparison_impl(None, None, None)
|
|
196
|
+
NotImplemented
|
|
197
|
+
"""
|
|
198
|
+
return NotImplemented
|
|
199
|
+
|
|
200
|
+
def _richcmp_(self, other, op):
|
|
201
|
+
r"""
|
|
202
|
+
Compare :class:`EllipticCurveHom` objects.
|
|
203
|
+
|
|
204
|
+
ALGORITHM:
|
|
205
|
+
|
|
206
|
+
The method first makes sure that domain, codomain and degree match.
|
|
207
|
+
Then, it determines if there is a specialized comparison method by
|
|
208
|
+
trying :meth:`_comparison_impl` on either input. If not, it falls
|
|
209
|
+
back to comparing :meth:`rational_maps`.
|
|
210
|
+
|
|
211
|
+
EXAMPLES::
|
|
212
|
+
|
|
213
|
+
sage: E = EllipticCurve(QQ, [0,0,0,1,0])
|
|
214
|
+
sage: phi_v = EllipticCurveIsogeny(E, E((0,0)))
|
|
215
|
+
sage: phi_k = EllipticCurveIsogeny(E, [0,1])
|
|
216
|
+
sage: phi_k == phi_v
|
|
217
|
+
True
|
|
218
|
+
sage: E_F17 = EllipticCurve(GF(17), [0,0,0,1,0])
|
|
219
|
+
sage: phi_p = EllipticCurveIsogeny(E_F17, [0,1])
|
|
220
|
+
sage: phi_p == phi_v
|
|
221
|
+
False
|
|
222
|
+
sage: E = EllipticCurve('11a1')
|
|
223
|
+
sage: phi = E.isogeny(E(5,5))
|
|
224
|
+
sage: phi == phi
|
|
225
|
+
True
|
|
226
|
+
sage: phi == -phi
|
|
227
|
+
False
|
|
228
|
+
sage: psi = E.isogeny(phi.kernel_polynomial())
|
|
229
|
+
sage: phi == psi
|
|
230
|
+
True
|
|
231
|
+
sage: phi.dual() == psi.dual()
|
|
232
|
+
True
|
|
233
|
+
|
|
234
|
+
::
|
|
235
|
+
|
|
236
|
+
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism, identity_morphism
|
|
237
|
+
sage: E = EllipticCurve([9,9])
|
|
238
|
+
sage: F = E.change_ring(GF(71))
|
|
239
|
+
sage: wE = identity_morphism(E)
|
|
240
|
+
sage: wF = identity_morphism(F)
|
|
241
|
+
sage: mE = E.scalar_multiplication(1)
|
|
242
|
+
sage: mE == wE
|
|
243
|
+
True
|
|
244
|
+
sage: [a == wF for a in (wE,mE)]
|
|
245
|
+
[False, False]
|
|
246
|
+
|
|
247
|
+
.. SEEALSO::
|
|
248
|
+
|
|
249
|
+
- :meth:`_comparison_impl`
|
|
250
|
+
- :func:`compare_via_evaluation`
|
|
251
|
+
"""
|
|
252
|
+
if not isinstance(self, EllipticCurveHom) or not isinstance(other, EllipticCurveHom):
|
|
253
|
+
raise TypeError(f'cannot compare {type(self)} to {type(other)}')
|
|
254
|
+
|
|
255
|
+
if op == op_NE:
|
|
256
|
+
return not self._richcmp_(other, op_EQ)
|
|
257
|
+
|
|
258
|
+
# We first compare domain, codomain, and degree; cf. Issue #11327
|
|
259
|
+
|
|
260
|
+
lx, rx = self.domain(), other.domain()
|
|
261
|
+
if lx != rx:
|
|
262
|
+
return richcmp_not_equal(lx, rx, op)
|
|
263
|
+
|
|
264
|
+
lx, rx = self.codomain(), other.codomain()
|
|
265
|
+
if lx != rx:
|
|
266
|
+
return richcmp_not_equal(lx, rx, op)
|
|
267
|
+
|
|
268
|
+
lx, rx = self.degree(), other.degree()
|
|
269
|
+
if lx != rx:
|
|
270
|
+
return richcmp_not_equal(lx, rx, op)
|
|
271
|
+
|
|
272
|
+
# Check the Weierstraß scaling factor, too (should be fast)
|
|
273
|
+
|
|
274
|
+
if op == op_EQ or op == op_NE:
|
|
275
|
+
lx, rx = self.scaling_factor(), other.scaling_factor()
|
|
276
|
+
if lx != rx:
|
|
277
|
+
return richcmp_not_equal(lx, rx, op)
|
|
278
|
+
|
|
279
|
+
# Do self or other have specialized comparison methods?
|
|
280
|
+
|
|
281
|
+
ret = self._comparison_impl(self, other, op)
|
|
282
|
+
if ret is not NotImplemented:
|
|
283
|
+
return ret
|
|
284
|
+
|
|
285
|
+
ret = other._comparison_impl(self, other, op)
|
|
286
|
+
if ret is not NotImplemented:
|
|
287
|
+
return ret
|
|
288
|
+
|
|
289
|
+
# If not, fall back to comparing rational maps; cf. Issue #11327
|
|
290
|
+
|
|
291
|
+
return richcmp(self.rational_maps(), other.rational_maps(), op)
|
|
292
|
+
|
|
293
|
+
def degree(self):
|
|
294
|
+
r"""
|
|
295
|
+
Return the degree of this elliptic-curve morphism.
|
|
296
|
+
|
|
297
|
+
EXAMPLES::
|
|
298
|
+
|
|
299
|
+
sage: E = EllipticCurve(QQ, [0,0,0,1,0])
|
|
300
|
+
sage: phi = EllipticCurveIsogeny(E, E((0,0)))
|
|
301
|
+
sage: phi.degree()
|
|
302
|
+
2
|
|
303
|
+
sage: phi = EllipticCurveIsogeny(E, [0,1,0,1])
|
|
304
|
+
sage: phi.degree()
|
|
305
|
+
4
|
|
306
|
+
|
|
307
|
+
sage: E = EllipticCurve(GF(31), [1,0,0,1,2])
|
|
308
|
+
sage: phi = EllipticCurveIsogeny(E, [17, 1])
|
|
309
|
+
sage: phi.degree()
|
|
310
|
+
3
|
|
311
|
+
|
|
312
|
+
Degrees are multiplicative, so the degree of a composite isogeny
|
|
313
|
+
is the product of the degrees of the individual factors::
|
|
314
|
+
|
|
315
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
316
|
+
sage: E = EllipticCurve(GF(419), [1,0])
|
|
317
|
+
sage: P, = E.gens()
|
|
318
|
+
sage: phi = EllipticCurveHom_composite(E, P+P)
|
|
319
|
+
sage: phi.degree()
|
|
320
|
+
210
|
|
321
|
+
sage: phi.degree() == prod(f.degree() for f in phi.factors())
|
|
322
|
+
True
|
|
323
|
+
|
|
324
|
+
Isomorphisms always have degree `1` by definition::
|
|
325
|
+
|
|
326
|
+
sage: E1 = EllipticCurve([1,2,3,4,5])
|
|
327
|
+
sage: E2 = EllipticCurve_from_j(E1.j_invariant())
|
|
328
|
+
sage: E1.isomorphism_to(E2).degree()
|
|
329
|
+
1
|
|
330
|
+
|
|
331
|
+
TESTS::
|
|
332
|
+
|
|
333
|
+
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
|
|
334
|
+
sage: EllipticCurveHom.degree(None)
|
|
335
|
+
Traceback (most recent call last):
|
|
336
|
+
...
|
|
337
|
+
NotImplementedError: ...
|
|
338
|
+
"""
|
|
339
|
+
try:
|
|
340
|
+
return self._degree
|
|
341
|
+
except AttributeError:
|
|
342
|
+
raise NotImplementedError('children must implement')
|
|
343
|
+
|
|
344
|
+
@cached_method
|
|
345
|
+
def trace(self):
|
|
346
|
+
r"""
|
|
347
|
+
Return the trace of this elliptic-curve morphism, which must
|
|
348
|
+
be an endomorphism.
|
|
349
|
+
|
|
350
|
+
ALGORITHM: :func:`compute_trace_generic`
|
|
351
|
+
|
|
352
|
+
EXAMPLES::
|
|
353
|
+
|
|
354
|
+
sage: E = EllipticCurve(QQ, [42, 42])
|
|
355
|
+
sage: m5 = E.scalar_multiplication(5)
|
|
356
|
+
sage: m5.trace()
|
|
357
|
+
10
|
|
358
|
+
|
|
359
|
+
::
|
|
360
|
+
|
|
361
|
+
sage: E = EllipticCurve(GF(71^2), [45, 45])
|
|
362
|
+
sage: P = E.lift_x(27)
|
|
363
|
+
sage: P.order()
|
|
364
|
+
71
|
|
365
|
+
sage: tau = E.isogeny(P, codomain=E)
|
|
366
|
+
sage: tau.trace()
|
|
367
|
+
-1
|
|
368
|
+
|
|
369
|
+
TESTS:
|
|
370
|
+
|
|
371
|
+
Make sure the cached value of the trace is not accidentally
|
|
372
|
+
copied on composition with automorphisms::
|
|
373
|
+
|
|
374
|
+
sage: aut = E.automorphisms()[1] # [-1]
|
|
375
|
+
sage: (aut * tau).trace()
|
|
376
|
+
1
|
|
377
|
+
|
|
378
|
+
It also works for more complicated :class:`EllipticCurveHom`
|
|
379
|
+
children::
|
|
380
|
+
|
|
381
|
+
sage: tau = E.isogeny(P, codomain=E, algorithm='velusqrt')
|
|
382
|
+
sage: tau.trace()
|
|
383
|
+
-1
|
|
384
|
+
|
|
385
|
+
Check that negation commutes with taking the trace::
|
|
386
|
+
|
|
387
|
+
sage: (-tau).trace()
|
|
388
|
+
1
|
|
389
|
+
"""
|
|
390
|
+
F = self.domain().base_field()
|
|
391
|
+
if F.characteristic().is_zero():
|
|
392
|
+
d = self.degree()
|
|
393
|
+
s = self.scaling_factor()
|
|
394
|
+
return ZZ(s + d/s)
|
|
395
|
+
return compute_trace_generic(self)
|
|
396
|
+
|
|
397
|
+
def characteristic_polynomial(self):
|
|
398
|
+
r"""
|
|
399
|
+
Return the characteristic polynomial of this elliptic-curve
|
|
400
|
+
morphism, which must be an endomorphism.
|
|
401
|
+
|
|
402
|
+
.. SEEALSO::
|
|
403
|
+
|
|
404
|
+
- :meth:`degree`
|
|
405
|
+
- :meth:`trace`
|
|
406
|
+
|
|
407
|
+
EXAMPLES::
|
|
408
|
+
|
|
409
|
+
sage: E = EllipticCurve(QQ, [42, 42])
|
|
410
|
+
sage: m5 = E.scalar_multiplication(5)
|
|
411
|
+
sage: m5.characteristic_polynomial()
|
|
412
|
+
x^2 - 10*x + 25
|
|
413
|
+
|
|
414
|
+
::
|
|
415
|
+
|
|
416
|
+
sage: E = EllipticCurve(GF(71), [42, 42])
|
|
417
|
+
sage: pi = E.frobenius_endomorphism()
|
|
418
|
+
sage: pi.characteristic_polynomial()
|
|
419
|
+
x^2 - 8*x + 71
|
|
420
|
+
sage: E.frobenius().charpoly()
|
|
421
|
+
x^2 - 8*x + 71
|
|
422
|
+
|
|
423
|
+
TESTS::
|
|
424
|
+
|
|
425
|
+
sage: m5.characteristic_polynomial().parent()
|
|
426
|
+
Univariate Polynomial Ring in x over Integer Ring
|
|
427
|
+
sage: pi.characteristic_polynomial().parent()
|
|
428
|
+
Univariate Polynomial Ring in x over Integer Ring
|
|
429
|
+
"""
|
|
430
|
+
R = ZZ['x']
|
|
431
|
+
return R([self.degree(), -self.trace(), 1])
|
|
432
|
+
|
|
433
|
+
def kernel_polynomial(self):
|
|
434
|
+
r"""
|
|
435
|
+
Return the kernel polynomial of this elliptic-curve morphism.
|
|
436
|
+
|
|
437
|
+
Implemented by child classes. For examples, see:
|
|
438
|
+
|
|
439
|
+
- :meth:`EllipticCurveIsogeny.kernel_polynomial`
|
|
440
|
+
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.kernel_polynomial`
|
|
441
|
+
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.kernel_polynomial`
|
|
442
|
+
- :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.kernel_polynomial`
|
|
443
|
+
- :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.kernel_polynomial`
|
|
444
|
+
- :meth:`sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius.kernel_polynomial`
|
|
445
|
+
|
|
446
|
+
TESTS::
|
|
447
|
+
|
|
448
|
+
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
|
|
449
|
+
sage: EllipticCurveHom.kernel_polynomial(None)
|
|
450
|
+
Traceback (most recent call last):
|
|
451
|
+
...
|
|
452
|
+
NotImplementedError: ...
|
|
453
|
+
"""
|
|
454
|
+
raise NotImplementedError('children must implement')
|
|
455
|
+
|
|
456
|
+
def dual(self):
|
|
457
|
+
r"""
|
|
458
|
+
Return the dual of this elliptic-curve morphism.
|
|
459
|
+
|
|
460
|
+
Implemented by child classes. For examples, see:
|
|
461
|
+
|
|
462
|
+
- :meth:`EllipticCurveIsogeny.dual`
|
|
463
|
+
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.dual`
|
|
464
|
+
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.dual`
|
|
465
|
+
- :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.dual`
|
|
466
|
+
- :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.dual`
|
|
467
|
+
- :meth:`sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius.dual`
|
|
468
|
+
|
|
469
|
+
TESTS::
|
|
470
|
+
|
|
471
|
+
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
|
|
472
|
+
sage: EllipticCurveHom.dual(None)
|
|
473
|
+
Traceback (most recent call last):
|
|
474
|
+
...
|
|
475
|
+
NotImplementedError: ...
|
|
476
|
+
"""
|
|
477
|
+
raise NotImplementedError('children must implement')
|
|
478
|
+
|
|
479
|
+
def rational_maps(self):
|
|
480
|
+
r"""
|
|
481
|
+
Return the pair of explicit rational maps defining this
|
|
482
|
+
elliptic-curve morphism as fractions of bivariate
|
|
483
|
+
polynomials in `x` and `y`.
|
|
484
|
+
|
|
485
|
+
Implemented by child classes. For examples, see:
|
|
486
|
+
|
|
487
|
+
- :meth:`EllipticCurveIsogeny.rational_maps`
|
|
488
|
+
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.rational_maps`
|
|
489
|
+
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.rational_maps`
|
|
490
|
+
- :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.rational_maps`
|
|
491
|
+
- :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.rational_maps`
|
|
492
|
+
- :meth:`sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius.rational_maps`
|
|
493
|
+
|
|
494
|
+
TESTS::
|
|
495
|
+
|
|
496
|
+
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
|
|
497
|
+
sage: EllipticCurveHom.rational_maps(None)
|
|
498
|
+
Traceback (most recent call last):
|
|
499
|
+
...
|
|
500
|
+
NotImplementedError: ...
|
|
501
|
+
"""
|
|
502
|
+
raise NotImplementedError('children must implement')
|
|
503
|
+
|
|
504
|
+
def x_rational_map(self):
|
|
505
|
+
r"""
|
|
506
|
+
Return the `x`-coordinate rational map of this elliptic-curve
|
|
507
|
+
morphism as a univariate rational expression in `x`.
|
|
508
|
+
|
|
509
|
+
Implemented by child classes. For examples, see:
|
|
510
|
+
|
|
511
|
+
- :meth:`EllipticCurveIsogeny.x_rational_map`
|
|
512
|
+
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.x_rational_map`
|
|
513
|
+
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.x_rational_map`
|
|
514
|
+
- :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.x_rational_map`
|
|
515
|
+
- :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.x_rational_map`
|
|
516
|
+
- :meth:`sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius.x_rational_map`
|
|
517
|
+
|
|
518
|
+
TESTS::
|
|
519
|
+
|
|
520
|
+
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
|
|
521
|
+
sage: EllipticCurveHom.x_rational_map(None)
|
|
522
|
+
Traceback (most recent call last):
|
|
523
|
+
...
|
|
524
|
+
NotImplementedError: ...
|
|
525
|
+
"""
|
|
526
|
+
# TODO: could have a default implementation that simply
|
|
527
|
+
# returns the first component of rational_maps()
|
|
528
|
+
raise NotImplementedError('children must implement')
|
|
529
|
+
|
|
530
|
+
def scaling_factor(self):
|
|
531
|
+
r"""
|
|
532
|
+
Return the Weierstrass scaling factor associated to this
|
|
533
|
+
elliptic-curve morphism.
|
|
534
|
+
|
|
535
|
+
The scaling factor is the constant `u` (in the base field)
|
|
536
|
+
such that `\varphi^* \omega_2 = u \omega_1`, where
|
|
537
|
+
`\varphi: E_1\to E_2` is this morphism and `\omega_i` are
|
|
538
|
+
the standard Weierstrass differentials on `E_i` defined by
|
|
539
|
+
`\mathrm dx/(2y+a_1x+a_3)`.
|
|
540
|
+
|
|
541
|
+
Implemented by child classes. For examples, see:
|
|
542
|
+
|
|
543
|
+
- :meth:`EllipticCurveIsogeny.scaling_factor`
|
|
544
|
+
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.scaling_factor`
|
|
545
|
+
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.scaling_factor`
|
|
546
|
+
- :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.scaling_factor`
|
|
547
|
+
- :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.scaling_factor`
|
|
548
|
+
|
|
549
|
+
TESTS::
|
|
550
|
+
|
|
551
|
+
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
|
|
552
|
+
sage: EllipticCurveHom.scaling_factor(None)
|
|
553
|
+
Traceback (most recent call last):
|
|
554
|
+
...
|
|
555
|
+
NotImplementedError: ...
|
|
556
|
+
"""
|
|
557
|
+
# TODO: could have a default implementation that simply
|
|
558
|
+
# returns .formal()[1], but it seems safer to fail
|
|
559
|
+
# visibly to make sure we would notice regressions
|
|
560
|
+
raise NotImplementedError('children must implement')
|
|
561
|
+
|
|
562
|
+
def formal(self, prec=20):
|
|
563
|
+
r"""
|
|
564
|
+
Return the formal isogeny associated to this elliptic-curve
|
|
565
|
+
morphism as a power series in the variable `t=-x/y` on the
|
|
566
|
+
domain curve.
|
|
567
|
+
|
|
568
|
+
INPUT:
|
|
569
|
+
|
|
570
|
+
- ``prec`` -- (default: 20) the precision with which the
|
|
571
|
+
computations in the formal group are carried out
|
|
572
|
+
|
|
573
|
+
EXAMPLES::
|
|
574
|
+
|
|
575
|
+
sage: E = EllipticCurve(GF(13),[1,7])
|
|
576
|
+
sage: phi = E.isogeny(E(10,4))
|
|
577
|
+
sage: phi.formal()
|
|
578
|
+
t + 12*t^13 + 2*t^17 + 8*t^19 + 2*t^21 + O(t^23)
|
|
579
|
+
|
|
580
|
+
::
|
|
581
|
+
|
|
582
|
+
sage: E = EllipticCurve([0,1])
|
|
583
|
+
sage: phi = E.isogeny(E(2,3))
|
|
584
|
+
sage: phi.formal(prec=10)
|
|
585
|
+
t + 54*t^5 + 255*t^7 + 2430*t^9 + 19278*t^11 + O(t^13)
|
|
586
|
+
|
|
587
|
+
::
|
|
588
|
+
|
|
589
|
+
sage: E = EllipticCurve('11a2')
|
|
590
|
+
sage: R.<x> = QQ[]
|
|
591
|
+
sage: phi = E.isogeny(x^2 + 101*x + 12751/5)
|
|
592
|
+
sage: phi.formal(prec=7)
|
|
593
|
+
t - 2724/5*t^5 + 209046/5*t^7 - 4767/5*t^8 + 29200946/5*t^9 + O(t^10)
|
|
594
|
+
"""
|
|
595
|
+
Eh = self._domain.formal()
|
|
596
|
+
f, g = self.rational_maps()
|
|
597
|
+
xh = Eh.x(prec=prec)
|
|
598
|
+
assert not self.is_separable() or xh.valuation() == -2, f"xh has valuation {xh.valuation()} (should be -2)"
|
|
599
|
+
yh = Eh.y(prec=prec)
|
|
600
|
+
assert not self.is_separable() or yh.valuation() == -3, f"yh has valuation {yh.valuation()} (should be -3)"
|
|
601
|
+
fh = f(xh,yh)
|
|
602
|
+
assert not self.is_separable() or fh.valuation() == -2, f"fh has valuation {fh.valuation()} (should be -2)"
|
|
603
|
+
gh = g(xh,yh)
|
|
604
|
+
assert not self.is_separable() or gh.valuation() == -3, f"gh has valuation {gh.valuation()} (should be -3)"
|
|
605
|
+
th = -fh/gh
|
|
606
|
+
assert not self.is_separable() or th.valuation() == +1, f"th has valuation {th.valuation()} (should be +1)"
|
|
607
|
+
return th
|
|
608
|
+
|
|
609
|
+
def is_normalized(self):
|
|
610
|
+
r"""
|
|
611
|
+
Determine whether this morphism is a normalized isogeny.
|
|
612
|
+
|
|
613
|
+
.. NOTE::
|
|
614
|
+
|
|
615
|
+
An isogeny `\varphi\colon E_1\to E_2` between two given
|
|
616
|
+
Weierstrass equations is said to be *normalized* if the
|
|
617
|
+
`\varphi^*(\omega_2) = \omega_1`, where `\omega_1` and
|
|
618
|
+
`\omega_2` are the invariant differentials on `E_1` and
|
|
619
|
+
`E_2` corresponding to the given equation.
|
|
620
|
+
|
|
621
|
+
EXAMPLES::
|
|
622
|
+
|
|
623
|
+
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism
|
|
624
|
+
sage: E = EllipticCurve(GF(7), [0,0,0,1,0])
|
|
625
|
+
sage: R.<x> = GF(7)[]
|
|
626
|
+
sage: phi = EllipticCurveIsogeny(E, x)
|
|
627
|
+
sage: phi.is_normalized()
|
|
628
|
+
True
|
|
629
|
+
sage: isom = WeierstrassIsomorphism(phi.codomain(), (3, 0, 0, 0))
|
|
630
|
+
sage: phi = isom * phi
|
|
631
|
+
sage: phi.is_normalized()
|
|
632
|
+
False
|
|
633
|
+
sage: isom = WeierstrassIsomorphism(phi.codomain(), (5, 0, 0, 0))
|
|
634
|
+
sage: phi = isom * phi
|
|
635
|
+
sage: phi.is_normalized()
|
|
636
|
+
True
|
|
637
|
+
sage: isom = WeierstrassIsomorphism(phi.codomain(), (1, 1, 1, 1))
|
|
638
|
+
sage: phi = isom * phi
|
|
639
|
+
sage: phi.is_normalized()
|
|
640
|
+
True
|
|
641
|
+
|
|
642
|
+
::
|
|
643
|
+
|
|
644
|
+
sage: F = GF(2^5, 'alpha'); alpha = F.gen()
|
|
645
|
+
sage: E = EllipticCurve(F, [1,0,1,1,1])
|
|
646
|
+
sage: R.<x> = F[]
|
|
647
|
+
sage: phi = EllipticCurveIsogeny(E, x+1)
|
|
648
|
+
sage: isom = WeierstrassIsomorphism(phi.codomain(), (alpha, 0, 0, 0))
|
|
649
|
+
sage: phi.is_normalized()
|
|
650
|
+
True
|
|
651
|
+
sage: phi = isom * phi
|
|
652
|
+
sage: phi.is_normalized()
|
|
653
|
+
False
|
|
654
|
+
sage: isom = WeierstrassIsomorphism(phi.codomain(), (1/alpha, 0, 0, 0))
|
|
655
|
+
sage: phi = isom * phi
|
|
656
|
+
sage: phi.is_normalized()
|
|
657
|
+
True
|
|
658
|
+
sage: isom = WeierstrassIsomorphism(phi.codomain(), (1, 1, 1, 1))
|
|
659
|
+
sage: phi = isom * phi
|
|
660
|
+
sage: phi.is_normalized()
|
|
661
|
+
True
|
|
662
|
+
|
|
663
|
+
::
|
|
664
|
+
|
|
665
|
+
sage: E = EllipticCurve('11a1')
|
|
666
|
+
sage: R.<x> = QQ[]
|
|
667
|
+
sage: f = x^3 - x^2 - 10*x - 79/4
|
|
668
|
+
sage: phi = EllipticCurveIsogeny(E, f)
|
|
669
|
+
sage: isom = WeierstrassIsomorphism(phi.codomain(), (2, 0, 0, 0))
|
|
670
|
+
sage: phi.is_normalized()
|
|
671
|
+
True
|
|
672
|
+
sage: phi = isom * phi
|
|
673
|
+
sage: phi.is_normalized()
|
|
674
|
+
False
|
|
675
|
+
sage: isom = WeierstrassIsomorphism(phi.codomain(), (1/2, 0, 0, 0))
|
|
676
|
+
sage: phi = isom * phi
|
|
677
|
+
sage: phi.is_normalized()
|
|
678
|
+
True
|
|
679
|
+
sage: isom = WeierstrassIsomorphism(phi.codomain(), (1, 1, 1, 1))
|
|
680
|
+
sage: phi = isom * phi
|
|
681
|
+
sage: phi.is_normalized()
|
|
682
|
+
True
|
|
683
|
+
|
|
684
|
+
ALGORITHM: We check if :meth:`scaling_factor` returns `1`.
|
|
685
|
+
"""
|
|
686
|
+
return self.scaling_factor().is_one()
|
|
687
|
+
|
|
688
|
+
def inseparable_degree(self):
|
|
689
|
+
r"""
|
|
690
|
+
Return the inseparable degree of this isogeny.
|
|
691
|
+
|
|
692
|
+
Implemented by child classes. For examples, see:
|
|
693
|
+
|
|
694
|
+
- :meth:`EllipticCurveIsogeny.inseparable_degree`
|
|
695
|
+
- :meth:`sage.schemes.elliptic_curves.weierstrass_morphism.WeierstrassIsomorphism.inseparable_degree`
|
|
696
|
+
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite.inseparable_degree`
|
|
697
|
+
- :meth:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum.inseparable_degree`
|
|
698
|
+
- :meth:`sage.schemes.elliptic_curves.hom_scalar.EllipticCurveHom_scalar.inseparable_degree`
|
|
699
|
+
- :meth:`sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius.inseparable_degree`
|
|
700
|
+
|
|
701
|
+
TESTS::
|
|
702
|
+
|
|
703
|
+
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
|
|
704
|
+
sage: EllipticCurveHom.inseparable_degree(None)
|
|
705
|
+
Traceback (most recent call last):
|
|
706
|
+
...
|
|
707
|
+
NotImplementedError: ...
|
|
708
|
+
"""
|
|
709
|
+
raise NotImplementedError('children must implement')
|
|
710
|
+
|
|
711
|
+
def separable_degree(self):
|
|
712
|
+
r"""
|
|
713
|
+
Return the separable degree of this isogeny.
|
|
714
|
+
|
|
715
|
+
The separable degree is the result of dividing the :meth:`degree`
|
|
716
|
+
by the :meth:`inseparable_degree`.
|
|
717
|
+
|
|
718
|
+
EXAMPLES::
|
|
719
|
+
|
|
720
|
+
sage: E = EllipticCurve(GF(11), [5,5])
|
|
721
|
+
sage: E.is_supersingular()
|
|
722
|
+
False
|
|
723
|
+
sage: E.scalar_multiplication(-77).separable_degree()
|
|
724
|
+
539
|
|
725
|
+
sage: E = EllipticCurve(GF(11), [5,0])
|
|
726
|
+
sage: E.is_supersingular()
|
|
727
|
+
True
|
|
728
|
+
sage: E.scalar_multiplication(-77).separable_degree()
|
|
729
|
+
49
|
|
730
|
+
"""
|
|
731
|
+
return self.degree() // self.inseparable_degree()
|
|
732
|
+
|
|
733
|
+
def is_separable(self):
|
|
734
|
+
r"""
|
|
735
|
+
Determine whether or not this morphism is a separable isogeny.
|
|
736
|
+
|
|
737
|
+
EXAMPLES::
|
|
738
|
+
|
|
739
|
+
sage: E = EllipticCurve(GF(17), [0,0,0,3,0])
|
|
740
|
+
sage: phi = EllipticCurveIsogeny(E, E((0,0)))
|
|
741
|
+
sage: phi.is_separable()
|
|
742
|
+
True
|
|
743
|
+
|
|
744
|
+
::
|
|
745
|
+
|
|
746
|
+
sage: E = EllipticCurve('11a1')
|
|
747
|
+
sage: phi = EllipticCurveIsogeny(E, E.torsion_points())
|
|
748
|
+
sage: phi.is_separable()
|
|
749
|
+
True
|
|
750
|
+
|
|
751
|
+
::
|
|
752
|
+
|
|
753
|
+
sage: E = EllipticCurve(GF(31337), [0,1]) # needs sage.rings.finite_rings
|
|
754
|
+
sage: {f.is_separable() for f in E.automorphisms()} # needs sage.rings.finite_rings
|
|
755
|
+
{True}
|
|
756
|
+
|
|
757
|
+
::
|
|
758
|
+
|
|
759
|
+
sage: # needs sage.rings.finite_rings
|
|
760
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
761
|
+
sage: E = EllipticCurve(GF(7^2), [3,2])
|
|
762
|
+
sage: P = E.lift_x(1)
|
|
763
|
+
sage: phi = EllipticCurveHom_composite(E, P); phi
|
|
764
|
+
Composite morphism of degree 7:
|
|
765
|
+
From: Elliptic Curve defined by y^2 = x^3 + 3*x + 2 over Finite Field in z2 of size 7^2
|
|
766
|
+
To: Elliptic Curve defined by y^2 = x^3 + 3*x + 2 over Finite Field in z2 of size 7^2
|
|
767
|
+
sage: phi.is_separable()
|
|
768
|
+
True
|
|
769
|
+
|
|
770
|
+
::
|
|
771
|
+
|
|
772
|
+
sage: E = EllipticCurve(GF(11), [4,4])
|
|
773
|
+
sage: E.scalar_multiplication(11).is_separable()
|
|
774
|
+
False
|
|
775
|
+
sage: E.scalar_multiplication(-11).is_separable()
|
|
776
|
+
False
|
|
777
|
+
sage: E.scalar_multiplication(777).is_separable()
|
|
778
|
+
True
|
|
779
|
+
sage: E.scalar_multiplication(-1).is_separable()
|
|
780
|
+
True
|
|
781
|
+
sage: E.scalar_multiplication(77).is_separable()
|
|
782
|
+
False
|
|
783
|
+
sage: E.scalar_multiplication(121).is_separable()
|
|
784
|
+
False
|
|
785
|
+
|
|
786
|
+
::
|
|
787
|
+
|
|
788
|
+
sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
|
|
789
|
+
sage: E = EllipticCurve(GF(11), [1,1])
|
|
790
|
+
sage: pi = EllipticCurveHom_frobenius(E)
|
|
791
|
+
sage: pi.degree()
|
|
792
|
+
11
|
|
793
|
+
sage: pi.is_separable()
|
|
794
|
+
False
|
|
795
|
+
sage: pi = EllipticCurveHom_frobenius(E, 0)
|
|
796
|
+
sage: pi.degree()
|
|
797
|
+
1
|
|
798
|
+
sage: pi.is_separable()
|
|
799
|
+
True
|
|
800
|
+
|
|
801
|
+
::
|
|
802
|
+
|
|
803
|
+
sage: E = EllipticCurve(GF(17), [0,0,0,3,0])
|
|
804
|
+
sage: phi = E.isogeny(E((1,2)), algorithm='velusqrt')
|
|
805
|
+
sage: phi.is_separable()
|
|
806
|
+
True
|
|
807
|
+
"""
|
|
808
|
+
if self.is_zero():
|
|
809
|
+
raise ValueError('constant zero map is not an isogeny')
|
|
810
|
+
return self.inseparable_degree().is_one()
|
|
811
|
+
|
|
812
|
+
def is_surjective(self):
|
|
813
|
+
r"""
|
|
814
|
+
Determine whether or not this morphism is surjective.
|
|
815
|
+
|
|
816
|
+
EXAMPLES::
|
|
817
|
+
|
|
818
|
+
sage: E = EllipticCurve('11a1')
|
|
819
|
+
sage: R.<x> = QQ[]
|
|
820
|
+
sage: f = x^2 + x - 29/5
|
|
821
|
+
sage: phi = EllipticCurveIsogeny(E, f)
|
|
822
|
+
sage: phi.is_surjective()
|
|
823
|
+
True
|
|
824
|
+
|
|
825
|
+
::
|
|
826
|
+
|
|
827
|
+
sage: E = EllipticCurve(GF(7), [0,0,0,1,0])
|
|
828
|
+
sage: phi = EllipticCurveIsogeny(E, E((0,0)))
|
|
829
|
+
sage: phi.is_surjective()
|
|
830
|
+
True
|
|
831
|
+
|
|
832
|
+
::
|
|
833
|
+
|
|
834
|
+
sage: F = GF(2^5, 'omega')
|
|
835
|
+
sage: E = EllipticCurve(j=F(0))
|
|
836
|
+
sage: R.<x> = F[]
|
|
837
|
+
sage: phi = EllipticCurveIsogeny(E, x)
|
|
838
|
+
sage: phi.is_surjective()
|
|
839
|
+
True
|
|
840
|
+
"""
|
|
841
|
+
return bool(self.degree())
|
|
842
|
+
|
|
843
|
+
def is_injective(self):
|
|
844
|
+
r"""
|
|
845
|
+
Determine whether or not this morphism has trivial kernel.
|
|
846
|
+
|
|
847
|
+
The kernel is trivial if and only if this morphism is a
|
|
848
|
+
purely inseparable isogeny.
|
|
849
|
+
|
|
850
|
+
EXAMPLES::
|
|
851
|
+
|
|
852
|
+
sage: E = EllipticCurve('11a1')
|
|
853
|
+
sage: R.<x> = QQ[]
|
|
854
|
+
sage: f = x^2 + x - 29/5
|
|
855
|
+
sage: phi = EllipticCurveIsogeny(E, f)
|
|
856
|
+
sage: phi.is_injective()
|
|
857
|
+
False
|
|
858
|
+
sage: phi = EllipticCurveIsogeny(E, R(1))
|
|
859
|
+
sage: phi.is_injective()
|
|
860
|
+
True
|
|
861
|
+
|
|
862
|
+
::
|
|
863
|
+
|
|
864
|
+
sage: F = GF(7)
|
|
865
|
+
sage: E = EllipticCurve(j=F(0))
|
|
866
|
+
sage: phi = EllipticCurveIsogeny(E, [ E((0,-1)), E((0,1))])
|
|
867
|
+
sage: phi.is_injective()
|
|
868
|
+
False
|
|
869
|
+
sage: phi = EllipticCurveIsogeny(E, E(0))
|
|
870
|
+
sage: phi.is_injective()
|
|
871
|
+
True
|
|
872
|
+
|
|
873
|
+
::
|
|
874
|
+
|
|
875
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
876
|
+
sage: E = EllipticCurve([1,0])
|
|
877
|
+
sage: phi = EllipticCurveHom_composite(E, E(0,0))
|
|
878
|
+
sage: phi.is_injective()
|
|
879
|
+
False
|
|
880
|
+
sage: E = EllipticCurve_from_j(GF(3).algebraic_closure()(0))
|
|
881
|
+
sage: nu = EllipticCurveHom_composite.from_factors(E.automorphisms())
|
|
882
|
+
sage: nu
|
|
883
|
+
Composite morphism of degree 1 = 1^12:
|
|
884
|
+
From: Elliptic Curve defined by y^2 = x^3 + x
|
|
885
|
+
over Algebraic closure of Finite Field of size 3
|
|
886
|
+
To: Elliptic Curve defined by y^2 = x^3 + x
|
|
887
|
+
over Algebraic closure of Finite Field of size 3
|
|
888
|
+
sage: nu.is_injective()
|
|
889
|
+
True
|
|
890
|
+
|
|
891
|
+
::
|
|
892
|
+
|
|
893
|
+
sage: E = EllipticCurve(GF(23), [1,0])
|
|
894
|
+
sage: E.scalar_multiplication(4).is_injective()
|
|
895
|
+
False
|
|
896
|
+
sage: E.scalar_multiplication(5).is_injective()
|
|
897
|
+
False
|
|
898
|
+
sage: E.scalar_multiplication(1).is_injective()
|
|
899
|
+
True
|
|
900
|
+
sage: E.scalar_multiplication(-1).is_injective()
|
|
901
|
+
True
|
|
902
|
+
sage: E.scalar_multiplication(23).is_injective()
|
|
903
|
+
True
|
|
904
|
+
sage: E.scalar_multiplication(-23).is_injective()
|
|
905
|
+
True
|
|
906
|
+
sage: E.scalar_multiplication(0).is_injective()
|
|
907
|
+
False
|
|
908
|
+
|
|
909
|
+
::
|
|
910
|
+
|
|
911
|
+
sage: from sage.schemes.elliptic_curves.hom_frobenius import EllipticCurveHom_frobenius
|
|
912
|
+
sage: E = EllipticCurve(GF(11), [1,1])
|
|
913
|
+
sage: pi = EllipticCurveHom_frobenius(E, 5)
|
|
914
|
+
sage: pi.is_injective()
|
|
915
|
+
True
|
|
916
|
+
"""
|
|
917
|
+
if self.is_zero():
|
|
918
|
+
return False
|
|
919
|
+
return self.separable_degree().is_one()
|
|
920
|
+
|
|
921
|
+
def is_zero(self):
|
|
922
|
+
r"""
|
|
923
|
+
Check whether this elliptic-curve morphism is the zero map.
|
|
924
|
+
|
|
925
|
+
EXAMPLES::
|
|
926
|
+
|
|
927
|
+
sage: E = EllipticCurve(j=GF(7)(0))
|
|
928
|
+
sage: phi = EllipticCurveIsogeny(E, [E(0,1), E(0,-1)])
|
|
929
|
+
sage: phi.is_zero()
|
|
930
|
+
False
|
|
931
|
+
"""
|
|
932
|
+
return not self.degree()
|
|
933
|
+
|
|
934
|
+
def __neg__(self):
|
|
935
|
+
r"""
|
|
936
|
+
Return the negative of this elliptic-curve morphism. In other
|
|
937
|
+
words, return `[-1]\circ\varphi` where `\varphi` is ``self``
|
|
938
|
+
and `[-1]` is the negation automorphism on the codomain curve.
|
|
939
|
+
|
|
940
|
+
EXAMPLES::
|
|
941
|
+
|
|
942
|
+
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
|
|
943
|
+
sage: E = EllipticCurve(GF(1019), [5,5])
|
|
944
|
+
sage: phi = E.isogeny(E.lift_x(73))
|
|
945
|
+
sage: f,g = phi.rational_maps()
|
|
946
|
+
sage: psi = EllipticCurveHom.__neg__(phi)
|
|
947
|
+
sage: psi.rational_maps() == (f, -g)
|
|
948
|
+
True
|
|
949
|
+
"""
|
|
950
|
+
return wm.negation_morphism(self.codomain()) * self
|
|
951
|
+
|
|
952
|
+
@cached_method
|
|
953
|
+
def __hash__(self):
|
|
954
|
+
r"""
|
|
955
|
+
Return a hash value for this elliptic-curve morphism.
|
|
956
|
+
|
|
957
|
+
ALGORITHM:
|
|
958
|
+
|
|
959
|
+
Hash a tuple containing the domain, codomain, and kernel
|
|
960
|
+
polynomial of this morphism. (The base field is factored
|
|
961
|
+
into the computation as part of the (co)domain hashes.)
|
|
962
|
+
|
|
963
|
+
EXAMPLES::
|
|
964
|
+
|
|
965
|
+
sage: E = EllipticCurve(QQ, [0,0,0,1,0])
|
|
966
|
+
sage: phi_v = EllipticCurveIsogeny(E, E((0,0)))
|
|
967
|
+
sage: phi_k = EllipticCurveIsogeny(E, [0,1])
|
|
968
|
+
sage: phi_k.__hash__() == phi_v.__hash__()
|
|
969
|
+
True
|
|
970
|
+
sage: E_F17 = EllipticCurve(GF(17), [0,0,0,1,1])
|
|
971
|
+
sage: phi_p = EllipticCurveIsogeny(E_F17, E_F17([0,1]))
|
|
972
|
+
sage: phi_p.__hash__() == phi_v.__hash__()
|
|
973
|
+
False
|
|
974
|
+
|
|
975
|
+
::
|
|
976
|
+
|
|
977
|
+
sage: E = EllipticCurve('49a3')
|
|
978
|
+
sage: R.<X> = QQ[]
|
|
979
|
+
sage: EllipticCurveIsogeny(E,X^3-13*X^2-58*X+503,check=False)
|
|
980
|
+
Isogeny of degree 7 from Elliptic Curve defined by y^2 + x*y = x^3 - x^2 - 107*x + 552 over Rational Field to Elliptic Curve defined by y^2 + x*y = x^3 - x^2 - 5252*x - 178837 over Rational Field
|
|
981
|
+
"""
|
|
982
|
+
return hash((self.domain(), self.codomain(), self.kernel_polynomial(), self.scaling_factor()))
|
|
983
|
+
|
|
984
|
+
def as_morphism(self):
|
|
985
|
+
r"""
|
|
986
|
+
Return ``self`` as a morphism of projective schemes.
|
|
987
|
+
|
|
988
|
+
EXAMPLES::
|
|
989
|
+
|
|
990
|
+
sage: k = GF(11)
|
|
991
|
+
sage: E = EllipticCurve(k, [1,1])
|
|
992
|
+
sage: Q = E(6,5)
|
|
993
|
+
sage: phi = E.isogeny(Q)
|
|
994
|
+
sage: mor = phi.as_morphism()
|
|
995
|
+
sage: mor.domain() == E
|
|
996
|
+
True
|
|
997
|
+
sage: mor.codomain() == phi.codomain()
|
|
998
|
+
True
|
|
999
|
+
sage: mor(Q) == phi(Q)
|
|
1000
|
+
True
|
|
1001
|
+
|
|
1002
|
+
TESTS::
|
|
1003
|
+
|
|
1004
|
+
sage: mor(0*Q)
|
|
1005
|
+
(0 : 1 : 0)
|
|
1006
|
+
sage: mor(1*Q)
|
|
1007
|
+
(0 : 1 : 0)
|
|
1008
|
+
"""
|
|
1009
|
+
from sage.schemes.curves.constructor import Curve
|
|
1010
|
+
X_affine = Curve(self.domain()).affine_patch(2)
|
|
1011
|
+
Y_affine = Curve(self.codomain()).affine_patch(2)
|
|
1012
|
+
return X_affine.hom(self.rational_maps(), Y_affine).homogenize(2)
|
|
1013
|
+
|
|
1014
|
+
def matrix_on_subgroup(self, domain_gens, codomain_gens=None):
|
|
1015
|
+
r"""
|
|
1016
|
+
Return the matrix by which this isogeny acts on the
|
|
1017
|
+
`n`-torsion subgroup with respect to the given bases.
|
|
1018
|
+
|
|
1019
|
+
INPUT:
|
|
1020
|
+
|
|
1021
|
+
- ``domain_gens`` -- basis `(P,Q)` of some `n`-torsion
|
|
1022
|
+
subgroup on the domain of this elliptic-curve morphism
|
|
1023
|
+
|
|
1024
|
+
- ``codomain_gens`` -- basis `(R,S)` of the `n`-torsion
|
|
1025
|
+
on the codomain of this morphism, or (default) ``None``
|
|
1026
|
+
if ``self`` is an endomorphism
|
|
1027
|
+
|
|
1028
|
+
OUTPUT:
|
|
1029
|
+
|
|
1030
|
+
A `2\times 2` matrix `M` over `\ZZ/n`, such that the
|
|
1031
|
+
image of any point `[a]P + [b]Q` under this morphism
|
|
1032
|
+
equals `[c]R + [d]S` where `(c\ d)^T = (a\ b) M`.
|
|
1033
|
+
|
|
1034
|
+
EXAMPLES::
|
|
1035
|
+
|
|
1036
|
+
sage: F.<i> = GF(419^2, modulus=[1,0,1])
|
|
1037
|
+
sage: E = EllipticCurve(F, [1,0])
|
|
1038
|
+
sage: P = E(3, 176*i)
|
|
1039
|
+
sage: Q = E(i+7, 67*i+48)
|
|
1040
|
+
sage: P.weil_pairing(Q, 420).multiplicative_order()
|
|
1041
|
+
420
|
|
1042
|
+
sage: iota = E.automorphisms()[2]; iota
|
|
1043
|
+
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + x over Finite Field in i of size 419^2
|
|
1044
|
+
Via: (u,r,s,t) = (i, 0, 0, 0)
|
|
1045
|
+
sage: iota^2 == E.scalar_multiplication(-1)
|
|
1046
|
+
True
|
|
1047
|
+
sage: mat = iota.matrix_on_subgroup((P,Q)); mat
|
|
1048
|
+
[301 386]
|
|
1049
|
+
[ 83 119]
|
|
1050
|
+
sage: mat.parent()
|
|
1051
|
+
Full MatrixSpace of 2 by 2 dense matrices over Ring of integers modulo 420
|
|
1052
|
+
sage: iota(P) == 301*P + 386*Q
|
|
1053
|
+
True
|
|
1054
|
+
sage: iota(Q) == 83*P + 119*Q
|
|
1055
|
+
True
|
|
1056
|
+
sage: a,b = 123, 456
|
|
1057
|
+
sage: c,d = vector((a,b)) * mat; (c,d)
|
|
1058
|
+
(111, 102)
|
|
1059
|
+
sage: iota(a*P + b*Q) == c*P + d*Q
|
|
1060
|
+
True
|
|
1061
|
+
|
|
1062
|
+
One important application of this is to compute generators of
|
|
1063
|
+
the kernel subgroup of an isogeny, when the `n`-torsion subgroup
|
|
1064
|
+
containing the kernel is accessible::
|
|
1065
|
+
|
|
1066
|
+
sage: K = E(83*i-16, 9*i-147)
|
|
1067
|
+
sage: K.order()
|
|
1068
|
+
7
|
|
1069
|
+
sage: phi = E.isogeny(K)
|
|
1070
|
+
sage: R,S = phi.codomain().gens()
|
|
1071
|
+
sage: mat = phi.matrix_on_subgroup((P,Q), (R,S))
|
|
1072
|
+
sage: mat # random -- depends on R,S
|
|
1073
|
+
[124 263]
|
|
1074
|
+
[115 141]
|
|
1075
|
+
sage: kermat = mat.left_kernel_matrix(); kermat
|
|
1076
|
+
[300 60]
|
|
1077
|
+
sage: ker = [ZZ(v[0])*P + ZZ(v[1])*Q for v in kermat]
|
|
1078
|
+
sage: {phi(T) for T in ker}
|
|
1079
|
+
{(0 : 1 : 0)}
|
|
1080
|
+
sage: phi == E.isogeny(ker)
|
|
1081
|
+
True
|
|
1082
|
+
|
|
1083
|
+
We can also compute the matrix of a Frobenius endomorphism
|
|
1084
|
+
(:class:`~sage.schemes.elliptic_curves.hom_frobenius.EllipticCurveHom_frobenius`)
|
|
1085
|
+
on a large enough subgroup to verify point-counting results::
|
|
1086
|
+
|
|
1087
|
+
sage: F.<a> = GF((101, 36))
|
|
1088
|
+
sage: E = EllipticCurve(GF(101), [1,1])
|
|
1089
|
+
sage: EE = E.change_ring(F)
|
|
1090
|
+
sage: P,Q = EE.torsion_basis(37)
|
|
1091
|
+
sage: pi = EE.frobenius_isogeny()
|
|
1092
|
+
sage: M = pi.matrix_on_subgroup((P,Q))
|
|
1093
|
+
sage: M.parent()
|
|
1094
|
+
Full MatrixSpace of 2 by 2 dense matrices over Ring of integers modulo 37
|
|
1095
|
+
sage: M.trace()
|
|
1096
|
+
34
|
|
1097
|
+
sage: E.trace_of_frobenius()
|
|
1098
|
+
-3
|
|
1099
|
+
|
|
1100
|
+
.. SEEALSO::
|
|
1101
|
+
|
|
1102
|
+
To compute a basis of the `n`-torsion, you may use
|
|
1103
|
+
:meth:`~sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field.torsion_basis`.
|
|
1104
|
+
"""
|
|
1105
|
+
if codomain_gens is None:
|
|
1106
|
+
if not self.is_endomorphism():
|
|
1107
|
+
raise ValueError('basis of codomain subgroup is required for non-endomorphisms')
|
|
1108
|
+
codomain_gens = domain_gens
|
|
1109
|
+
|
|
1110
|
+
P,Q = domain_gens
|
|
1111
|
+
R,S = codomain_gens
|
|
1112
|
+
|
|
1113
|
+
ords = {P.order() for P in (P,Q,R,S)}
|
|
1114
|
+
if len(ords) != 1:
|
|
1115
|
+
#TODO: Is there some meaningful way to lift this restriction?
|
|
1116
|
+
raise ValueError('generator points must all have the same order')
|
|
1117
|
+
n, = ords
|
|
1118
|
+
|
|
1119
|
+
if P.weil_pairing(Q, n).multiplicative_order() != n:
|
|
1120
|
+
raise ValueError('generator points on domain are not independent')
|
|
1121
|
+
if R.weil_pairing(S, n).multiplicative_order() != n:
|
|
1122
|
+
raise ValueError('generator points on codomain are not independent')
|
|
1123
|
+
|
|
1124
|
+
imP = self._eval(P)
|
|
1125
|
+
imQ = self._eval(Q)
|
|
1126
|
+
|
|
1127
|
+
vecP = imP.log([R, S])
|
|
1128
|
+
vecQ = imQ.log([R, S])
|
|
1129
|
+
|
|
1130
|
+
from sage.matrix.constructor import matrix
|
|
1131
|
+
from sage.rings.finite_rings.integer_mod_ring import Zmod
|
|
1132
|
+
return matrix(Zmod(n), [vecP, vecQ])
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
def compare_via_evaluation(left, right):
|
|
1136
|
+
r"""
|
|
1137
|
+
Test if two elliptic-curve morphisms are equal by evaluating
|
|
1138
|
+
them at enough points.
|
|
1139
|
+
|
|
1140
|
+
INPUT:
|
|
1141
|
+
|
|
1142
|
+
- ``left``, ``right`` -- :class:`EllipticCurveHom` objects
|
|
1143
|
+
|
|
1144
|
+
ALGORITHM:
|
|
1145
|
+
|
|
1146
|
+
We use the fact that two isogenies of equal degree `d` must be
|
|
1147
|
+
the same if and only if they behave identically on more than
|
|
1148
|
+
`4d` points. (It suffices to check this on a few points that
|
|
1149
|
+
generate a large enough subgroup.)
|
|
1150
|
+
|
|
1151
|
+
If the domain curve does not have sufficiently many rational
|
|
1152
|
+
points, the base field is extended first: Taking an extension
|
|
1153
|
+
of degree `O(\log(d))` suffices.
|
|
1154
|
+
|
|
1155
|
+
EXAMPLES::
|
|
1156
|
+
|
|
1157
|
+
sage: E = EllipticCurve(GF(83), [1,0])
|
|
1158
|
+
sage: phi = E.isogeny(12*E.0, model='montgomery'); phi
|
|
1159
|
+
Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 83 to Elliptic Curve defined by y^2 = x^3 + 70*x^2 + x over Finite Field of size 83
|
|
1160
|
+
sage: psi = phi.dual(); psi
|
|
1161
|
+
Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 70*x^2 + x over Finite Field of size 83 to Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 83
|
|
1162
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
1163
|
+
sage: mu = EllipticCurveHom_composite.from_factors([phi, psi])
|
|
1164
|
+
sage: from sage.schemes.elliptic_curves.hom import compare_via_evaluation
|
|
1165
|
+
sage: compare_via_evaluation(mu, E.scalar_multiplication(7)) # needs sage.symbolic
|
|
1166
|
+
True
|
|
1167
|
+
|
|
1168
|
+
.. SEEALSO::
|
|
1169
|
+
|
|
1170
|
+
- :meth:`sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite._richcmp_`
|
|
1171
|
+
"""
|
|
1172
|
+
if left.domain() != right.domain():
|
|
1173
|
+
return False
|
|
1174
|
+
if left.codomain() != right.codomain():
|
|
1175
|
+
return False
|
|
1176
|
+
if left.degree() != right.degree():
|
|
1177
|
+
return False
|
|
1178
|
+
|
|
1179
|
+
E = left.domain()
|
|
1180
|
+
F = E.base_ring()
|
|
1181
|
+
|
|
1182
|
+
d = left.degree()
|
|
1183
|
+
if isinstance(F, finite_field_base.FiniteField):
|
|
1184
|
+
# check at a random rational point first
|
|
1185
|
+
P = E.random_point()
|
|
1186
|
+
if left(P) != right(P):
|
|
1187
|
+
return False
|
|
1188
|
+
|
|
1189
|
+
# then extend to a field with enough points to conclude
|
|
1190
|
+
q = F.cardinality()
|
|
1191
|
+
e = integer_floor(1 + 2 * (2*d.sqrt() + 1).log(q)) # from Hasse bound
|
|
1192
|
+
e = next(i for i, n in enumerate(E.count_points(e+1), 1) if n > 4*d)
|
|
1193
|
+
EE = E.base_extend(F.extension(e, 'U')) # named extension is faster
|
|
1194
|
+
Ps = EE.gens()
|
|
1195
|
+
return all(left._eval(P) == right._eval(P) for P in Ps)
|
|
1196
|
+
|
|
1197
|
+
elif isinstance(F, number_field_base.NumberField):
|
|
1198
|
+
for _ in range(100):
|
|
1199
|
+
P = E.lift_x(F.random_element(), extend=True)
|
|
1200
|
+
if P._has_order_at_least(4*d + 1, attempts=50):
|
|
1201
|
+
# if P.height(precision=250) == 0: # slow sometimes
|
|
1202
|
+
return left._eval(P) == right._eval(P)
|
|
1203
|
+
assert False, "couldn't find a point of large enough order"
|
|
1204
|
+
|
|
1205
|
+
else:
|
|
1206
|
+
raise NotImplementedError('not implemented for this base field')
|
|
1207
|
+
|
|
1208
|
+
|
|
1209
|
+
def find_post_isomorphism(phi, psi):
|
|
1210
|
+
r"""
|
|
1211
|
+
Given two isogenies `\phi: E\to E'` and `\psi: E\to E''`
|
|
1212
|
+
which are equal up to post-isomorphism defined over the
|
|
1213
|
+
same field, find that isomorphism.
|
|
1214
|
+
|
|
1215
|
+
In other words, this function computes an isomorphism
|
|
1216
|
+
`\alpha: E'\to E''` such that `\alpha\circ\phi = \psi`.
|
|
1217
|
+
|
|
1218
|
+
ALGORITHM:
|
|
1219
|
+
|
|
1220
|
+
Start with a list of all isomorphisms `E'\to E''`. Then
|
|
1221
|
+
repeatedly evaluate `\phi` and `\psi` at random points
|
|
1222
|
+
`P` to filter the list for isomorphisms `\alpha` with
|
|
1223
|
+
`\alpha(\phi(P)) = \psi(P)`. Once only one candidate is
|
|
1224
|
+
left, return it. Periodically extend the base field to
|
|
1225
|
+
avoid getting stuck (say, if all candidate isomorphisms
|
|
1226
|
+
act the same on all rational points).
|
|
1227
|
+
|
|
1228
|
+
EXAMPLES::
|
|
1229
|
+
|
|
1230
|
+
sage: from sage.schemes.elliptic_curves.hom import find_post_isomorphism
|
|
1231
|
+
sage: E = EllipticCurve(GF(7^2), [1,0])
|
|
1232
|
+
sage: f = E.scalar_multiplication(1)
|
|
1233
|
+
sage: g = choice(E.automorphisms())
|
|
1234
|
+
sage: find_post_isomorphism(f, g) == g
|
|
1235
|
+
True
|
|
1236
|
+
|
|
1237
|
+
::
|
|
1238
|
+
|
|
1239
|
+
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism
|
|
1240
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
1241
|
+
sage: x = polygen(ZZ, 'x')
|
|
1242
|
+
sage: F.<i> = GF(883^2, modulus=x^2+1)
|
|
1243
|
+
sage: E = EllipticCurve(F, [1,0])
|
|
1244
|
+
sage: P = E.lift_x(117)
|
|
1245
|
+
sage: Q = E.lift_x(774)
|
|
1246
|
+
sage: w = WeierstrassIsomorphism(E, [i,0,0,0])
|
|
1247
|
+
sage: phi = EllipticCurveHom_composite(E, [P,w(Q)]) * w
|
|
1248
|
+
sage: psi = EllipticCurveHom_composite(E, [Q,w(P)])
|
|
1249
|
+
sage: phi.kernel_polynomial() == psi.kernel_polynomial()
|
|
1250
|
+
True
|
|
1251
|
+
sage: find_post_isomorphism(phi, psi)
|
|
1252
|
+
Elliptic-curve morphism:
|
|
1253
|
+
From: Elliptic Curve defined by y^2 = x^3 + 320*x + 482 over Finite Field in i of size 883^2
|
|
1254
|
+
To: Elliptic Curve defined by y^2 = x^3 + 320*x + 401 over Finite Field in i of size 883^2
|
|
1255
|
+
Via: (u,r,s,t) = (882*i, 0, 0, 0)
|
|
1256
|
+
"""
|
|
1257
|
+
E = phi.domain()
|
|
1258
|
+
if psi.domain() != E:
|
|
1259
|
+
raise ValueError('domains do not match')
|
|
1260
|
+
|
|
1261
|
+
isos = phi.codomain().isomorphisms(psi.codomain())
|
|
1262
|
+
if not isos:
|
|
1263
|
+
raise ValueError('codomains not isomorphic')
|
|
1264
|
+
|
|
1265
|
+
F = E.base_ring()
|
|
1266
|
+
|
|
1267
|
+
if isinstance(F, finite_field_base.FiniteField):
|
|
1268
|
+
while len(isos) > 1:
|
|
1269
|
+
for _ in range(20):
|
|
1270
|
+
P = E.random_point()
|
|
1271
|
+
im_phi, im_psi = (phi._eval(P), psi._eval(P))
|
|
1272
|
+
isos = [iso for iso in isos if iso._eval(im_phi) == im_psi]
|
|
1273
|
+
if len(isos) <= 1:
|
|
1274
|
+
break
|
|
1275
|
+
else:
|
|
1276
|
+
E = E.base_extend(E.base_field().extension(2, 'U')) # named extension is faster
|
|
1277
|
+
|
|
1278
|
+
elif isinstance(F, number_field_base.NumberField):
|
|
1279
|
+
for _ in range(100):
|
|
1280
|
+
P = E.lift_x(F.random_element(), extend=True)
|
|
1281
|
+
if P.has_finite_order():
|
|
1282
|
+
continue
|
|
1283
|
+
break
|
|
1284
|
+
else:
|
|
1285
|
+
assert False, "couldn't find a point of infinite order"
|
|
1286
|
+
im_phi, im_psi = (phi._eval(P), psi._eval(P))
|
|
1287
|
+
isos = [iso for iso in isos if iso._eval(im_phi) == im_psi]
|
|
1288
|
+
|
|
1289
|
+
else:
|
|
1290
|
+
# fall back to generic method
|
|
1291
|
+
sc = psi.scaling_factor() / phi.scaling_factor()
|
|
1292
|
+
isos = [iso for iso in isos if iso.u == sc]
|
|
1293
|
+
|
|
1294
|
+
assert len(isos) <= 1
|
|
1295
|
+
if isos:
|
|
1296
|
+
return isos[0]
|
|
1297
|
+
|
|
1298
|
+
# found no suitable isomorphism -- either doesn't exist or a bug
|
|
1299
|
+
raise ValueError('isogenies not equal up to post-isomorphism')
|
|
1300
|
+
|
|
1301
|
+
|
|
1302
|
+
def compute_trace_generic(phi):
|
|
1303
|
+
r"""
|
|
1304
|
+
Compute the trace of the given elliptic-curve endomorphism.
|
|
1305
|
+
|
|
1306
|
+
ALGORITHM: Simple variant of Schoof's algorithm.
|
|
1307
|
+
For enough small primes `\ell`, we find an order-`\ell` point `P`
|
|
1308
|
+
on `E` and use a discrete-logarithm calculation to find the unique
|
|
1309
|
+
scalar `t_\ell \in \{0,...,\ell-1\}` such that
|
|
1310
|
+
`\varphi^2(P)+[\deg(\varphi)]P = [t_\ell]\varphi(P)`.
|
|
1311
|
+
Then `t_\ell` equals the trace of `\varphi` modulo `\ell`, which
|
|
1312
|
+
can therefore be recovered using the Chinese remainder theorem.
|
|
1313
|
+
|
|
1314
|
+
EXAMPLES:
|
|
1315
|
+
|
|
1316
|
+
It works over finite fields::
|
|
1317
|
+
|
|
1318
|
+
sage: from sage.schemes.elliptic_curves.hom import compute_trace_generic
|
|
1319
|
+
sage: E = EllipticCurve(GF(31337), [1,1])
|
|
1320
|
+
sage: compute_trace_generic(E.frobenius_endomorphism())
|
|
1321
|
+
314
|
|
1322
|
+
|
|
1323
|
+
It works over `\QQ`::
|
|
1324
|
+
|
|
1325
|
+
sage: from sage.schemes.elliptic_curves.hom import compute_trace_generic
|
|
1326
|
+
sage: E = EllipticCurve(QQ, [1,2,3,4,5])
|
|
1327
|
+
sage: dbl = E.scalar_multiplication(2)
|
|
1328
|
+
sage: compute_trace_generic(dbl)
|
|
1329
|
+
4
|
|
1330
|
+
|
|
1331
|
+
It works over number fields (for a CM curve)::
|
|
1332
|
+
|
|
1333
|
+
sage: from sage.schemes.elliptic_curves.hom import compute_trace_generic
|
|
1334
|
+
sage: x = polygen(QQ)
|
|
1335
|
+
sage: K.<t> = NumberField(5*x^2 - 2*x + 1)
|
|
1336
|
+
sage: E = EllipticCurve(K, [1,0])
|
|
1337
|
+
sage: phi = E.isogeny([t,0,1], codomain=E) # phi = 2 + i
|
|
1338
|
+
sage: compute_trace_generic(phi)
|
|
1339
|
+
4
|
|
1340
|
+
|
|
1341
|
+
TESTS:
|
|
1342
|
+
|
|
1343
|
+
Check on random elliptic curves over finite fields that
|
|
1344
|
+
the result for Frobenius matches
|
|
1345
|
+
:meth:`~sage.schemes.elliptic_curves.ell_finite_field.EllipticCurve_finite_field.trace_of_frobenius`::
|
|
1346
|
+
|
|
1347
|
+
sage: # needs sage.symbolic
|
|
1348
|
+
sage: from sage.schemes.elliptic_curves.hom import compute_trace_generic
|
|
1349
|
+
sage: p = random_prime(10^3)
|
|
1350
|
+
sage: e = randrange(1, ceil(log(10^5,p)))
|
|
1351
|
+
sage: F.<t> = GF((p, e))
|
|
1352
|
+
sage: E = choice(EllipticCurve(j=F.random_element()).twists())
|
|
1353
|
+
sage: pi = E.frobenius_endomorphism()
|
|
1354
|
+
sage: compute_trace_generic(pi) == E.trace_of_frobenius()
|
|
1355
|
+
True
|
|
1356
|
+
|
|
1357
|
+
Check that the nonexistence of `p`-torsion for supersingular curves
|
|
1358
|
+
does not cause trouble::
|
|
1359
|
+
|
|
1360
|
+
sage: from sage.schemes.elliptic_curves.hom import compute_trace_generic
|
|
1361
|
+
sage: E = EllipticCurve(GF(5), [0,1])
|
|
1362
|
+
sage: E.division_polynomial(5)
|
|
1363
|
+
4
|
|
1364
|
+
sage: m7 = E.scalar_multiplication(7)
|
|
1365
|
+
sage: compute_trace_generic(-m7)
|
|
1366
|
+
-14
|
|
1367
|
+
"""
|
|
1368
|
+
from sage.rings.finite_rings.integer_mod import Mod
|
|
1369
|
+
from sage.groups.generic import discrete_log
|
|
1370
|
+
from sage.sets.primes import Primes
|
|
1371
|
+
from sage.schemes.elliptic_curves.ell_field import point_of_order
|
|
1372
|
+
|
|
1373
|
+
E = phi.domain()
|
|
1374
|
+
if phi.codomain() != E:
|
|
1375
|
+
raise ValueError('trace only makes sense for endomorphisms')
|
|
1376
|
+
|
|
1377
|
+
d = phi.degree()
|
|
1378
|
+
|
|
1379
|
+
M = 4 * d.isqrt() + 1 # |trace| <= 2 sqrt(deg)
|
|
1380
|
+
tr = Mod(0,1)
|
|
1381
|
+
|
|
1382
|
+
F = E.base_field()
|
|
1383
|
+
p = F.characteristic()
|
|
1384
|
+
if p:
|
|
1385
|
+
s = phi.scaling_factor()
|
|
1386
|
+
if s:
|
|
1387
|
+
tr = Mod(ZZ(s + d/s), p)
|
|
1388
|
+
|
|
1389
|
+
for l in Primes():
|
|
1390
|
+
if tr.modulus() >= M:
|
|
1391
|
+
break
|
|
1392
|
+
try:
|
|
1393
|
+
P = point_of_order(E, l)
|
|
1394
|
+
except ValueError:
|
|
1395
|
+
continue # supersingular and l == p
|
|
1396
|
+
|
|
1397
|
+
Q = phi._eval(P)
|
|
1398
|
+
if not Q: # we learn nothing when P lies in the kernel
|
|
1399
|
+
continue
|
|
1400
|
+
R = phi._eval(Q)
|
|
1401
|
+
t = discrete_log(R + d*P, Q, ord=l, operation='+')
|
|
1402
|
+
# assert not R - t*Q + d*P
|
|
1403
|
+
|
|
1404
|
+
tr = tr.crt(Mod(t, l))
|
|
1405
|
+
|
|
1406
|
+
return tr.lift_centered()
|