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,934 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-schemes
|
|
2
|
+
r"""
|
|
3
|
+
Composite morphisms of elliptic curves
|
|
4
|
+
|
|
5
|
+
It is often computationally convenient (for example, in cryptography)
|
|
6
|
+
to factor an isogeny of large degree into a composition of isogenies
|
|
7
|
+
of smaller (prime) degree. This class implements such a decomposition
|
|
8
|
+
while exposing (close to) the same interface as "normal", unfactored
|
|
9
|
+
elliptic-curve isogenies.
|
|
10
|
+
|
|
11
|
+
EXAMPLES:
|
|
12
|
+
|
|
13
|
+
The following example would take quite literally forever with the
|
|
14
|
+
straightforward :class:`EllipticCurveIsogeny` implementation, but
|
|
15
|
+
decomposing into prime steps is exponentially faster::
|
|
16
|
+
|
|
17
|
+
sage: # needs sage.rings.finite_rings
|
|
18
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
19
|
+
sage: p = 3 * 2^143 - 1
|
|
20
|
+
sage: GF(p^2).inject_variables()
|
|
21
|
+
Defining z2
|
|
22
|
+
sage: E = EllipticCurve(GF(p^2), [1,0])
|
|
23
|
+
sage: P = E.lift_x(31415926535897932384626433832795028841971 - z2)
|
|
24
|
+
sage: P.order().factor()
|
|
25
|
+
2^143
|
|
26
|
+
sage: EllipticCurveHom_composite(E, P)
|
|
27
|
+
Composite morphism of degree 11150372599265311570767859136324180752990208 = 2^143:
|
|
28
|
+
From: Elliptic Curve defined by y^2 = x^3 + x
|
|
29
|
+
over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2
|
|
30
|
+
To: Elliptic Curve defined by y^2 = x^3 + (18676616716352953484576727486205473216172067*z2+32690199585974925193292786311814241821808308)*x
|
|
31
|
+
+ (3369702436351367403910078877591946300201903*z2+15227558615699041241851978605002704626689722)
|
|
32
|
+
over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2
|
|
33
|
+
|
|
34
|
+
Yet, the interface provided by :class:`EllipticCurveHom_composite`
|
|
35
|
+
is identical to :class:`EllipticCurveIsogeny` and other instantiations
|
|
36
|
+
of :class:`EllipticCurveHom`::
|
|
37
|
+
|
|
38
|
+
sage: # needs sage.rings.finite_rings
|
|
39
|
+
sage: E = EllipticCurve(GF(419), [0,1])
|
|
40
|
+
sage: P = E.lift_x(33); P.order()
|
|
41
|
+
35
|
|
42
|
+
sage: psi = EllipticCurveHom_composite(E, P); psi
|
|
43
|
+
Composite morphism of degree 35 = 5*7:
|
|
44
|
+
From: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 419
|
|
45
|
+
To: Elliptic Curve defined by y^2 = x^3 + 101*x + 285 over Finite Field of size 419
|
|
46
|
+
sage: psi(E.lift_x(11))
|
|
47
|
+
(352 : 346 : 1)
|
|
48
|
+
sage: psi.rational_maps()
|
|
49
|
+
((x^35 + 162*x^34 + 186*x^33 + 92*x^32 - ... + 44*x^3 + 190*x^2 + 80*x
|
|
50
|
+
- 72)/(x^34 + 162*x^33 - 129*x^32 + 41*x^31 + ... + 66*x^3 - 191*x^2 + 119*x + 21),
|
|
51
|
+
(x^51*y - 176*x^50*y + 115*x^49*y - 120*x^48*y + ... + 72*x^3*y + 129*x^2*y + 163*x*y
|
|
52
|
+
+ 178*y)/(x^51 - 176*x^50 + 11*x^49 + 26*x^48 - ... - 77*x^3 + 185*x^2 + 169*x - 128))
|
|
53
|
+
sage: psi.kernel_polynomial()
|
|
54
|
+
x^17 + 81*x^16 + 7*x^15 + 82*x^14 + 49*x^13 + 68*x^12 + 109*x^11 + 326*x^10
|
|
55
|
+
+ 117*x^9 + 136*x^8 + 111*x^7 + 292*x^6 + 55*x^5 + 389*x^4 + 175*x^3 + 43*x^2 + 149*x + 373
|
|
56
|
+
sage: psi.dual()
|
|
57
|
+
Composite morphism of degree 35 = 7*5:
|
|
58
|
+
From: Elliptic Curve defined by y^2 = x^3 + 101*x + 285 over Finite Field of size 419
|
|
59
|
+
To: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 419
|
|
60
|
+
sage: psi.formal()
|
|
61
|
+
t + 211*t^5 + 417*t^7 + 159*t^9 + 360*t^11 + 259*t^13 + 224*t^15 + 296*t^17 + 139*t^19 + 222*t^21 + O(t^23)
|
|
62
|
+
|
|
63
|
+
Equality is decided correctly (and, in some cases, much faster than
|
|
64
|
+
comparing :meth:`EllipticCurveHom.rational_maps`) even when distinct
|
|
65
|
+
factorizations of the same isogeny are compared::
|
|
66
|
+
|
|
67
|
+
sage: psi == EllipticCurveIsogeny(E, P) # needs sage.rings.finite_rings sage.symbolic
|
|
68
|
+
True
|
|
69
|
+
|
|
70
|
+
We can easily obtain the individual factors of the composite map::
|
|
71
|
+
|
|
72
|
+
sage: psi.factors() # needs sage.rings.finite_rings
|
|
73
|
+
(Isogeny of degree 5
|
|
74
|
+
from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 419
|
|
75
|
+
to Elliptic Curve defined by y^2 = x^3 + 140*x + 214 over Finite Field of size 419,
|
|
76
|
+
Isogeny of degree 7
|
|
77
|
+
from Elliptic Curve defined by y^2 = x^3 + 140*x + 214 over Finite Field of size 419
|
|
78
|
+
to Elliptic Curve defined by y^2 = x^3 + 101*x + 285 over Finite Field of size 419)
|
|
79
|
+
|
|
80
|
+
AUTHORS:
|
|
81
|
+
|
|
82
|
+
- Lukas Zobernig (2020): initial proof-of-concept version
|
|
83
|
+
- Lorenz Panny (2021): :class:`EllipticCurveHom` interface,
|
|
84
|
+
documentation and tests, equality testing
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
from sage.structure.richcmp import op_EQ
|
|
88
|
+
from sage.misc.cachefunc import cached_method
|
|
89
|
+
from sage.structure.sequence import Sequence
|
|
90
|
+
|
|
91
|
+
from sage.arith.misc import prod
|
|
92
|
+
|
|
93
|
+
from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic
|
|
94
|
+
from sage.schemes.elliptic_curves.hom import EllipticCurveHom, compare_via_evaluation
|
|
95
|
+
from sage.schemes.elliptic_curves.ell_curve_isogeny import EllipticCurveIsogeny
|
|
96
|
+
from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism, identity_morphism
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _eval_factored_isogeny(phis, P):
|
|
100
|
+
"""
|
|
101
|
+
This method pushes a point `P` through a given sequence ``phis``
|
|
102
|
+
of compatible isogenies.
|
|
103
|
+
|
|
104
|
+
EXAMPLES::
|
|
105
|
+
|
|
106
|
+
sage: # needs sage.rings.finite_rings
|
|
107
|
+
sage: from sage.schemes.elliptic_curves import hom_composite
|
|
108
|
+
sage: E = EllipticCurve(GF(419), [1,0])
|
|
109
|
+
sage: Q = E(21, 8)
|
|
110
|
+
sage: phis = []
|
|
111
|
+
sage: while len(phis) < 10:
|
|
112
|
+
....: P = list(sorted(E(0).division_points(7)))[1]
|
|
113
|
+
....: phis.append(E.isogeny(P))
|
|
114
|
+
....: E = phis[-1].codomain()
|
|
115
|
+
sage: R = hom_composite._eval_factored_isogeny(phis, Q); R
|
|
116
|
+
(290 : 183 : 1)
|
|
117
|
+
sage: R in E
|
|
118
|
+
True
|
|
119
|
+
"""
|
|
120
|
+
for phi in phis:
|
|
121
|
+
P = phi(P)
|
|
122
|
+
return P
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _compute_factored_isogeny_prime_power(P, l, n, split=.8, velu_sqrt_bound=None):
|
|
126
|
+
r"""
|
|
127
|
+
This method takes a point `P` of order `\ell^n` and returns
|
|
128
|
+
a sequence of degree-`\ell` isogenies whose composition has
|
|
129
|
+
the subgroup generated by `P` as its kernel.
|
|
130
|
+
|
|
131
|
+
The optional argument ``split``, a real number between
|
|
132
|
+
`0` and `1`, controls the *strategy* used to compute the
|
|
133
|
+
isogeny: In general, the algorithm performs a number of
|
|
134
|
+
scalar multiplications `[\ell]` and a number of
|
|
135
|
+
`\ell`-isogeny evaluations, and there exist tradeoffs
|
|
136
|
+
between them.
|
|
137
|
+
|
|
138
|
+
- Setting ``split`` to `0` skews the algorithm towards
|
|
139
|
+
isogenies, minimizing multiplications.
|
|
140
|
+
The asymptotic complexity is `O(n \log(\ell) + n^2 \ell)`.
|
|
141
|
+
|
|
142
|
+
- Setting ``split`` to `1` skews the algorithm towards
|
|
143
|
+
multiplications, minimizing isogenies.
|
|
144
|
+
The asymptotic complexity is `O(n^2 \log(\ell) + n \ell)`.
|
|
145
|
+
|
|
146
|
+
- Values strictly between `0` and `1` define *sparse*
|
|
147
|
+
strategies, which balance the number of isogenies and
|
|
148
|
+
multiplications according to the parameter.
|
|
149
|
+
The asymptotic complexity is `O(n \log(n) \ell)`.
|
|
150
|
+
|
|
151
|
+
The optional parameter ``velu_sqrt_bound`` prescribes the
|
|
152
|
+
point in which the computation of a single isogeny should be
|
|
153
|
+
performed using square root Velu instead of simple Velu.
|
|
154
|
+
|
|
155
|
+
.. NOTE::
|
|
156
|
+
|
|
157
|
+
As of July 2022, good values for ``split`` range somewhere
|
|
158
|
+
between roughly `0.6` and `0.9`, depending on the size of
|
|
159
|
+
`\ell` and the cost of base-field arithmetic.
|
|
160
|
+
|
|
161
|
+
REFERENCES:
|
|
162
|
+
|
|
163
|
+
Sparse strategies were introduced in [DJP2014]_, §4.2.2.
|
|
164
|
+
|
|
165
|
+
ALGORITHM:
|
|
166
|
+
|
|
167
|
+
The splitting rule implemented here is a simple heuristic which
|
|
168
|
+
is usually not optimal. The advantage is that it does not rely
|
|
169
|
+
on prior knowledge of degrees and exact costs of elliptic-curve
|
|
170
|
+
arithmetic, while still working reasonably well for a fairly
|
|
171
|
+
wide range of situations.
|
|
172
|
+
|
|
173
|
+
EXAMPLES::
|
|
174
|
+
|
|
175
|
+
sage: # needs sage.rings.finite_rings
|
|
176
|
+
sage: from sage.schemes.elliptic_curves import hom_composite
|
|
177
|
+
sage: E = EllipticCurve(GF(8191), [1,0])
|
|
178
|
+
sage: P = E.random_point()
|
|
179
|
+
sage: (l,n), = P.order().factor()
|
|
180
|
+
sage: phis = hom_composite._compute_factored_isogeny_prime_power(P, l, n)
|
|
181
|
+
sage: hom_composite._eval_factored_isogeny(phis, P)
|
|
182
|
+
(0 : 1 : 0)
|
|
183
|
+
sage: [phi.degree() for phi in phis] == [l]*n
|
|
184
|
+
True
|
|
185
|
+
|
|
186
|
+
All choices of ``split`` produce the same result, albeit
|
|
187
|
+
not equally fast::
|
|
188
|
+
|
|
189
|
+
sage: # needs sage.rings.finite_rings
|
|
190
|
+
sage: E = EllipticCurve(GF(2^127 - 1), [1,0])
|
|
191
|
+
sage: P, = E.gens()
|
|
192
|
+
sage: (l,n), = P.order().factor()
|
|
193
|
+
sage: phis = hom_composite._compute_factored_isogeny_prime_power(P,l,n)
|
|
194
|
+
sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0) # long time -- about 10s
|
|
195
|
+
True
|
|
196
|
+
sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0.1)
|
|
197
|
+
True
|
|
198
|
+
sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0.5)
|
|
199
|
+
True
|
|
200
|
+
sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0.9)
|
|
201
|
+
True
|
|
202
|
+
sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=1)
|
|
203
|
+
True
|
|
204
|
+
"""
|
|
205
|
+
def rec(Q, k):
|
|
206
|
+
|
|
207
|
+
if k == 1:
|
|
208
|
+
# base case: Q has order l
|
|
209
|
+
Q._order = l # This was not cached before
|
|
210
|
+
return [Q.curve().isogeny(kernel=Q, velu_sqrt_bound=velu_sqrt_bound)]
|
|
211
|
+
|
|
212
|
+
# recursive case: k > 1 and Q has order l^k
|
|
213
|
+
|
|
214
|
+
k1 = int(k * split + .5)
|
|
215
|
+
k1 = max(1, min(k - 1, k1)) # clamp to [1, k - 1]
|
|
216
|
+
|
|
217
|
+
Q1 = l**k1 * Q
|
|
218
|
+
L = rec(Q1, k - k1)
|
|
219
|
+
|
|
220
|
+
Q2 = _eval_factored_isogeny(L, Q)
|
|
221
|
+
R = rec(Q2, k1)
|
|
222
|
+
|
|
223
|
+
return L + R
|
|
224
|
+
|
|
225
|
+
return rec(P, n)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _compute_factored_isogeny_single_generator(P, velu_sqrt_bound=None):
|
|
229
|
+
"""
|
|
230
|
+
This method takes a point `P` and returns a sequence of
|
|
231
|
+
prime-degree isogenies whose composition has the subgroup
|
|
232
|
+
generated by `P` as its kernel.
|
|
233
|
+
|
|
234
|
+
The optional parameter ``velu_sqrt_bound`` prescribes the
|
|
235
|
+
point in which the computation of a single isogeny should be
|
|
236
|
+
performed using square root Velu instead of simple Velu.
|
|
237
|
+
|
|
238
|
+
EXAMPLES::
|
|
239
|
+
|
|
240
|
+
sage: # needs sage.rings.finite_rings
|
|
241
|
+
sage: from sage.schemes.elliptic_curves import hom_composite
|
|
242
|
+
sage: E = EllipticCurve(GF(419), [1,0])
|
|
243
|
+
sage: P = E(42, 321)
|
|
244
|
+
sage: phis = hom_composite._compute_factored_isogeny_single_generator(P)
|
|
245
|
+
sage: list(sorted(phi.degree() for phi in phis))
|
|
246
|
+
[2, 2, 3, 5, 7]
|
|
247
|
+
sage: hom_composite._eval_factored_isogeny(phis, P)
|
|
248
|
+
(0 : 1 : 0)
|
|
249
|
+
|
|
250
|
+
::
|
|
251
|
+
|
|
252
|
+
sage: from sage.schemes.elliptic_curves import hom_composite
|
|
253
|
+
sage: p = 3217
|
|
254
|
+
sage: E = EllipticCurve_from_j(GF(p)(42))
|
|
255
|
+
sage: P = E.gens()[0]
|
|
256
|
+
sage: phis = hom_composite._compute_factored_isogeny_single_generator(P, velu_sqrt_bound=50)
|
|
257
|
+
sage: for phi in phis:
|
|
258
|
+
....: print(phi)
|
|
259
|
+
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
|
|
260
|
+
Elliptic-curve isogeny (using square-root Vélu) of degree 103:
|
|
261
|
+
From: Elliptic Curve defined by y^2 = x^3 + 277*x + 1710 over Finite Field of size 3217
|
|
262
|
+
To: Elliptic Curve defined by y^2 = x^3 + 2979*x + 1951 over Finite Field of size 3217
|
|
263
|
+
"""
|
|
264
|
+
phis = []
|
|
265
|
+
h = P.order()
|
|
266
|
+
for l,e in P.order().factor():
|
|
267
|
+
h //= l**e
|
|
268
|
+
psis = _compute_factored_isogeny_prime_power(h*P, l, e, velu_sqrt_bound=velu_sqrt_bound)
|
|
269
|
+
P = _eval_factored_isogeny(psis, P)
|
|
270
|
+
phis += psis
|
|
271
|
+
return phis
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def _compute_factored_isogeny(kernel, velu_sqrt_bound=None):
|
|
275
|
+
"""
|
|
276
|
+
This method takes a set of points on an elliptic curve
|
|
277
|
+
and returns a sequence of isogenies whose composition
|
|
278
|
+
has the subgroup generated by that subset as its kernel.
|
|
279
|
+
|
|
280
|
+
The optional parameter ``velu_sqrt_bound`` prescribes the
|
|
281
|
+
point in which the computation of a single isogeny should be
|
|
282
|
+
performed using square root Velu instead of simple Velu.
|
|
283
|
+
|
|
284
|
+
EXAMPLES::
|
|
285
|
+
|
|
286
|
+
sage: # needs sage.rings.finite_rings
|
|
287
|
+
sage: from sage.schemes.elliptic_curves import hom_composite
|
|
288
|
+
sage: E = EllipticCurve(GF(419), [-1,0])
|
|
289
|
+
sage: Ps = [E(41,99), E(41,-99), E(51,14), E(21,21), E(33,17)]
|
|
290
|
+
sage: phis = hom_composite._compute_factored_isogeny(Ps)
|
|
291
|
+
sage: [phi.degree() for phi in phis]
|
|
292
|
+
[2, 3, 5, 7, 2]
|
|
293
|
+
sage: {hom_composite._eval_factored_isogeny(phis, P) for P in Ps}
|
|
294
|
+
{(0 : 1 : 0)}
|
|
295
|
+
"""
|
|
296
|
+
phis = []
|
|
297
|
+
ker = list(kernel)
|
|
298
|
+
while ker:
|
|
299
|
+
K = ker.pop(0)
|
|
300
|
+
psis = _compute_factored_isogeny_single_generator(K, velu_sqrt_bound=velu_sqrt_bound)
|
|
301
|
+
ker = [_eval_factored_isogeny(psis, P) for P in ker]
|
|
302
|
+
phis += psis
|
|
303
|
+
return phis
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class EllipticCurveHom_composite(EllipticCurveHom):
|
|
307
|
+
|
|
308
|
+
_degree = None
|
|
309
|
+
_phis = None
|
|
310
|
+
|
|
311
|
+
def __init__(self, E, kernel, codomain=None, model=None, velu_sqrt_bound=None):
|
|
312
|
+
"""
|
|
313
|
+
Construct a composite isogeny with given kernel (and optionally,
|
|
314
|
+
prescribed codomain curve). The isogeny is decomposed into steps
|
|
315
|
+
of prime degree.
|
|
316
|
+
|
|
317
|
+
The ``codomain`` and ``model`` parameters have the same meaning
|
|
318
|
+
as for :class:`EllipticCurveIsogeny`.
|
|
319
|
+
|
|
320
|
+
The optional parameter ``velu_sqrt_bound`` prescribes the point
|
|
321
|
+
in which the computation of a single isogeny should be performed
|
|
322
|
+
using square root Velu instead of simple Velu. If not provided,
|
|
323
|
+
the system default is used (see
|
|
324
|
+
:class:`EllipticCurve_field.isogeny` for a more detailed
|
|
325
|
+
discussion.
|
|
326
|
+
|
|
327
|
+
EXAMPLES::
|
|
328
|
+
|
|
329
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
330
|
+
sage: E = EllipticCurve(GF(419), [1,0]) # needs sage.rings.finite_rings
|
|
331
|
+
sage: EllipticCurveHom_composite(E, E.lift_x(23)) # needs sage.rings.finite_rings
|
|
332
|
+
Composite morphism of degree 105 = 3*5*7:
|
|
333
|
+
From: Elliptic Curve defined by y^2 = x^3 + x
|
|
334
|
+
over Finite Field of size 419
|
|
335
|
+
To: Elliptic Curve defined by y^2 = x^3 + 373*x + 126
|
|
336
|
+
over Finite Field of size 419
|
|
337
|
+
|
|
338
|
+
The given kernel generators need not be independent::
|
|
339
|
+
|
|
340
|
+
sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
|
|
341
|
+
sage: x = polygen(ZZ, 'x')
|
|
342
|
+
sage: K.<a> = NumberField(x^2 - x - 5)
|
|
343
|
+
sage: E = EllipticCurve('210.b6').change_ring(K)
|
|
344
|
+
sage: E.torsion_subgroup()
|
|
345
|
+
Torsion Subgroup isomorphic to Z/12 + Z/2 associated to the Elliptic Curve
|
|
346
|
+
defined by y^2 + x*y + y = x^3 + (-578)*x + 2756
|
|
347
|
+
over Number Field in a with defining polynomial x^2 - x - 5
|
|
348
|
+
sage: EllipticCurveHom_composite(E, E.torsion_points())
|
|
349
|
+
Composite morphism of degree 24 = 2^3*3:
|
|
350
|
+
From: Elliptic Curve defined by y^2 + x*y + y = x^3 + (-578)*x + 2756
|
|
351
|
+
over Number Field in a with defining polynomial x^2 - x - 5
|
|
352
|
+
To: Elliptic Curve defined by
|
|
353
|
+
y^2 + x*y + y = x^3 + (-89915533/16)*x + (-328200928141/64)
|
|
354
|
+
over Number Field in a with defining polynomial x^2 - x - 5
|
|
355
|
+
|
|
356
|
+
TESTS::
|
|
357
|
+
|
|
358
|
+
sage: E = EllipticCurve(GF(19), [1,0])
|
|
359
|
+
sage: P = E.random_point()
|
|
360
|
+
sage: psi = EllipticCurveHom_composite(E, P)
|
|
361
|
+
sage: psi # random
|
|
362
|
+
Composite morphism of degree 10 = 2*5:
|
|
363
|
+
From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 19
|
|
364
|
+
To: Elliptic Curve defined by y^2 = x^3 + 14*x over Finite Field of size 19
|
|
365
|
+
|
|
366
|
+
::
|
|
367
|
+
|
|
368
|
+
sage: EllipticCurveHom_composite(E, E.lift_x(3), codomain=E)
|
|
369
|
+
Composite morphism of degree 20 = 2^2*5:
|
|
370
|
+
From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 19
|
|
371
|
+
To: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 19
|
|
372
|
+
|
|
373
|
+
::
|
|
374
|
+
|
|
375
|
+
sage: # needs sage.rings.finite_rings
|
|
376
|
+
sage: E = EllipticCurve(GF((2^127-1)^2), [1,0])
|
|
377
|
+
sage: K = 2^30 * E.random_point()
|
|
378
|
+
sage: psi = EllipticCurveHom_composite(E, K, model='montgomery')
|
|
379
|
+
sage: psi.codomain().a_invariants()
|
|
380
|
+
(0, ..., 0, 1, 0)
|
|
381
|
+
"""
|
|
382
|
+
if not isinstance(E, EllipticCurve_generic):
|
|
383
|
+
raise ValueError(f'not an elliptic curve: {E}')
|
|
384
|
+
|
|
385
|
+
if not isinstance(kernel, list) and not isinstance(kernel, tuple):
|
|
386
|
+
kernel = [kernel]
|
|
387
|
+
|
|
388
|
+
for P in kernel:
|
|
389
|
+
if P not in E:
|
|
390
|
+
raise ValueError(f'given point {P} does not lie on {E}')
|
|
391
|
+
|
|
392
|
+
self._phis = _compute_factored_isogeny(kernel, velu_sqrt_bound=velu_sqrt_bound)
|
|
393
|
+
|
|
394
|
+
if not self._phis:
|
|
395
|
+
self._phis = [identity_morphism(E)]
|
|
396
|
+
|
|
397
|
+
if model is not None:
|
|
398
|
+
if codomain is not None:
|
|
399
|
+
raise ValueError("cannot specify a codomain curve and model name simultaneously")
|
|
400
|
+
|
|
401
|
+
from sage.schemes.elliptic_curves.ell_field import compute_model
|
|
402
|
+
codomain = compute_model(self._phis[-1].codomain(), model)
|
|
403
|
+
|
|
404
|
+
if codomain is not None:
|
|
405
|
+
if not isinstance(codomain, EllipticCurve_generic):
|
|
406
|
+
raise ValueError(f'not an elliptic curve: {codomain}')
|
|
407
|
+
iso = self._phis[-1].codomain().isomorphism_to(codomain)
|
|
408
|
+
if hasattr(self._phis[-1], '_set_post_isomorphism'):
|
|
409
|
+
self._phis[-1]._set_post_isomorphism(iso)
|
|
410
|
+
else:
|
|
411
|
+
self._phis.append(iso)
|
|
412
|
+
|
|
413
|
+
self._phis = tuple(self._phis) # make immutable
|
|
414
|
+
self.__perform_inheritance_housekeeping()
|
|
415
|
+
|
|
416
|
+
def __perform_inheritance_housekeeping(self):
|
|
417
|
+
"""
|
|
418
|
+
Internal helper function to set values of the superclass.
|
|
419
|
+
|
|
420
|
+
TESTS::
|
|
421
|
+
|
|
422
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
423
|
+
sage: E = EllipticCurve([1,0])
|
|
424
|
+
sage: phi = EllipticCurveHom_composite(E, E(0,0)) # implicit doctest
|
|
425
|
+
sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
|
|
426
|
+
sage: print(EllipticCurveHom._repr_(phi))
|
|
427
|
+
Elliptic-curve morphism:
|
|
428
|
+
From: Elliptic Curve defined by y^2 = x^3 + x over Rational Field
|
|
429
|
+
To: Elliptic Curve defined by y^2 = x^3 - 4*x over Rational Field
|
|
430
|
+
sage: phi.domain()
|
|
431
|
+
Elliptic Curve defined by y^2 = x^3 + x over Rational Field
|
|
432
|
+
sage: phi.codomain()
|
|
433
|
+
Elliptic Curve defined by y^2 = x^3 - 4*x over Rational Field
|
|
434
|
+
"""
|
|
435
|
+
self._degree = prod(phi.degree() for phi in self._phis)
|
|
436
|
+
self._domain = self._phis[0].domain()
|
|
437
|
+
self._codomain = self._phis[-1].codomain()
|
|
438
|
+
EllipticCurveHom.__init__(self, self._domain, self._codomain)
|
|
439
|
+
|
|
440
|
+
@classmethod
|
|
441
|
+
def from_factors(cls, maps, E=None, strict=True):
|
|
442
|
+
r"""
|
|
443
|
+
This method constructs a :class:`EllipticCurveHom_composite`
|
|
444
|
+
object encapsulating a given sequence of compatible isogenies.
|
|
445
|
+
|
|
446
|
+
The isogenies are composed in left-to-right order, i.e., the
|
|
447
|
+
resulting composite map equals `f_{n-1} \circ \dots \circ f_0`
|
|
448
|
+
where `f_i` denotes ``maps[i]``.
|
|
449
|
+
|
|
450
|
+
INPUT:
|
|
451
|
+
|
|
452
|
+
- ``maps`` -- sequence of :class:`EllipticCurveHom` objects
|
|
453
|
+
- ``E`` -- (optional) the domain elliptic curve
|
|
454
|
+
- ``strict`` -- boolean (default: ``True``); if ``True``,
|
|
455
|
+
always return an :class:`EllipticCurveHom_composite` object,
|
|
456
|
+
else may return another :class:`EllipticCurveHom` type
|
|
457
|
+
|
|
458
|
+
OUTPUT: the composite of ``maps``
|
|
459
|
+
|
|
460
|
+
EXAMPLES::
|
|
461
|
+
|
|
462
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
463
|
+
sage: E = EllipticCurve(GF(43), [1,0])
|
|
464
|
+
sage: P, = E.gens()
|
|
465
|
+
sage: phi = EllipticCurveHom_composite(E, P)
|
|
466
|
+
sage: psi = EllipticCurveHom_composite.from_factors(phi.factors())
|
|
467
|
+
sage: psi == phi # needs sage.symbolic
|
|
468
|
+
True
|
|
469
|
+
|
|
470
|
+
TESTS::
|
|
471
|
+
|
|
472
|
+
sage: E = EllipticCurve('4730k1')
|
|
473
|
+
sage: EllipticCurveHom_composite.from_factors([], E) == E.scalar_multiplication(1)
|
|
474
|
+
True
|
|
475
|
+
|
|
476
|
+
::
|
|
477
|
+
|
|
478
|
+
sage: # needs sage.rings.finite_rings
|
|
479
|
+
sage: E = EllipticCurve(GF(419), [1,0])
|
|
480
|
+
sage: P, = E.gens()
|
|
481
|
+
sage: phi = EllipticCurveHom_composite(E, P)
|
|
482
|
+
sage: EllipticCurveHom_composite.from_factors(phi.factors()) == phi # needs sage.symbolic
|
|
483
|
+
True
|
|
484
|
+
"""
|
|
485
|
+
maps = tuple(maps)
|
|
486
|
+
if not maps and E is None:
|
|
487
|
+
raise ValueError('need either factors or domain')
|
|
488
|
+
if E is None:
|
|
489
|
+
E = maps[0].domain()
|
|
490
|
+
|
|
491
|
+
for phi in maps:
|
|
492
|
+
if not isinstance(phi, EllipticCurveHom):
|
|
493
|
+
raise TypeError(f'not an elliptic-curve isogeny: {phi}')
|
|
494
|
+
if phi.domain() != E:
|
|
495
|
+
raise ValueError(f'isogeny has incorrect domain: {phi}')
|
|
496
|
+
E = phi.codomain()
|
|
497
|
+
|
|
498
|
+
if not maps:
|
|
499
|
+
maps = (identity_morphism(E),)
|
|
500
|
+
|
|
501
|
+
if len(maps) == 1 and not strict:
|
|
502
|
+
return maps[0]
|
|
503
|
+
|
|
504
|
+
result = cls.__new__(cls)
|
|
505
|
+
result._phis = maps
|
|
506
|
+
result.__perform_inheritance_housekeeping()
|
|
507
|
+
return result
|
|
508
|
+
|
|
509
|
+
def _call_(self, P):
|
|
510
|
+
"""
|
|
511
|
+
Evaluate this composite isogeny at a point.
|
|
512
|
+
|
|
513
|
+
TESTS::
|
|
514
|
+
|
|
515
|
+
sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
|
|
516
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
517
|
+
sage: x = polygen(ZZ, 'x')
|
|
518
|
+
sage: K.<a> = NumberField(x^2 - x - 5)
|
|
519
|
+
sage: E = EllipticCurve('210.b6').change_ring(K)
|
|
520
|
+
sage: psi = EllipticCurveHom_composite(E, E.torsion_points())
|
|
521
|
+
sage: R = E.lift_x(15/4 * (a+3))
|
|
522
|
+
sage: psi(R) # indirect doctest
|
|
523
|
+
(1033648757/303450 : -58397496786187/1083316500*a + 54706287407197/2166633000 : 1)
|
|
524
|
+
|
|
525
|
+
Check that copying the order over works::
|
|
526
|
+
|
|
527
|
+
sage: # needs sage.rings.finite_rings
|
|
528
|
+
sage: E = EllipticCurve(GF(431), [1,0])
|
|
529
|
+
sage: P, = E.gens()
|
|
530
|
+
sage: Q = 2^99*P; Q.order()
|
|
531
|
+
27
|
|
532
|
+
sage: phi = E.isogeny(3^99*P, algorithm='factored')
|
|
533
|
+
sage: phi(Q)._order
|
|
534
|
+
27
|
|
535
|
+
"""
|
|
536
|
+
return _eval_factored_isogeny(self._phis, P)
|
|
537
|
+
|
|
538
|
+
def _eval(self, P):
|
|
539
|
+
r"""
|
|
540
|
+
Less strict evaluation method for internal use.
|
|
541
|
+
|
|
542
|
+
In particular, this can be used to evaluate ``self`` at a
|
|
543
|
+
point defined over an extension field.
|
|
544
|
+
|
|
545
|
+
INPUT: a sequence of 3 coordinates defining a point on ``self``
|
|
546
|
+
|
|
547
|
+
OUTPUT: the result of evaluating ``self`` at the given point
|
|
548
|
+
|
|
549
|
+
EXAMPLES::
|
|
550
|
+
|
|
551
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
552
|
+
sage: E = EllipticCurve(j=Mod(1728,419))
|
|
553
|
+
sage: K, = E.gens()
|
|
554
|
+
sage: psi = EllipticCurveHom_composite(E, 4*K)
|
|
555
|
+
sage: Ps = E.change_ring(GF(419**2))(0).division_points(5) # needs sage.rings.finite_rings
|
|
556
|
+
sage: {psi._eval(P).curve() for P in Ps} # needs sage.rings.finite_rings
|
|
557
|
+
{Elliptic Curve defined by y^2 = x^3 + 373*x + 126 over Finite Field in z2 of size 419^2}
|
|
558
|
+
"""
|
|
559
|
+
if self._domain.defining_polynomial()(*P):
|
|
560
|
+
raise ValueError(f'{P} not on {self._domain}')
|
|
561
|
+
k = Sequence(P).universe()
|
|
562
|
+
|
|
563
|
+
Q = P
|
|
564
|
+
for phi in self._phis:
|
|
565
|
+
Q = phi._eval(Q)
|
|
566
|
+
|
|
567
|
+
return self._codomain.base_extend(k)(*Q)
|
|
568
|
+
|
|
569
|
+
def _repr_(self):
|
|
570
|
+
"""
|
|
571
|
+
Return basic facts about this composite isogeny as a string.
|
|
572
|
+
|
|
573
|
+
TESTS::
|
|
574
|
+
|
|
575
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
576
|
+
sage: E = EllipticCurve(GF(43), [1,0])
|
|
577
|
+
sage: P, = E.gens()
|
|
578
|
+
sage: phi = EllipticCurveHom_composite(E, P)
|
|
579
|
+
sage: phi # indirect doctest
|
|
580
|
+
Composite morphism of degree 44 = 2^2*11:
|
|
581
|
+
From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43
|
|
582
|
+
To: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43
|
|
583
|
+
sage: phi * phi * phi * phi * phi * phi * phi # indirect doctest
|
|
584
|
+
Composite morphism of degree 319277809664 = 2^2*11*2^2*11*2^2*11*2^2*11*2^2*11*2^2*11*2^2*11:
|
|
585
|
+
From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43
|
|
586
|
+
To: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43
|
|
587
|
+
"""
|
|
588
|
+
from itertools import groupby
|
|
589
|
+
degs = [phi.degree() for phi in self._phis]
|
|
590
|
+
if len(degs) == 1:
|
|
591
|
+
return f'Composite morphism of degree {self._degree}:' \
|
|
592
|
+
f'\n From: {self._domain}' \
|
|
593
|
+
f'\n To: {self._codomain}'
|
|
594
|
+
grouped = [(d, sum(1 for _ in g)) for d,g in groupby(degs)]
|
|
595
|
+
degs_str = '*'.join(str(d) + (f'^{e}' if e > 1 else '') for d,e in grouped)
|
|
596
|
+
return f'Composite morphism of degree {self._degree} = {degs_str}:' \
|
|
597
|
+
f'\n From: {self._domain}' \
|
|
598
|
+
f'\n To: {self._codomain}'
|
|
599
|
+
|
|
600
|
+
def factors(self):
|
|
601
|
+
r"""
|
|
602
|
+
Return the factors of this composite isogeny as a tuple.
|
|
603
|
+
|
|
604
|
+
The isogenies are returned in left-to-right order, i.e.,
|
|
605
|
+
the returned tuple `(f_1,...,f_n)` corresponds to the map
|
|
606
|
+
`f_n \circ \dots \circ f_1`.
|
|
607
|
+
|
|
608
|
+
EXAMPLES::
|
|
609
|
+
|
|
610
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
611
|
+
sage: E = EllipticCurve(GF(43), [1,0])
|
|
612
|
+
sage: P, = E.gens()
|
|
613
|
+
sage: phi = EllipticCurveHom_composite(E, P)
|
|
614
|
+
sage: phi.factors()
|
|
615
|
+
(Isogeny of degree 2
|
|
616
|
+
from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43
|
|
617
|
+
to Elliptic Curve defined by y^2 = x^3 + 39*x over Finite Field of size 43,
|
|
618
|
+
Isogeny of degree 2
|
|
619
|
+
from Elliptic Curve defined by y^2 = x^3 + 39*x over Finite Field of size 43
|
|
620
|
+
to Elliptic Curve defined by y^2 = x^3 + 42*x + 26 over Finite Field of size 43,
|
|
621
|
+
Isogeny of degree 11
|
|
622
|
+
from Elliptic Curve defined by y^2 = x^3 + 42*x + 26 over Finite Field of size 43
|
|
623
|
+
to Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43)
|
|
624
|
+
"""
|
|
625
|
+
return self._phis
|
|
626
|
+
|
|
627
|
+
# EllipticCurveHom methods
|
|
628
|
+
|
|
629
|
+
@staticmethod
|
|
630
|
+
def _composition_impl(left, right):
|
|
631
|
+
"""
|
|
632
|
+
Helper method to compose other elliptic-curve morphisms with
|
|
633
|
+
:class:`EllipticCurveHom_composite` objects. Called by
|
|
634
|
+
:meth:`EllipticCurveHom._composition_`.
|
|
635
|
+
|
|
636
|
+
TESTS::
|
|
637
|
+
|
|
638
|
+
sage: # needs sage.rings.number_field
|
|
639
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
640
|
+
sage: E = EllipticCurve([i + 1, i, 0, -4, -6*i])
|
|
641
|
+
sage: P,Q = E.lift_x(i - 5), E.lift_x(-4*i)
|
|
642
|
+
sage: phi = EllipticCurveHom_composite(E, P)
|
|
643
|
+
sage: psi = phi.codomain().isogeny(phi(Q))
|
|
644
|
+
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism
|
|
645
|
+
sage: iso1 = WeierstrassIsomorphism(E, (-1, 0, -i - 1, 0))
|
|
646
|
+
sage: iso2 = psi.codomain().isomorphism_to(E)
|
|
647
|
+
sage: psi * phi # indirect doctest
|
|
648
|
+
Composite morphism of degree 16 = 2^2*4:
|
|
649
|
+
From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I)
|
|
650
|
+
over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
|
|
651
|
+
To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-3331/4)*x + (-142593/8*I)
|
|
652
|
+
over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
|
|
653
|
+
sage: iso2 * EllipticCurveHom_composite.from_factors([phi, psi]) # indirect doctest
|
|
654
|
+
Composite morphism of degree 16 = 4^2:
|
|
655
|
+
From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I)
|
|
656
|
+
over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
|
|
657
|
+
To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I)
|
|
658
|
+
over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
|
|
659
|
+
sage: phi * iso1 # indirect doctest
|
|
660
|
+
Composite morphism of degree 4 = 2^2:
|
|
661
|
+
From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I)
|
|
662
|
+
over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
|
|
663
|
+
To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (480*I-694)*x + (-7778*I+5556)
|
|
664
|
+
over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
|
|
665
|
+
sage: iso2 * psi * phi * iso1 # indirect doctest
|
|
666
|
+
Composite morphism of degree 16 = 2^2*4:
|
|
667
|
+
From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I)
|
|
668
|
+
over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
|
|
669
|
+
To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I)
|
|
670
|
+
over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
|
|
671
|
+
"""
|
|
672
|
+
if isinstance(left, EllipticCurveHom_composite):
|
|
673
|
+
if isinstance(right, WeierstrassIsomorphism) and hasattr(left.factors()[0], '_set_pre_isomorphism'): # XXX bit of a hack
|
|
674
|
+
return EllipticCurveHom_composite.from_factors((left.factors()[0] * right,) + left.factors()[1:], strict=False)
|
|
675
|
+
if isinstance(right, EllipticCurveHom_composite):
|
|
676
|
+
return EllipticCurveHom_composite.from_factors(right.factors() + left.factors())
|
|
677
|
+
if isinstance(right, EllipticCurveHom):
|
|
678
|
+
return EllipticCurveHom_composite.from_factors((right,) + left.factors())
|
|
679
|
+
if isinstance(right, EllipticCurveHom_composite):
|
|
680
|
+
if isinstance(left, WeierstrassIsomorphism) and hasattr(right.factors()[-1], '_set_post_isomorphism'): # XXX bit of a hack
|
|
681
|
+
return EllipticCurveHom_composite.from_factors(right.factors()[:-1] + (left * right.factors()[-1],), strict=False)
|
|
682
|
+
if isinstance(left, EllipticCurveHom):
|
|
683
|
+
return EllipticCurveHom_composite.from_factors(right.factors() + (left,))
|
|
684
|
+
return NotImplemented
|
|
685
|
+
|
|
686
|
+
@staticmethod
|
|
687
|
+
def _comparison_impl(left, right, op):
|
|
688
|
+
r"""
|
|
689
|
+
Compare a composite isogeny to another elliptic-curve morphism.
|
|
690
|
+
|
|
691
|
+
Called by :meth:`EllipticCurveHom._richcmp_`.
|
|
692
|
+
|
|
693
|
+
ALGORITHM:
|
|
694
|
+
|
|
695
|
+
If possible, we use
|
|
696
|
+
:func:`~sage.schemes.elliptic_curves.hom.compare_via_evaluation`.
|
|
697
|
+
The complexity in that case is polynomial in the representation
|
|
698
|
+
size of this morphism.
|
|
699
|
+
|
|
700
|
+
TESTS::
|
|
701
|
+
|
|
702
|
+
sage: # needs sage.rings.number_field
|
|
703
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
704
|
+
sage: E = EllipticCurve(QuadraticField(-3), [0,16])
|
|
705
|
+
sage: P,Q = E.lift_x(0), E.lift_x(-4)
|
|
706
|
+
sage: phi = EllipticCurveHom_composite(E, P)
|
|
707
|
+
sage: psi = phi.codomain().isogeny(phi(Q))
|
|
708
|
+
sage: psi = psi.codomain().isomorphism_to(E) * psi
|
|
709
|
+
sage: comp = psi * phi
|
|
710
|
+
sage: mu = E.scalar_multiplication(phi.degree())
|
|
711
|
+
sage: sum(a*comp == mu for a in E.automorphisms())
|
|
712
|
+
1
|
|
713
|
+
|
|
714
|
+
::
|
|
715
|
+
|
|
716
|
+
sage: # needs sage.rings.finite_rings sage.rings.number_field sage.symbolic
|
|
717
|
+
sage: E = EllipticCurve(GF(431**2), [1,0])
|
|
718
|
+
sage: P,Q = E.gens()
|
|
719
|
+
sage: phi1 = EllipticCurveHom_composite(E, P)
|
|
720
|
+
sage: phi2 = EllipticCurveHom_composite(phi1.codomain(), phi1(Q))
|
|
721
|
+
sage: psi1 = EllipticCurveHom_composite(E, Q)
|
|
722
|
+
sage: psi2 = EllipticCurveHom_composite(psi1.codomain(), psi1(P))
|
|
723
|
+
sage: phi2 * phi1 == psi2 * psi1
|
|
724
|
+
True
|
|
725
|
+
"""
|
|
726
|
+
if op != op_EQ:
|
|
727
|
+
return NotImplemented
|
|
728
|
+
try:
|
|
729
|
+
return compare_via_evaluation(left, right)
|
|
730
|
+
except NotImplementedError:
|
|
731
|
+
return NotImplemented
|
|
732
|
+
|
|
733
|
+
def rational_maps(self):
|
|
734
|
+
"""
|
|
735
|
+
Return the pair of explicit rational maps defining this composite
|
|
736
|
+
isogeny.
|
|
737
|
+
|
|
738
|
+
EXAMPLES::
|
|
739
|
+
|
|
740
|
+
sage: # needs sage.rings.finite_rings
|
|
741
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
742
|
+
sage: E = EllipticCurve(GF(65537), [1,2,3,4,5])
|
|
743
|
+
sage: P = E.lift_x(7321)
|
|
744
|
+
sage: phi = EllipticCurveHom_composite(E, P)
|
|
745
|
+
sage: phi.rational_maps()
|
|
746
|
+
((x^9 + 27463*x^8 + 21204*x^7 - 5750*x^6 + 1610*x^5 + 14440*x^4
|
|
747
|
+
+ 26605*x^3 - 15569*x^2 - 3341*x + 1267)/(x^8 + 27463*x^7 + 26871*x^6
|
|
748
|
+
+ 5999*x^5 - 20194*x^4 - 6310*x^3 + 24366*x^2 - 20905*x - 13867),
|
|
749
|
+
(x^12*y + 8426*x^11*y + 5667*x^11 + 27612*x^10*y + 26124*x^10 + 9688*x^9*y
|
|
750
|
+
- 22715*x^9 + 19864*x^8*y + 498*x^8 + 22466*x^7*y - 14036*x^7 + 8070*x^6*y
|
|
751
|
+
+ 19955*x^6 - 20765*x^5*y - 12481*x^5 + 12672*x^4*y + 24142*x^4 - 23695*x^3*y
|
|
752
|
+
+ 26667*x^3 + 23780*x^2*y + 17864*x^2 + 15053*x*y - 30118*x + 17539*y
|
|
753
|
+
- 23609)/(x^12 + 8426*x^11 + 21945*x^10 - 22587*x^9 + 22094*x^8 + 14603*x^7
|
|
754
|
+
- 26255*x^6 + 11171*x^5 - 16508*x^4 - 14435*x^3 - 2170*x^2 + 29081*x - 19009))
|
|
755
|
+
|
|
756
|
+
TESTS::
|
|
757
|
+
|
|
758
|
+
sage: f = phi.codomain().defining_polynomial() # needs sage.rings.finite_rings
|
|
759
|
+
sage: g = E.defining_polynomial().subs({2:1}) # needs sage.rings.finite_rings
|
|
760
|
+
sage: f(*phi.rational_maps(), 1) % g # needs sage.rings.finite_rings
|
|
761
|
+
0
|
|
762
|
+
|
|
763
|
+
::
|
|
764
|
+
|
|
765
|
+
sage: phi.rational_maps()[0].parent() # needs sage.rings.finite_rings
|
|
766
|
+
Fraction Field of
|
|
767
|
+
Multivariate Polynomial Ring in x, y over Finite Field of size 65537
|
|
768
|
+
sage: phi.rational_maps()[1].parent() # needs sage.rings.finite_rings
|
|
769
|
+
Fraction Field of
|
|
770
|
+
Multivariate Polynomial Ring in x, y over Finite Field of size 65537
|
|
771
|
+
"""
|
|
772
|
+
fx, fy = self._phis[-1].rational_maps()
|
|
773
|
+
for phi in self._phis[:-1][::-1]:
|
|
774
|
+
gx, gy = phi.rational_maps()
|
|
775
|
+
fx, fy = fx(gx, gy), fy(gx, gy)
|
|
776
|
+
return (fx, fy)
|
|
777
|
+
|
|
778
|
+
def x_rational_map(self):
|
|
779
|
+
"""
|
|
780
|
+
Return the `x`-coordinate rational map of this composite isogeny.
|
|
781
|
+
|
|
782
|
+
EXAMPLES::
|
|
783
|
+
|
|
784
|
+
sage: # needs sage.rings.finite_rings
|
|
785
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
786
|
+
sage: E = EllipticCurve(GF(65537), [1,2,3,4,5])
|
|
787
|
+
sage: P = E.lift_x(7321)
|
|
788
|
+
sage: phi = EllipticCurveHom_composite(E, P)
|
|
789
|
+
sage: phi.x_rational_map() == phi.rational_maps()[0]
|
|
790
|
+
True
|
|
791
|
+
|
|
792
|
+
TESTS::
|
|
793
|
+
|
|
794
|
+
sage: phi.x_rational_map().parent() # needs sage.rings.finite_rings
|
|
795
|
+
Fraction Field of Univariate Polynomial Ring in x
|
|
796
|
+
over Finite Field of size 65537
|
|
797
|
+
"""
|
|
798
|
+
fx = self._phis[-1].x_rational_map()
|
|
799
|
+
for phi in self._phis[:-1][::-1]:
|
|
800
|
+
fx = fx(phi.x_rational_map())
|
|
801
|
+
return fx
|
|
802
|
+
|
|
803
|
+
def kernel_polynomial(self):
|
|
804
|
+
"""
|
|
805
|
+
Return the kernel polynomial of this composite isogeny.
|
|
806
|
+
|
|
807
|
+
EXAMPLES::
|
|
808
|
+
|
|
809
|
+
sage: # needs sage.rings.finite_rings
|
|
810
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
811
|
+
sage: E = EllipticCurve(GF(65537), [1,2,3,4,5])
|
|
812
|
+
sage: P = E.lift_x(7321)
|
|
813
|
+
sage: phi = EllipticCurveHom_composite(E, P); phi
|
|
814
|
+
Composite morphism of degree 9 = 3^2:
|
|
815
|
+
From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5
|
|
816
|
+
over Finite Field of size 65537
|
|
817
|
+
To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 28339*x + 59518
|
|
818
|
+
over Finite Field of size 65537
|
|
819
|
+
sage: phi.kernel_polynomial()
|
|
820
|
+
x^4 + 46500*x^3 + 19556*x^2 + 7643*x + 15952
|
|
821
|
+
"""
|
|
822
|
+
# shouldn't there be a better algorithm for this?
|
|
823
|
+
return self.x_rational_map().denominator().radical()
|
|
824
|
+
|
|
825
|
+
@cached_method
|
|
826
|
+
def dual(self):
|
|
827
|
+
"""
|
|
828
|
+
Return the dual of this composite isogeny.
|
|
829
|
+
|
|
830
|
+
EXAMPLES::
|
|
831
|
+
|
|
832
|
+
sage: # needs sage.rings.finite_rings
|
|
833
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
834
|
+
sage: E = EllipticCurve(GF(65537), [1,2,3,4,5])
|
|
835
|
+
sage: P = E.lift_x(7321)
|
|
836
|
+
sage: phi = EllipticCurveHom_composite(E, P); phi
|
|
837
|
+
Composite morphism of degree 9 = 3^2:
|
|
838
|
+
From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5
|
|
839
|
+
over Finite Field of size 65537
|
|
840
|
+
To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 28339*x + 59518
|
|
841
|
+
over Finite Field of size 65537
|
|
842
|
+
sage: psi = phi.dual(); psi
|
|
843
|
+
Composite morphism of degree 9 = 3^2:
|
|
844
|
+
From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 28339*x + 59518
|
|
845
|
+
over Finite Field of size 65537
|
|
846
|
+
To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5
|
|
847
|
+
over Finite Field of size 65537
|
|
848
|
+
sage: psi * phi == phi.domain().scalar_multiplication(phi.degree()) # needs sage.symbolic
|
|
849
|
+
True
|
|
850
|
+
sage: phi * psi == psi.domain().scalar_multiplication(psi.degree()) # needs sage.symbolic
|
|
851
|
+
True
|
|
852
|
+
"""
|
|
853
|
+
phis = (phi.dual() for phi in self._phis[::-1])
|
|
854
|
+
return EllipticCurveHom_composite.from_factors(phis)
|
|
855
|
+
|
|
856
|
+
def formal(self, prec=20):
|
|
857
|
+
"""
|
|
858
|
+
Return the formal isogeny corresponding to this composite
|
|
859
|
+
isogeny as a power series in the variable `t=-x/y` on the
|
|
860
|
+
domain curve.
|
|
861
|
+
|
|
862
|
+
EXAMPLES::
|
|
863
|
+
|
|
864
|
+
sage: # needs sage.rings.finite_rings
|
|
865
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
866
|
+
sage: E = EllipticCurve(GF(65537), [1,2,3,4,5])
|
|
867
|
+
sage: P = E.lift_x(7321)
|
|
868
|
+
sage: phi = EllipticCurveHom_composite(E, P)
|
|
869
|
+
sage: phi.formal()
|
|
870
|
+
t + 54203*t^5 + 48536*t^6 + 40698*t^7 + 37808*t^8 + 21111*t^9 + 42381*t^10
|
|
871
|
+
+ 46688*t^11 + 657*t^12 + 38916*t^13 + 62261*t^14 + 59707*t^15
|
|
872
|
+
+ 30767*t^16 + 7248*t^17 + 60287*t^18 + 50451*t^19 + 38305*t^20
|
|
873
|
+
+ 12312*t^21 + 31329*t^22 + O(t^23)
|
|
874
|
+
sage: (phi.dual() * phi).formal(prec=5)
|
|
875
|
+
9*t + 65501*t^2 + 65141*t^3 + 59183*t^4 + 21491*t^5 + 8957*t^6
|
|
876
|
+
+ 999*t^7 + O(t^8)
|
|
877
|
+
"""
|
|
878
|
+
res = self._phis[-1].formal(prec=prec)
|
|
879
|
+
for phi in self._phis[:-1][::-1]:
|
|
880
|
+
res = res(phi.formal(prec=prec))
|
|
881
|
+
return res
|
|
882
|
+
|
|
883
|
+
def scaling_factor(self):
|
|
884
|
+
r"""
|
|
885
|
+
Return the Weierstrass scaling factor associated to this
|
|
886
|
+
composite morphism.
|
|
887
|
+
|
|
888
|
+
The scaling factor is the constant `u` (in the base field)
|
|
889
|
+
such that `\varphi^* \omega_2 = u \omega_1`, where
|
|
890
|
+
`\varphi: E_1\to E_2` is this morphism and `\omega_i` are
|
|
891
|
+
the standard Weierstrass differentials on `E_i` defined by
|
|
892
|
+
`\mathrm dx/(2y+a_1x+a_3)`.
|
|
893
|
+
|
|
894
|
+
EXAMPLES::
|
|
895
|
+
|
|
896
|
+
sage: # needs sage.rings.finite_rings
|
|
897
|
+
sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
|
|
898
|
+
sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism
|
|
899
|
+
sage: E = EllipticCurve(GF(65537), [1,2,3,4,5])
|
|
900
|
+
sage: P = E.lift_x(7321)
|
|
901
|
+
sage: phi = EllipticCurveHom_composite(E, P)
|
|
902
|
+
sage: phi = WeierstrassIsomorphism(phi.codomain(), [7,8,9,10]) * phi
|
|
903
|
+
sage: phi.formal()
|
|
904
|
+
7*t + 65474*t^2 + 511*t^3 + 61316*t^4 + 20548*t^5 + 45511*t^6 + 37285*t^7
|
|
905
|
+
+ 48414*t^8 + 9022*t^9 + 24025*t^10 + 35986*t^11 + 55397*t^12 + 25199*t^13
|
|
906
|
+
+ 18744*t^14 + 46142*t^15 + 9078*t^16 + 18030*t^17 + 47599*t^18
|
|
907
|
+
+ 12158*t^19 + 50630*t^20 + 56449*t^21 + 43320*t^22 + O(t^23)
|
|
908
|
+
sage: phi.scaling_factor()
|
|
909
|
+
7
|
|
910
|
+
|
|
911
|
+
ALGORITHM: The scaling factor is multiplicative under
|
|
912
|
+
composition, so we return the product of the individual
|
|
913
|
+
scaling factors associated to each factor.
|
|
914
|
+
"""
|
|
915
|
+
return prod(phi.scaling_factor() for phi in self._phis)
|
|
916
|
+
|
|
917
|
+
def inseparable_degree(self):
|
|
918
|
+
r"""
|
|
919
|
+
Return the inseparable degree of this morphism.
|
|
920
|
+
|
|
921
|
+
Like the degree, the inseparable degree is multiplicative
|
|
922
|
+
under composition, so this method returns the product of
|
|
923
|
+
the inseparable degrees of the factors.
|
|
924
|
+
|
|
925
|
+
EXAMPLES::
|
|
926
|
+
|
|
927
|
+
sage: E = EllipticCurve(j=GF(11^5).random_element())
|
|
928
|
+
sage: phi = E.frobenius_isogeny(2) * E.scalar_multiplication(77)
|
|
929
|
+
sage: type(phi)
|
|
930
|
+
<class 'sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite'>
|
|
931
|
+
sage: phi.inseparable_degree()
|
|
932
|
+
1331
|
|
933
|
+
"""
|
|
934
|
+
return prod(phi.inseparable_degree() for phi in self._phis)
|