passagemath-schemes 10.8.1a4__cp314-cp314t-macosx_13_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (312) hide show
  1. passagemath_schemes/.dylibs/libflint.22.0.dylib +0 -0
  2. passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
  3. passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
  4. passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
  5. passagemath_schemes/__init__.py +3 -0
  6. passagemath_schemes-10.8.1a4.dist-info/METADATA +203 -0
  7. passagemath_schemes-10.8.1a4.dist-info/METADATA.bak +204 -0
  8. passagemath_schemes-10.8.1a4.dist-info/RECORD +312 -0
  9. passagemath_schemes-10.8.1a4.dist-info/WHEEL +6 -0
  10. passagemath_schemes-10.8.1a4.dist-info/top_level.txt +3 -0
  11. sage/all__sagemath_schemes.py +23 -0
  12. sage/databases/all__sagemath_schemes.py +7 -0
  13. sage/databases/cremona.py +1723 -0
  14. sage/dynamics/all__sagemath_schemes.py +2 -0
  15. sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
  16. sage/dynamics/arithmetic_dynamics/all.py +14 -0
  17. sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
  18. sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
  19. sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
  20. sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
  21. sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
  22. sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
  23. sage/dynamics/arithmetic_dynamics/projective_ds.py +9556 -0
  24. sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314t-darwin.so +0 -0
  25. sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
  26. sage/dynamics/arithmetic_dynamics/wehlerK3.py +2578 -0
  27. sage/lfunctions/all.py +18 -0
  28. sage/lfunctions/dokchitser.py +727 -0
  29. sage/lfunctions/pari.py +971 -0
  30. sage/lfunctions/zero_sums.cpython-314t-darwin.so +0 -0
  31. sage/lfunctions/zero_sums.pyx +1847 -0
  32. sage/modular/abvar/abvar.py +5132 -0
  33. sage/modular/abvar/abvar_ambient_jacobian.py +414 -0
  34. sage/modular/abvar/abvar_newform.py +246 -0
  35. sage/modular/abvar/all.py +8 -0
  36. sage/modular/abvar/constructor.py +187 -0
  37. sage/modular/abvar/cuspidal_subgroup.py +371 -0
  38. sage/modular/abvar/finite_subgroup.py +896 -0
  39. sage/modular/abvar/homology.py +721 -0
  40. sage/modular/abvar/homspace.py +989 -0
  41. sage/modular/abvar/lseries.py +415 -0
  42. sage/modular/abvar/morphism.py +935 -0
  43. sage/modular/abvar/torsion_point.py +274 -0
  44. sage/modular/abvar/torsion_subgroup.py +741 -0
  45. sage/modular/all.py +43 -0
  46. sage/modular/arithgroup/all.py +20 -0
  47. sage/modular/arithgroup/arithgroup_element.cpython-314t-darwin.so +0 -0
  48. sage/modular/arithgroup/arithgroup_element.pyx +474 -0
  49. sage/modular/arithgroup/arithgroup_generic.py +1406 -0
  50. sage/modular/arithgroup/arithgroup_perm.py +2692 -0
  51. sage/modular/arithgroup/congroup.cpython-314t-darwin.so +0 -0
  52. sage/modular/arithgroup/congroup.pyx +334 -0
  53. sage/modular/arithgroup/congroup_gamma.py +361 -0
  54. sage/modular/arithgroup/congroup_gamma0.py +692 -0
  55. sage/modular/arithgroup/congroup_gamma1.py +659 -0
  56. sage/modular/arithgroup/congroup_gammaH.py +1491 -0
  57. sage/modular/arithgroup/congroup_generic.py +630 -0
  58. sage/modular/arithgroup/congroup_sl2z.py +266 -0
  59. sage/modular/arithgroup/farey_symbol.cpython-314t-darwin.so +0 -0
  60. sage/modular/arithgroup/farey_symbol.pyx +1067 -0
  61. sage/modular/arithgroup/tests.py +425 -0
  62. sage/modular/btquotients/all.py +4 -0
  63. sage/modular/btquotients/btquotient.py +3736 -0
  64. sage/modular/btquotients/pautomorphicform.py +2564 -0
  65. sage/modular/buzzard.py +100 -0
  66. sage/modular/congroup.py +29 -0
  67. sage/modular/congroup_element.py +13 -0
  68. sage/modular/cusps.py +1107 -0
  69. sage/modular/cusps_nf.py +1270 -0
  70. sage/modular/dims.py +571 -0
  71. sage/modular/dirichlet.py +3310 -0
  72. sage/modular/drinfeld_modform/all.py +2 -0
  73. sage/modular/drinfeld_modform/element.py +446 -0
  74. sage/modular/drinfeld_modform/ring.py +773 -0
  75. sage/modular/drinfeld_modform/tutorial.py +236 -0
  76. sage/modular/etaproducts.py +1076 -0
  77. sage/modular/hecke/algebra.py +725 -0
  78. sage/modular/hecke/all.py +19 -0
  79. sage/modular/hecke/ambient_module.py +994 -0
  80. sage/modular/hecke/degenmap.py +119 -0
  81. sage/modular/hecke/element.py +302 -0
  82. sage/modular/hecke/hecke_operator.py +736 -0
  83. sage/modular/hecke/homspace.py +185 -0
  84. sage/modular/hecke/module.py +1744 -0
  85. sage/modular/hecke/morphism.py +139 -0
  86. sage/modular/hecke/submodule.py +970 -0
  87. sage/modular/hypergeometric_misc.cpython-314t-darwin.so +0 -0
  88. sage/modular/hypergeometric_misc.pxd +4 -0
  89. sage/modular/hypergeometric_misc.pyx +166 -0
  90. sage/modular/hypergeometric_motive.py +2020 -0
  91. sage/modular/local_comp/all.py +2 -0
  92. sage/modular/local_comp/liftings.py +292 -0
  93. sage/modular/local_comp/local_comp.py +1070 -0
  94. sage/modular/local_comp/smoothchar.py +1825 -0
  95. sage/modular/local_comp/type_space.py +748 -0
  96. sage/modular/modform/all.py +30 -0
  97. sage/modular/modform/ambient.py +817 -0
  98. sage/modular/modform/ambient_R.py +177 -0
  99. sage/modular/modform/ambient_eps.py +306 -0
  100. sage/modular/modform/ambient_g0.py +120 -0
  101. sage/modular/modform/ambient_g1.py +199 -0
  102. sage/modular/modform/constructor.py +545 -0
  103. sage/modular/modform/cuspidal_submodule.py +708 -0
  104. sage/modular/modform/defaults.py +14 -0
  105. sage/modular/modform/eis_series.py +487 -0
  106. sage/modular/modform/eisenstein_submodule.py +663 -0
  107. sage/modular/modform/element.py +4105 -0
  108. sage/modular/modform/half_integral.py +154 -0
  109. sage/modular/modform/hecke_operator_on_qexp.py +247 -0
  110. sage/modular/modform/j_invariant.py +47 -0
  111. sage/modular/modform/l_series_gross_zagier.py +127 -0
  112. sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314t-darwin.so +0 -0
  113. sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
  114. sage/modular/modform/notes.py +45 -0
  115. sage/modular/modform/numerical.py +514 -0
  116. sage/modular/modform/periods.py +14 -0
  117. sage/modular/modform/ring.py +1257 -0
  118. sage/modular/modform/space.py +1859 -0
  119. sage/modular/modform/submodule.py +118 -0
  120. sage/modular/modform/tests.py +64 -0
  121. sage/modular/modform/theta.py +110 -0
  122. sage/modular/modform/vm_basis.py +380 -0
  123. sage/modular/modform/weight1.py +221 -0
  124. sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
  125. sage/modular/modform_hecketriangle/abstract_space.py +2527 -0
  126. sage/modular/modform_hecketriangle/all.py +30 -0
  127. sage/modular/modform_hecketriangle/analytic_type.py +590 -0
  128. sage/modular/modform_hecketriangle/constructor.py +416 -0
  129. sage/modular/modform_hecketriangle/element.py +351 -0
  130. sage/modular/modform_hecketriangle/functors.py +752 -0
  131. sage/modular/modform_hecketriangle/graded_ring.py +541 -0
  132. sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
  133. sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3349 -0
  134. sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1426 -0
  135. sage/modular/modform_hecketriangle/readme.py +1214 -0
  136. sage/modular/modform_hecketriangle/series_constructor.py +580 -0
  137. sage/modular/modform_hecketriangle/space.py +1037 -0
  138. sage/modular/modform_hecketriangle/subspace.py +423 -0
  139. sage/modular/modsym/all.py +17 -0
  140. sage/modular/modsym/ambient.py +3844 -0
  141. sage/modular/modsym/boundary.py +1420 -0
  142. sage/modular/modsym/element.py +336 -0
  143. sage/modular/modsym/g1list.py +178 -0
  144. sage/modular/modsym/ghlist.py +182 -0
  145. sage/modular/modsym/hecke_operator.py +73 -0
  146. sage/modular/modsym/manin_symbol.cpython-314t-darwin.so +0 -0
  147. sage/modular/modsym/manin_symbol.pxd +5 -0
  148. sage/modular/modsym/manin_symbol.pyx +497 -0
  149. sage/modular/modsym/manin_symbol_list.py +1291 -0
  150. sage/modular/modsym/modsym.py +400 -0
  151. sage/modular/modsym/modular_symbols.py +384 -0
  152. sage/modular/modsym/p1list_nf.py +1241 -0
  153. sage/modular/modsym/relation_matrix.py +591 -0
  154. sage/modular/modsym/relation_matrix_pyx.cpython-314t-darwin.so +0 -0
  155. sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
  156. sage/modular/modsym/space.py +2468 -0
  157. sage/modular/modsym/subspace.py +455 -0
  158. sage/modular/modsym/tests.py +376 -0
  159. sage/modular/multiple_zeta.py +2635 -0
  160. sage/modular/multiple_zeta_F_algebra.py +789 -0
  161. sage/modular/overconvergent/all.py +6 -0
  162. sage/modular/overconvergent/genus0.py +1879 -0
  163. sage/modular/overconvergent/hecke_series.py +1187 -0
  164. sage/modular/overconvergent/weightspace.py +776 -0
  165. sage/modular/pollack_stevens/all.py +4 -0
  166. sage/modular/pollack_stevens/distributions.py +874 -0
  167. sage/modular/pollack_stevens/fund_domain.py +1572 -0
  168. sage/modular/pollack_stevens/manin_map.py +856 -0
  169. sage/modular/pollack_stevens/modsym.py +1590 -0
  170. sage/modular/pollack_stevens/padic_lseries.py +417 -0
  171. sage/modular/pollack_stevens/sigma0.py +534 -0
  172. sage/modular/pollack_stevens/space.py +1078 -0
  173. sage/modular/quasimodform/all.py +3 -0
  174. sage/modular/quasimodform/element.py +846 -0
  175. sage/modular/quasimodform/ring.py +826 -0
  176. sage/modular/quatalg/all.py +3 -0
  177. sage/modular/quatalg/brandt.py +1642 -0
  178. sage/modular/ssmod/all.py +8 -0
  179. sage/modular/ssmod/ssmod.py +827 -0
  180. sage/rings/all__sagemath_schemes.py +1 -0
  181. sage/rings/polynomial/all__sagemath_schemes.py +1 -0
  182. sage/rings/polynomial/binary_form_reduce.py +585 -0
  183. sage/schemes/all.py +41 -0
  184. sage/schemes/berkovich/all.py +6 -0
  185. sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
  186. sage/schemes/berkovich/berkovich_space.py +700 -0
  187. sage/schemes/curves/affine_curve.py +2924 -0
  188. sage/schemes/curves/all.py +33 -0
  189. sage/schemes/curves/closed_point.py +434 -0
  190. sage/schemes/curves/constructor.py +397 -0
  191. sage/schemes/curves/curve.py +542 -0
  192. sage/schemes/curves/plane_curve_arrangement.py +1283 -0
  193. sage/schemes/curves/point.py +463 -0
  194. sage/schemes/curves/projective_curve.py +3203 -0
  195. sage/schemes/curves/weighted_projective_curve.py +106 -0
  196. sage/schemes/curves/zariski_vankampen.py +1931 -0
  197. sage/schemes/cyclic_covers/all.py +2 -0
  198. sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
  199. sage/schemes/cyclic_covers/constructor.py +137 -0
  200. sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
  201. sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
  202. sage/schemes/elliptic_curves/BSD.py +991 -0
  203. sage/schemes/elliptic_curves/Qcurves.py +592 -0
  204. sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
  205. sage/schemes/elliptic_curves/all.py +49 -0
  206. sage/schemes/elliptic_curves/cardinality.py +609 -0
  207. sage/schemes/elliptic_curves/cm.py +1103 -0
  208. sage/schemes/elliptic_curves/constructor.py +1530 -0
  209. sage/schemes/elliptic_curves/ec_database.py +175 -0
  210. sage/schemes/elliptic_curves/ell_curve_isogeny.py +3971 -0
  211. sage/schemes/elliptic_curves/ell_egros.py +457 -0
  212. sage/schemes/elliptic_curves/ell_field.py +2837 -0
  213. sage/schemes/elliptic_curves/ell_finite_field.py +3249 -0
  214. sage/schemes/elliptic_curves/ell_generic.py +3760 -0
  215. sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
  216. sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
  217. sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
  218. sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
  219. sage/schemes/elliptic_curves/ell_point.py +4944 -0
  220. sage/schemes/elliptic_curves/ell_rational_field.py +7184 -0
  221. sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
  222. sage/schemes/elliptic_curves/ell_torsion.py +436 -0
  223. sage/schemes/elliptic_curves/ell_wp.py +352 -0
  224. sage/schemes/elliptic_curves/formal_group.py +760 -0
  225. sage/schemes/elliptic_curves/gal_reps.py +1459 -0
  226. sage/schemes/elliptic_curves/gal_reps_number_field.py +1663 -0
  227. sage/schemes/elliptic_curves/gp_simon.py +152 -0
  228. sage/schemes/elliptic_curves/heegner.py +7328 -0
  229. sage/schemes/elliptic_curves/height.py +2108 -0
  230. sage/schemes/elliptic_curves/hom.py +1788 -0
  231. sage/schemes/elliptic_curves/hom_composite.py +1084 -0
  232. sage/schemes/elliptic_curves/hom_fractional.py +544 -0
  233. sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
  234. sage/schemes/elliptic_curves/hom_scalar.py +531 -0
  235. sage/schemes/elliptic_curves/hom_sum.py +681 -0
  236. sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
  237. sage/schemes/elliptic_curves/homset.py +271 -0
  238. sage/schemes/elliptic_curves/isogeny_class.py +1523 -0
  239. sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
  240. sage/schemes/elliptic_curves/jacobian.py +247 -0
  241. sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
  242. sage/schemes/elliptic_curves/kraus.py +1014 -0
  243. sage/schemes/elliptic_curves/lseries_ell.py +915 -0
  244. sage/schemes/elliptic_curves/mod5family.py +105 -0
  245. sage/schemes/elliptic_curves/mod_poly.py +197 -0
  246. sage/schemes/elliptic_curves/mod_sym_num.cpython-314t-darwin.so +0 -0
  247. sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
  248. sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
  249. sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
  250. sage/schemes/elliptic_curves/padics.py +1816 -0
  251. sage/schemes/elliptic_curves/period_lattice.py +2234 -0
  252. sage/schemes/elliptic_curves/period_lattice_region.cpython-314t-darwin.so +0 -0
  253. sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
  254. sage/schemes/elliptic_curves/saturation.py +716 -0
  255. sage/schemes/elliptic_curves/sha_tate.py +1158 -0
  256. sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
  257. sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
  258. sage/schemes/hyperelliptic_curves/all.py +6 -0
  259. sage/schemes/hyperelliptic_curves/constructor.py +369 -0
  260. sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1948 -0
  261. sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
  262. sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +936 -0
  263. sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
  264. sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
  265. sage/schemes/hyperelliptic_curves/invariants.py +410 -0
  266. sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +312 -0
  267. sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
  268. sage/schemes/hyperelliptic_curves/jacobian_generic.py +437 -0
  269. sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
  270. sage/schemes/hyperelliptic_curves/jacobian_morphism.py +878 -0
  271. sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
  272. sage/schemes/hyperelliptic_curves/mestre.py +302 -0
  273. sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3863 -0
  274. sage/schemes/jacobians/abstract_jacobian.py +277 -0
  275. sage/schemes/jacobians/all.py +2 -0
  276. sage/schemes/overview.py +161 -0
  277. sage/schemes/plane_conics/all.py +22 -0
  278. sage/schemes/plane_conics/con_field.py +1296 -0
  279. sage/schemes/plane_conics/con_finite_field.py +158 -0
  280. sage/schemes/plane_conics/con_number_field.py +456 -0
  281. sage/schemes/plane_conics/con_rational_field.py +406 -0
  282. sage/schemes/plane_conics/con_rational_function_field.py +581 -0
  283. sage/schemes/plane_conics/constructor.py +249 -0
  284. sage/schemes/plane_quartics/all.py +2 -0
  285. sage/schemes/plane_quartics/quartic_constructor.py +71 -0
  286. sage/schemes/plane_quartics/quartic_generic.py +53 -0
  287. sage/schemes/riemann_surfaces/all.py +1 -0
  288. sage/schemes/riemann_surfaces/riemann_surface.py +4177 -0
  289. sage_wheels/share/cremona/cremona_mini.db +0 -0
  290. sage_wheels/share/ellcurves/rank0 +30427 -0
  291. sage_wheels/share/ellcurves/rank1 +31871 -0
  292. sage_wheels/share/ellcurves/rank10 +6 -0
  293. sage_wheels/share/ellcurves/rank11 +6 -0
  294. sage_wheels/share/ellcurves/rank12 +1 -0
  295. sage_wheels/share/ellcurves/rank14 +1 -0
  296. sage_wheels/share/ellcurves/rank15 +1 -0
  297. sage_wheels/share/ellcurves/rank17 +1 -0
  298. sage_wheels/share/ellcurves/rank19 +1 -0
  299. sage_wheels/share/ellcurves/rank2 +2388 -0
  300. sage_wheels/share/ellcurves/rank20 +1 -0
  301. sage_wheels/share/ellcurves/rank21 +1 -0
  302. sage_wheels/share/ellcurves/rank22 +1 -0
  303. sage_wheels/share/ellcurves/rank23 +1 -0
  304. sage_wheels/share/ellcurves/rank24 +1 -0
  305. sage_wheels/share/ellcurves/rank28 +1 -0
  306. sage_wheels/share/ellcurves/rank3 +836 -0
  307. sage_wheels/share/ellcurves/rank4 +10 -0
  308. sage_wheels/share/ellcurves/rank5 +5 -0
  309. sage_wheels/share/ellcurves/rank6 +5 -0
  310. sage_wheels/share/ellcurves/rank7 +5 -0
  311. sage_wheels/share/ellcurves/rank8 +6 -0
  312. sage_wheels/share/ellcurves/rank9 +7 -0
@@ -0,0 +1,1084 @@
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: p = 3 * 2^143 - 1
19
+ sage: GF(p^2).inject_variables()
20
+ Defining z2
21
+ sage: E = EllipticCurve(GF(p^2), [1,0])
22
+ sage: P = E.lift_x(31415926535897932384626433832795028841971 - z2)
23
+ sage: P.order().factor()
24
+ 2^143
25
+ sage: E.isogeny(P, algorithm="factored") # preferred API
26
+ Composite morphism of degree 11150372599265311570767859136324180752990208 = 2^143:
27
+ From: Elliptic Curve defined by y^2 = x^3 + x
28
+ over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2
29
+ To: Elliptic Curve defined by y^2 = x^3 + (18676616716352953484576727486205473216172067*z2+32690199585974925193292786311814241821808308)*x
30
+ + (3369702436351367403910078877591946300201903*z2+15227558615699041241851978605002704626689722)
31
+ over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2
32
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
33
+ sage: EllipticCurveHom_composite(E, P) # same as above but use internal API, construct the isogeny directly
34
+ Composite morphism of degree 11150372599265311570767859136324180752990208 = 2^143: ...
35
+
36
+ Yet, the interface provided by :class:`EllipticCurveHom_composite`
37
+ is identical to :class:`EllipticCurveIsogeny` and other instantiations
38
+ of :class:`EllipticCurveHom`::
39
+
40
+ sage: # needs sage.rings.finite_rings
41
+ sage: E = EllipticCurve(GF(419), [0,1])
42
+ sage: P = E.lift_x(33); P.order()
43
+ 35
44
+ sage: psi = EllipticCurveHom_composite(E, P); psi
45
+ Composite morphism of degree 35 = 5*7:
46
+ From: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 419
47
+ To: Elliptic Curve defined by y^2 = x^3 + 101*x + 285 over Finite Field of size 419
48
+ sage: psi(E.lift_x(11))
49
+ (352 : 346 : 1)
50
+ sage: psi.rational_maps()
51
+ ((x^35 + 162*x^34 + 186*x^33 + 92*x^32 - ... + 44*x^3 + 190*x^2 + 80*x
52
+ - 72)/(x^34 + 162*x^33 - 129*x^32 + 41*x^31 + ... + 66*x^3 - 191*x^2 + 119*x + 21),
53
+ (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
54
+ + 178*y)/(x^51 - 176*x^50 + 11*x^49 + 26*x^48 - ... - 77*x^3 + 185*x^2 + 169*x - 128))
55
+ sage: psi.kernel_polynomial()
56
+ x^17 + 81*x^16 + 7*x^15 + 82*x^14 + 49*x^13 + 68*x^12 + 109*x^11 + 326*x^10
57
+ + 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
58
+ sage: psi.dual()
59
+ Composite morphism of degree 35 = 7*5:
60
+ From: Elliptic Curve defined by y^2 = x^3 + 101*x + 285 over Finite Field of size 419
61
+ To: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 419
62
+ sage: psi.formal()
63
+ 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)
64
+
65
+ Equality is decided correctly (and, in some cases, much faster than
66
+ comparing :meth:`EllipticCurveHom.rational_maps`) even when distinct
67
+ factorizations of the same isogeny are compared::
68
+
69
+ sage: psi == EllipticCurveIsogeny(E, P) # needs sage.rings.finite_rings sage.symbolic
70
+ True
71
+
72
+ We can easily obtain the individual factors of the composite map::
73
+
74
+ sage: psi.factors() # needs sage.rings.finite_rings
75
+ (Isogeny of degree 5
76
+ from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 419
77
+ to Elliptic Curve defined by y^2 = x^3 + 140*x + 214 over Finite Field of size 419,
78
+ Isogeny of degree 7
79
+ from Elliptic Curve defined by y^2 = x^3 + 140*x + 214 over Finite Field of size 419
80
+ to Elliptic Curve defined by y^2 = x^3 + 101*x + 285 over Finite Field of size 419)
81
+
82
+ AUTHORS:
83
+
84
+ - Lukas Zobernig (2020): initial proof-of-concept version
85
+ - Lorenz Panny (2021): :class:`EllipticCurveHom` interface,
86
+ documentation and tests, equality testing
87
+ """
88
+
89
+ from sage.structure.richcmp import op_EQ
90
+ from sage.misc.cachefunc import cached_method
91
+ from sage.structure.sequence import Sequence
92
+
93
+ from sage.arith.misc import prod
94
+
95
+ from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic
96
+ from sage.schemes.elliptic_curves.hom import EllipticCurveHom, compare_via_evaluation
97
+ from sage.schemes.elliptic_curves.ell_curve_isogeny import EllipticCurveIsogeny
98
+ from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism, identity_morphism
99
+
100
+
101
+ def _eval_factored_isogeny(phis, P):
102
+ """
103
+ This method pushes a point `P` through a given sequence ``phis``
104
+ of compatible isogenies.
105
+
106
+ EXAMPLES::
107
+
108
+ sage: # needs sage.rings.finite_rings
109
+ sage: from sage.schemes.elliptic_curves import hom_composite
110
+ sage: E = EllipticCurve(GF(419), [1,0])
111
+ sage: Q = E(21, 8)
112
+ sage: phis = []
113
+ sage: while len(phis) < 10:
114
+ ....: P = list(sorted(E(0).division_points(7)))[1]
115
+ ....: phis.append(E.isogeny(P))
116
+ ....: E = phis[-1].codomain()
117
+ sage: R = hom_composite._eval_factored_isogeny(phis, Q); R
118
+ (290 : 183 : 1)
119
+ sage: R in E
120
+ True
121
+ """
122
+ for phi in phis:
123
+ P = phi(P)
124
+ return P
125
+
126
+
127
+ def _compute_factored_isogeny_prime_power(P, l, n, split=.8, velu_sqrt_bound=None):
128
+ r"""
129
+ This method takes a point `P` of order `\ell^n` and returns
130
+ a sequence of degree-`\ell` isogenies whose composition has
131
+ the subgroup generated by `P` as its kernel.
132
+
133
+ The optional argument ``split``, a real number between
134
+ `0` and `1`, controls the *strategy* used to compute the
135
+ isogeny: In general, the algorithm performs a number of
136
+ scalar multiplications `[\ell]` and a number of
137
+ `\ell`-isogeny evaluations, and there exist tradeoffs
138
+ between them.
139
+
140
+ - Setting ``split`` to `0` skews the algorithm towards
141
+ isogenies, minimizing multiplications.
142
+ The asymptotic complexity is `O(n \log(\ell) + n^2 \ell)`.
143
+
144
+ - Setting ``split`` to `1` skews the algorithm towards
145
+ multiplications, minimizing isogenies.
146
+ The asymptotic complexity is `O(n^2 \log(\ell) + n \ell)`.
147
+
148
+ - Values strictly between `0` and `1` define *sparse*
149
+ strategies, which balance the number of isogenies and
150
+ multiplications according to the parameter.
151
+ The asymptotic complexity is `O(n \log(n) \ell)`.
152
+
153
+ The optional parameter ``velu_sqrt_bound`` prescribes the
154
+ point in which the computation of a single isogeny should be
155
+ performed using square root Velu instead of simple Velu.
156
+
157
+ .. NOTE::
158
+
159
+ As of July 2022, good values for ``split`` range somewhere
160
+ between roughly `0.6` and `0.9`, depending on the size of
161
+ `\ell` and the cost of base-field arithmetic.
162
+
163
+ REFERENCES:
164
+
165
+ Sparse strategies were introduced in [DJP2014]_, §4.2.2.
166
+
167
+ ALGORITHM:
168
+
169
+ The splitting rule implemented here is a simple heuristic which
170
+ is usually not optimal. The advantage is that it does not rely
171
+ on prior knowledge of degrees and exact costs of elliptic-curve
172
+ arithmetic, while still working reasonably well for a fairly
173
+ wide range of situations.
174
+
175
+ EXAMPLES::
176
+
177
+ sage: # needs sage.rings.finite_rings
178
+ sage: from sage.schemes.elliptic_curves import hom_composite
179
+ sage: E = EllipticCurve(GF(8191), [1,0])
180
+ sage: P = E.random_point()
181
+ sage: (l,n), = P.order().factor()
182
+ sage: phis = hom_composite._compute_factored_isogeny_prime_power(P, l, n)
183
+ sage: hom_composite._eval_factored_isogeny(phis, P)
184
+ (0 : 1 : 0)
185
+ sage: [phi.degree() for phi in phis] == [l]*n
186
+ True
187
+
188
+ All choices of ``split`` produce the same result, albeit
189
+ not equally fast::
190
+
191
+ sage: # needs sage.rings.finite_rings, long time (:issue:`39569`)
192
+ sage: E = EllipticCurve(GF(2^127 - 1), [1,0])
193
+ sage: P, = E.gens()
194
+ sage: (l,n), = P.order().factor()
195
+ sage: phis = hom_composite._compute_factored_isogeny_prime_power(P,l,n)
196
+ sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0) # long time -- about 10s
197
+ True
198
+ sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0.1)
199
+ True
200
+ sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0.5)
201
+ True
202
+ sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=0.9)
203
+ True
204
+ sage: phis == hom_composite._compute_factored_isogeny_prime_power(P,l,n, split=1)
205
+ True
206
+ """
207
+ def rec(Q, k):
208
+
209
+ if k == 1:
210
+ # base case: Q has order l
211
+ Q._order = l # This was not cached before
212
+ return [Q.curve().isogeny(kernel=Q, velu_sqrt_bound=velu_sqrt_bound)]
213
+
214
+ # recursive case: k > 1 and Q has order l^k
215
+
216
+ k1 = int(k * split + .5)
217
+ k1 = max(1, min(k - 1, k1)) # clamp to [1, k - 1]
218
+
219
+ Q1 = l**k1 * Q
220
+ L = rec(Q1, k - k1)
221
+
222
+ Q2 = _eval_factored_isogeny(L, Q)
223
+ R = rec(Q2, k1)
224
+
225
+ return L + R
226
+
227
+ return rec(P, n)
228
+
229
+
230
+ def _compute_factored_isogeny_single_generator(P, velu_sqrt_bound=None):
231
+ """
232
+ This method takes a point `P` and returns a sequence of
233
+ prime-degree isogenies whose composition has the subgroup
234
+ generated by `P` as its kernel.
235
+
236
+ The optional parameter ``velu_sqrt_bound`` prescribes the
237
+ point in which the computation of a single isogeny should be
238
+ performed using square root Velu instead of simple Velu.
239
+
240
+ EXAMPLES::
241
+
242
+ sage: # needs sage.rings.finite_rings
243
+ sage: from sage.schemes.elliptic_curves import hom_composite
244
+ sage: E = EllipticCurve(GF(419), [1,0])
245
+ sage: P = E(42, 321)
246
+ sage: phis = hom_composite._compute_factored_isogeny_single_generator(P)
247
+ sage: list(sorted(phi.degree() for phi in phis))
248
+ [2, 2, 3, 5, 7]
249
+ sage: hom_composite._eval_factored_isogeny(phis, P)
250
+ (0 : 1 : 0)
251
+
252
+ ::
253
+
254
+ sage: from sage.schemes.elliptic_curves import hom_composite
255
+ sage: p = 3217
256
+ sage: E = EllipticCurve_from_j(GF(p)(42))
257
+ sage: P = E.gens()[0]
258
+ sage: phis = hom_composite._compute_factored_isogeny_single_generator(P, velu_sqrt_bound=50)
259
+ sage: for phi in phis:
260
+ ....: print(phi)
261
+ 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
262
+ Elliptic-curve isogeny (using square-root Vélu) of degree 103:
263
+ From: Elliptic Curve defined by y^2 = x^3 + 277*x + 1710 over Finite Field of size 3217
264
+ To: Elliptic Curve defined by y^2 = x^3 + 2979*x + 1951 over Finite Field of size 3217
265
+ """
266
+ phis = []
267
+ h = P.order()
268
+ for l,e in P.order().factor():
269
+ h //= l**e
270
+ psis = _compute_factored_isogeny_prime_power(h*P, l, e, velu_sqrt_bound=velu_sqrt_bound)
271
+ P = _eval_factored_isogeny(psis, P)
272
+ phis += psis
273
+ return phis
274
+
275
+
276
+ def _compute_factored_isogeny(kernel, velu_sqrt_bound=None):
277
+ """
278
+ This method takes a set of points on an elliptic curve
279
+ and returns a sequence of isogenies whose composition
280
+ has the subgroup generated by that subset as its kernel.
281
+
282
+ The optional parameter ``velu_sqrt_bound`` prescribes the
283
+ point in which the computation of a single isogeny should be
284
+ performed using square root Velu instead of simple Velu.
285
+
286
+ EXAMPLES::
287
+
288
+ sage: # needs sage.rings.finite_rings
289
+ sage: from sage.schemes.elliptic_curves import hom_composite
290
+ sage: E = EllipticCurve(GF(419), [-1,0])
291
+ sage: Ps = [E(41,99), E(41,-99), E(51,14), E(21,21), E(33,17)]
292
+ sage: phis = hom_composite._compute_factored_isogeny(Ps)
293
+ sage: [phi.degree() for phi in phis]
294
+ [2, 3, 5, 7, 2]
295
+ sage: {hom_composite._eval_factored_isogeny(phis, P) for P in Ps}
296
+ {(0 : 1 : 0)}
297
+ """
298
+ phis = []
299
+ ker = list(kernel)
300
+ while ker:
301
+ K = ker.pop(0)
302
+ psis = _compute_factored_isogeny_single_generator(K, velu_sqrt_bound=velu_sqrt_bound)
303
+ ker = [_eval_factored_isogeny(psis, P) for P in ker]
304
+ phis += psis
305
+ return phis
306
+
307
+
308
+ class EllipticCurveHom_composite(EllipticCurveHom):
309
+
310
+ _degree = None
311
+ _phis = None
312
+
313
+ def __init__(self, E, kernel, codomain=None, model=None, velu_sqrt_bound=None):
314
+ """
315
+ Construct a composite isogeny with given kernel (and optionally,
316
+ prescribed codomain curve). The isogeny is decomposed into steps
317
+ of prime degree.
318
+
319
+ The ``codomain`` and ``model`` parameters have the same meaning
320
+ as for :class:`EllipticCurveIsogeny`.
321
+
322
+ The optional parameter ``velu_sqrt_bound`` prescribes the point
323
+ in which the computation of a single isogeny should be performed
324
+ using square root Velu instead of simple Velu. If not provided,
325
+ the system default is used (see
326
+ :class:`EllipticCurve_field.isogeny` for a more detailed
327
+ discussion.
328
+
329
+ EXAMPLES::
330
+
331
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
332
+ sage: E = EllipticCurve(GF(419), [1,0]) # needs sage.rings.finite_rings
333
+ sage: EllipticCurveHom_composite(E, E.lift_x(23)) # needs sage.rings.finite_rings
334
+ Composite morphism of degree 105 = 3*5*7:
335
+ From: Elliptic Curve defined by y^2 = x^3 + x
336
+ over Finite Field of size 419
337
+ To: Elliptic Curve defined by y^2 = x^3 + 373*x + 126
338
+ over Finite Field of size 419
339
+
340
+ The given kernel generators need not be independent::
341
+
342
+ sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
343
+ sage: x = polygen(ZZ, 'x')
344
+ sage: K.<a> = NumberField(x^2 - x - 5)
345
+ sage: E = EllipticCurve('210.b6').change_ring(K)
346
+ sage: E.torsion_subgroup()
347
+ Torsion Subgroup isomorphic to Z/12 + Z/2 associated to the Elliptic Curve
348
+ defined by y^2 + x*y + y = x^3 + (-578)*x + 2756
349
+ over Number Field in a with defining polynomial x^2 - x - 5
350
+ sage: EllipticCurveHom_composite(E, E.torsion_points())
351
+ Composite morphism of degree 24 = 2^3*3:
352
+ From: Elliptic Curve defined by y^2 + x*y + y = x^3 + (-578)*x + 2756
353
+ over Number Field in a with defining polynomial x^2 - x - 5
354
+ To: Elliptic Curve defined by
355
+ y^2 + x*y + y = x^3 + (-89915533/16)*x + (-328200928141/64)
356
+ over Number Field in a with defining polynomial x^2 - x - 5
357
+
358
+ TESTS::
359
+
360
+ sage: E = EllipticCurve(GF(19), [1,0])
361
+ sage: P = E.random_point()
362
+ sage: psi = EllipticCurveHom_composite(E, P)
363
+ sage: psi # random
364
+ Composite morphism of degree 10 = 2*5:
365
+ From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 19
366
+ To: Elliptic Curve defined by y^2 = x^3 + 14*x over Finite Field of size 19
367
+
368
+ ::
369
+
370
+ sage: EllipticCurveHom_composite(E, E.lift_x(3), codomain=E)
371
+ Composite morphism of degree 20 = 2^2*5:
372
+ From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 19
373
+ To: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 19
374
+
375
+ ::
376
+
377
+ sage: # needs sage.rings.finite_rings
378
+ sage: E = EllipticCurve(GF((2^127-1)^2), [1,0])
379
+ sage: K = 2^30 * E.random_point()
380
+ sage: psi = EllipticCurveHom_composite(E, K, model='montgomery')
381
+ sage: psi.codomain().a_invariants()
382
+ (0, ..., 0, 1, 0)
383
+ """
384
+ if not isinstance(E, EllipticCurve_generic):
385
+ raise ValueError(f'not an elliptic curve: {E}')
386
+
387
+ if not isinstance(kernel, list) and not isinstance(kernel, tuple):
388
+ kernel = [kernel]
389
+
390
+ for P in kernel:
391
+ if P not in E:
392
+ raise ValueError(f'given point {P} does not lie on {E}')
393
+
394
+ self._phis = _compute_factored_isogeny(kernel, velu_sqrt_bound=velu_sqrt_bound)
395
+
396
+ if not self._phis:
397
+ self._phis = [identity_morphism(E)]
398
+
399
+ if model is not None:
400
+ if codomain is not None:
401
+ raise ValueError("cannot specify a codomain curve and model name simultaneously")
402
+
403
+ from sage.schemes.elliptic_curves.ell_field import compute_model
404
+ codomain = compute_model(self._phis[-1].codomain(), model)
405
+
406
+ if codomain is not None:
407
+ if not isinstance(codomain, EllipticCurve_generic):
408
+ raise ValueError(f'not an elliptic curve: {codomain}')
409
+ iso = self._phis[-1].codomain().isomorphism_to(codomain)
410
+ if hasattr(self._phis[-1], '_set_post_isomorphism'):
411
+ self._phis[-1]._set_post_isomorphism(iso)
412
+ else:
413
+ self._phis.append(iso)
414
+
415
+ self._phis = tuple(self._phis) # make immutable
416
+ self.__perform_inheritance_housekeeping()
417
+
418
+ def __perform_inheritance_housekeeping(self):
419
+ """
420
+ Internal helper function to set values of the superclass.
421
+
422
+ TESTS::
423
+
424
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
425
+ sage: E = EllipticCurve([1,0])
426
+ sage: phi = EllipticCurveHom_composite(E, E(0,0)) # implicit doctest
427
+ sage: from sage.schemes.elliptic_curves.hom import EllipticCurveHom
428
+ sage: print(EllipticCurveHom._repr_(phi))
429
+ Elliptic-curve morphism:
430
+ From: Elliptic Curve defined by y^2 = x^3 + x over Rational Field
431
+ To: Elliptic Curve defined by y^2 = x^3 - 4*x over Rational Field
432
+ sage: phi.domain()
433
+ Elliptic Curve defined by y^2 = x^3 + x over Rational Field
434
+ sage: phi.codomain()
435
+ Elliptic Curve defined by y^2 = x^3 - 4*x over Rational Field
436
+ """
437
+ self._degree = prod(phi.degree() for phi in self._phis)
438
+ self._domain = self._phis[0].domain()
439
+ self._codomain = self._phis[-1].codomain()
440
+ EllipticCurveHom.__init__(self, self._domain, self._codomain)
441
+
442
+ @classmethod
443
+ def from_factors(cls, maps, E=None, strict=True):
444
+ r"""
445
+ This method constructs a :class:`EllipticCurveHom_composite`
446
+ object encapsulating a given sequence of compatible isogenies.
447
+
448
+ The isogenies are composed in left-to-right order, i.e., the
449
+ resulting composite map equals `f_{n-1} \circ \dots \circ f_0`
450
+ where `f_i` denotes ``maps[i]``.
451
+
452
+ INPUT:
453
+
454
+ - ``maps`` -- sequence of :class:`EllipticCurveHom` objects
455
+ - ``E`` -- (optional) the domain elliptic curve
456
+ - ``strict`` -- boolean (default: ``True``); if ``True``,
457
+ always return an :class:`EllipticCurveHom_composite` object,
458
+ else may return another :class:`EllipticCurveHom` type
459
+
460
+ OUTPUT: the composite of ``maps``
461
+
462
+ EXAMPLES::
463
+
464
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
465
+ sage: E = EllipticCurve(GF(43), [1,0])
466
+ sage: P, = E.gens()
467
+ sage: phi = EllipticCurveHom_composite(E, P)
468
+ sage: psi = EllipticCurveHom_composite.from_factors(phi.factors())
469
+ sage: psi == phi # needs sage.symbolic
470
+ True
471
+
472
+ TESTS::
473
+
474
+ sage: E = EllipticCurve('4730k1')
475
+ sage: EllipticCurveHom_composite.from_factors([], E) == E.scalar_multiplication(1)
476
+ True
477
+
478
+ ::
479
+
480
+ sage: # needs sage.rings.finite_rings
481
+ sage: E = EllipticCurve(GF(419), [1,0])
482
+ sage: P, = E.gens()
483
+ sage: phi = EllipticCurveHom_composite(E, P)
484
+ sage: EllipticCurveHom_composite.from_factors(phi.factors()) == phi # needs sage.symbolic
485
+ True
486
+ """
487
+ maps = tuple(maps)
488
+ if not maps and E is None:
489
+ raise ValueError('need either factors or domain')
490
+ if E is None:
491
+ E = maps[0].domain()
492
+
493
+ for phi in maps:
494
+ if not isinstance(phi, EllipticCurveHom):
495
+ raise TypeError(f'not an elliptic-curve isogeny: {phi}')
496
+ if phi.domain() != E:
497
+ raise ValueError(f'isogeny has incorrect domain: {phi}')
498
+ E = phi.codomain()
499
+
500
+ if not maps:
501
+ maps = (identity_morphism(E),)
502
+
503
+ if len(maps) == 1 and not strict:
504
+ return maps[0]
505
+
506
+ result = cls.__new__(cls)
507
+ result._phis = maps
508
+ result.__perform_inheritance_housekeeping()
509
+ return result
510
+
511
+ def _call_(self, P):
512
+ """
513
+ Evaluate this composite isogeny at a point.
514
+
515
+ TESTS::
516
+
517
+ sage: # needs database_cremona_mini_ellcurve sage.rings.number_field
518
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
519
+ sage: x = polygen(ZZ, 'x')
520
+ sage: K.<a> = NumberField(x^2 - x - 5)
521
+ sage: E = EllipticCurve('210.b6').change_ring(K)
522
+ sage: psi = EllipticCurveHom_composite(E, E.torsion_points())
523
+ sage: R = E.lift_x(15/4 * (a+3))
524
+ sage: psi(R) # indirect doctest
525
+ (1033648757/303450 : -58397496786187/1083316500*a + 54706287407197/2166633000 : 1)
526
+
527
+ Check that copying the order over works::
528
+
529
+ sage: # needs sage.rings.finite_rings
530
+ sage: E = EllipticCurve(GF(431), [1,0])
531
+ sage: P, = E.gens()
532
+ sage: Q = 2^99*P; Q.order()
533
+ 27
534
+ sage: phi = E.isogeny(3^99*P, algorithm='factored')
535
+ sage: phi(Q)._order
536
+ 27
537
+ """
538
+ return _eval_factored_isogeny(self._phis, P)
539
+
540
+ def _eval(self, P):
541
+ r"""
542
+ Less strict evaluation method for internal use.
543
+
544
+ In particular, this can be used to evaluate ``self`` at a
545
+ point defined over an extension field.
546
+
547
+ INPUT: a sequence of 3 coordinates defining a point on ``self``
548
+
549
+ OUTPUT: the result of evaluating ``self`` at the given point
550
+
551
+ EXAMPLES::
552
+
553
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
554
+ sage: E = EllipticCurve(j=Mod(1728,419))
555
+ sage: K, = E.gens()
556
+ sage: psi = EllipticCurveHom_composite(E, 4*K)
557
+ sage: Ps = E.change_ring(GF(419**2))(0).division_points(5) # needs sage.rings.finite_rings
558
+ sage: {psi._eval(P).curve() for P in Ps} # needs sage.rings.finite_rings
559
+ {Elliptic Curve defined by y^2 = x^3 + 373*x + 126 over Finite Field in z2 of size 419^2}
560
+ """
561
+ if self._domain.defining_polynomial()(*P):
562
+ raise ValueError(f'{P} not on {self._domain}')
563
+ k = Sequence(P).universe()
564
+
565
+ Q = P
566
+ for phi in self._phis:
567
+ Q = phi._eval(Q)
568
+
569
+ return self._codomain.base_extend(k)(*Q)
570
+
571
+ def _repr_(self):
572
+ """
573
+ Return basic facts about this composite isogeny as a string.
574
+
575
+ TESTS::
576
+
577
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
578
+ sage: E = EllipticCurve(GF(43), [1,0])
579
+ sage: P, = E.gens()
580
+ sage: phi = EllipticCurveHom_composite(E, P)
581
+ sage: phi # indirect doctest
582
+ Composite morphism of degree 44 = 2^2*11:
583
+ From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43
584
+ To: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43
585
+ sage: phi * phi * phi * phi * phi * phi * phi # indirect doctest
586
+ 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:
587
+ From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43
588
+ To: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43
589
+ """
590
+ from itertools import groupby
591
+ degs = [phi.degree() for phi in self._phis]
592
+ if len(degs) == 1:
593
+ return f'Composite morphism of degree {self._degree}:' \
594
+ f'\n From: {self._domain}' \
595
+ f'\n To: {self._codomain}'
596
+ grouped = [(d, sum(1 for _ in g)) for d,g in groupby(degs)]
597
+ degs_str = '*'.join(str(d) + (f'^{e}' if e > 1 else '') for d,e in grouped)
598
+ return f'Composite morphism of degree {self._degree} = {degs_str}:' \
599
+ f'\n From: {self._domain}' \
600
+ f'\n To: {self._codomain}'
601
+
602
+ def factors(self):
603
+ r"""
604
+ Return the factors of this composite isogeny as a tuple.
605
+
606
+ The isogenies are returned in left-to-right order, i.e.,
607
+ the returned tuple `(f_1,...,f_n)` corresponds to the map
608
+ `f_n \circ \dots \circ f_1`.
609
+
610
+ EXAMPLES::
611
+
612
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
613
+ sage: E = EllipticCurve(GF(43), [1,0])
614
+ sage: P, = E.gens()
615
+ sage: phi = EllipticCurveHom_composite(E, P)
616
+ sage: phi.factors()
617
+ (Isogeny of degree 2
618
+ from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43
619
+ to Elliptic Curve defined by y^2 = x^3 + 39*x over Finite Field of size 43,
620
+ Isogeny of degree 2
621
+ from Elliptic Curve defined by y^2 = x^3 + 39*x over Finite Field of size 43
622
+ to Elliptic Curve defined by y^2 = x^3 + 42*x + 26 over Finite Field of size 43,
623
+ Isogeny of degree 11
624
+ from Elliptic Curve defined by y^2 = x^3 + 42*x + 26 over Finite Field of size 43
625
+ to Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 43)
626
+ """
627
+ return self._phis
628
+
629
+ # EllipticCurveHom methods
630
+
631
+ @staticmethod
632
+ def _composition_impl(left, right):
633
+ """
634
+ Helper method to compose other elliptic-curve morphisms with
635
+ :class:`EllipticCurveHom_composite` objects. Called by
636
+ :meth:`EllipticCurveHom._composition_`.
637
+
638
+ TESTS::
639
+
640
+ sage: # needs sage.rings.number_field
641
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
642
+ sage: E = EllipticCurve([i + 1, i, 0, -4, -6*i])
643
+ sage: P,Q = E.lift_x(i - 5), E.lift_x(-4*i)
644
+ sage: phi = EllipticCurveHom_composite(E, P)
645
+ sage: psi = phi.codomain().isogeny(phi(Q))
646
+ sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism
647
+ sage: iso1 = WeierstrassIsomorphism(E, (-1, 0, -i - 1, 0))
648
+ sage: iso2 = psi.codomain().isomorphism_to(E)
649
+ sage: psi * phi # indirect doctest
650
+ Composite morphism of degree 16 = 2^2*4:
651
+ From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I)
652
+ over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
653
+ To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-3331/4)*x + (-142593/8*I)
654
+ over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
655
+ sage: iso2 * EllipticCurveHom_composite.from_factors([phi, psi]) # indirect doctest
656
+ Composite morphism of degree 16 = 4^2:
657
+ From: 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
+ To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I)
660
+ over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
661
+ sage: phi * iso1 # indirect doctest
662
+ Composite morphism of degree 4 = 2^2:
663
+ From: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I)
664
+ over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
665
+ To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (480*I-694)*x + (-7778*I+5556)
666
+ over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
667
+ sage: iso2 * psi * phi * iso1 # indirect doctest
668
+ Composite morphism of degree 16 = 2^2*4:
669
+ From: 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
+ To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I)
672
+ over Number Field in I with defining polynomial x^2 + 1 with I = 1*I
673
+ """
674
+ if isinstance(left, EllipticCurveHom_composite):
675
+ if isinstance(right, WeierstrassIsomorphism) and hasattr(left.factors()[0], '_set_pre_isomorphism'): # XXX bit of a hack
676
+ return EllipticCurveHom_composite.from_factors((left.factors()[0] * right,) + left.factors()[1:], strict=False)
677
+ if isinstance(right, EllipticCurveHom_composite):
678
+ return EllipticCurveHom_composite.from_factors(right.factors() + left.factors())
679
+ if isinstance(right, EllipticCurveHom):
680
+ return EllipticCurveHom_composite.from_factors((right,) + left.factors())
681
+ if isinstance(right, EllipticCurveHom_composite):
682
+ if isinstance(left, WeierstrassIsomorphism) and hasattr(right.factors()[-1], '_set_post_isomorphism'): # XXX bit of a hack
683
+ return EllipticCurveHom_composite.from_factors(right.factors()[:-1] + (left * right.factors()[-1],), strict=False)
684
+ if isinstance(left, EllipticCurveHom):
685
+ return EllipticCurveHom_composite.from_factors(right.factors() + (left,))
686
+ return NotImplemented
687
+
688
+ @staticmethod
689
+ def _comparison_impl(left, right, op):
690
+ r"""
691
+ Compare a composite isogeny to another elliptic-curve morphism.
692
+
693
+ Called by :meth:`EllipticCurveHom._richcmp_`.
694
+
695
+ ALGORITHM:
696
+
697
+ If possible, we use
698
+ :func:`~sage.schemes.elliptic_curves.hom.compare_via_evaluation`.
699
+ The complexity in that case is polynomial in the representation
700
+ size of this morphism.
701
+
702
+ TESTS::
703
+
704
+ sage: # needs sage.rings.number_field
705
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
706
+ sage: E = EllipticCurve(QuadraticField(-3), [0,16])
707
+ sage: P,Q = E.lift_x(0), E.lift_x(-4)
708
+ sage: phi = EllipticCurveHom_composite(E, P)
709
+ sage: psi = phi.codomain().isogeny(phi(Q))
710
+ sage: psi = psi.codomain().isomorphism_to(E) * psi
711
+ sage: comp = psi * phi
712
+ sage: mu = E.scalar_multiplication(phi.degree())
713
+ sage: sum(a*comp == mu for a in E.automorphisms())
714
+ 1
715
+
716
+ ::
717
+
718
+ sage: # needs sage.rings.finite_rings sage.rings.number_field sage.symbolic
719
+ sage: E = EllipticCurve(GF(431**2), [1,0])
720
+ sage: P,Q = E.gens()
721
+ sage: phi1 = EllipticCurveHom_composite(E, P)
722
+ sage: phi2 = EllipticCurveHom_composite(phi1.codomain(), phi1(Q))
723
+ sage: psi1 = EllipticCurveHom_composite(E, Q)
724
+ sage: psi2 = EllipticCurveHom_composite(psi1.codomain(), psi1(P))
725
+ sage: phi2 * phi1 == psi2 * psi1
726
+ True
727
+ """
728
+ if op != op_EQ:
729
+ return NotImplemented
730
+ try:
731
+ return compare_via_evaluation(left, right)
732
+ except NotImplementedError:
733
+ return NotImplemented
734
+
735
+ def rational_maps(self):
736
+ """
737
+ Return the pair of explicit rational maps defining this composite
738
+ isogeny.
739
+
740
+ EXAMPLES::
741
+
742
+ sage: # needs sage.rings.finite_rings
743
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
744
+ sage: E = EllipticCurve(GF(65537), [1,2,3,4,5])
745
+ sage: P = E.lift_x(7321)
746
+ sage: phi = EllipticCurveHom_composite(E, P)
747
+ sage: phi.rational_maps()
748
+ ((x^9 + 27463*x^8 + 21204*x^7 - 5750*x^6 + 1610*x^5 + 14440*x^4
749
+ + 26605*x^3 - 15569*x^2 - 3341*x + 1267)/(x^8 + 27463*x^7 + 26871*x^6
750
+ + 5999*x^5 - 20194*x^4 - 6310*x^3 + 24366*x^2 - 20905*x - 13867),
751
+ (x^12*y + 8426*x^11*y + 5667*x^11 + 27612*x^10*y + 26124*x^10 + 9688*x^9*y
752
+ - 22715*x^9 + 19864*x^8*y + 498*x^8 + 22466*x^7*y - 14036*x^7 + 8070*x^6*y
753
+ + 19955*x^6 - 20765*x^5*y - 12481*x^5 + 12672*x^4*y + 24142*x^4 - 23695*x^3*y
754
+ + 26667*x^3 + 23780*x^2*y + 17864*x^2 + 15053*x*y - 30118*x + 17539*y
755
+ - 23609)/(x^12 + 8426*x^11 + 21945*x^10 - 22587*x^9 + 22094*x^8 + 14603*x^7
756
+ - 26255*x^6 + 11171*x^5 - 16508*x^4 - 14435*x^3 - 2170*x^2 + 29081*x - 19009))
757
+
758
+ TESTS::
759
+
760
+ sage: f = phi.codomain().defining_polynomial() # needs sage.rings.finite_rings
761
+ sage: g = E.defining_polynomial().subs({2:1}) # needs sage.rings.finite_rings
762
+ sage: f(*phi.rational_maps(), 1) % g # needs sage.rings.finite_rings
763
+ 0
764
+
765
+ ::
766
+
767
+ sage: phi.rational_maps()[0].parent() # needs sage.rings.finite_rings
768
+ Fraction Field of
769
+ Multivariate Polynomial Ring in x, y over Finite Field of size 65537
770
+ sage: phi.rational_maps()[1].parent() # needs sage.rings.finite_rings
771
+ Fraction Field of
772
+ Multivariate Polynomial Ring in x, y over Finite Field of size 65537
773
+ """
774
+ fx, fy = self._phis[-1].rational_maps()
775
+ for phi in self._phis[:-1][::-1]:
776
+ gx, gy = phi.rational_maps()
777
+ fx, fy = fx(gx, gy), fy(gx, gy)
778
+ return (fx, fy)
779
+
780
+ def x_rational_map(self):
781
+ """
782
+ Return the `x`-coordinate rational map of this composite isogeny.
783
+
784
+ EXAMPLES::
785
+
786
+ sage: # needs sage.rings.finite_rings
787
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
788
+ sage: E = EllipticCurve(GF(65537), [1,2,3,4,5])
789
+ sage: P = E.lift_x(7321)
790
+ sage: phi = EllipticCurveHom_composite(E, P)
791
+ sage: phi.x_rational_map() == phi.rational_maps()[0]
792
+ True
793
+
794
+ TESTS::
795
+
796
+ sage: phi.x_rational_map().parent() # needs sage.rings.finite_rings
797
+ Fraction Field of Univariate Polynomial Ring in x
798
+ over Finite Field of size 65537
799
+ """
800
+ fx = self._phis[-1].x_rational_map()
801
+ for phi in self._phis[:-1][::-1]:
802
+ fx = fx(phi.x_rational_map())
803
+ return fx
804
+
805
+ def kernel_polynomial(self):
806
+ """
807
+ Return the kernel polynomial of this composite isogeny.
808
+
809
+ EXAMPLES::
810
+
811
+ sage: # needs sage.rings.finite_rings
812
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
813
+ sage: E = EllipticCurve(GF(65537), [1,2,3,4,5])
814
+ sage: P = E.lift_x(7321)
815
+ sage: phi = EllipticCurveHom_composite(E, P); phi
816
+ Composite morphism of degree 9 = 3^2:
817
+ From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5
818
+ over Finite Field of size 65537
819
+ To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 28339*x + 59518
820
+ over Finite Field of size 65537
821
+ sage: phi.kernel_polynomial()
822
+ x^4 + 46500*x^3 + 19556*x^2 + 7643*x + 15952
823
+ """
824
+ # shouldn't there be a better algorithm for this?
825
+ return self.x_rational_map().denominator().radical()
826
+
827
+ @cached_method
828
+ def dual(self):
829
+ """
830
+ Return the dual of this composite isogeny.
831
+
832
+ EXAMPLES::
833
+
834
+ sage: # needs sage.rings.finite_rings
835
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
836
+ sage: E = EllipticCurve(GF(65537), [1,2,3,4,5])
837
+ sage: P = E.lift_x(7321)
838
+ sage: phi = EllipticCurveHom_composite(E, P); phi
839
+ Composite morphism of degree 9 = 3^2:
840
+ From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5
841
+ over Finite Field of size 65537
842
+ To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 28339*x + 59518
843
+ over Finite Field of size 65537
844
+ sage: psi = phi.dual(); psi
845
+ Composite morphism of degree 9 = 3^2:
846
+ From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 28339*x + 59518
847
+ over Finite Field of size 65537
848
+ To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 4*x + 5
849
+ over Finite Field of size 65537
850
+ sage: psi * phi == phi.domain().scalar_multiplication(phi.degree()) # needs sage.symbolic
851
+ True
852
+ sage: phi * psi == psi.domain().scalar_multiplication(psi.degree()) # needs sage.symbolic
853
+ True
854
+ """
855
+ phis = (phi.dual() for phi in self._phis[::-1])
856
+ return EllipticCurveHom_composite.from_factors(phis)
857
+
858
+ def formal(self, prec=20):
859
+ """
860
+ Return the formal isogeny corresponding to this composite
861
+ isogeny as a power series in the variable `t=-x/y` on the
862
+ domain curve.
863
+
864
+ EXAMPLES::
865
+
866
+ sage: # needs sage.rings.finite_rings
867
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
868
+ sage: E = EllipticCurve(GF(65537), [1,2,3,4,5])
869
+ sage: P = E.lift_x(7321)
870
+ sage: phi = EllipticCurveHom_composite(E, P)
871
+ sage: phi.formal()
872
+ t + 54203*t^5 + 48536*t^6 + 40698*t^7 + 37808*t^8 + 21111*t^9 + 42381*t^10
873
+ + 46688*t^11 + 657*t^12 + 38916*t^13 + 62261*t^14 + 59707*t^15
874
+ + 30767*t^16 + 7248*t^17 + 60287*t^18 + 50451*t^19 + 38305*t^20
875
+ + 12312*t^21 + 31329*t^22 + O(t^23)
876
+ sage: (phi.dual() * phi).formal(prec=5)
877
+ 9*t + 65501*t^2 + 65141*t^3 + 59183*t^4 + 21491*t^5 + 8957*t^6
878
+ + 999*t^7 + O(t^8)
879
+ """
880
+ res = self._phis[-1].formal(prec=prec)
881
+ for phi in self._phis[:-1][::-1]:
882
+ res = res(phi.formal(prec=prec))
883
+ return res
884
+
885
+ def scaling_factor(self):
886
+ r"""
887
+ Return the Weierstrass scaling factor associated to this
888
+ composite morphism.
889
+
890
+ The scaling factor is the constant `u` (in the base field)
891
+ such that `\varphi^* \omega_2 = u \omega_1`, where
892
+ `\varphi: E_1\to E_2` is this morphism and `\omega_i` are
893
+ the standard Weierstrass differentials on `E_i` defined by
894
+ `\mathrm dx/(2y+a_1x+a_3)`.
895
+
896
+ EXAMPLES::
897
+
898
+ sage: # needs sage.rings.finite_rings
899
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
900
+ sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism
901
+ sage: E = EllipticCurve(GF(65537), [1,2,3,4,5])
902
+ sage: P = E.lift_x(7321)
903
+ sage: phi = EllipticCurveHom_composite(E, P)
904
+ sage: phi = WeierstrassIsomorphism(phi.codomain(), [7,8,9,10]) * phi
905
+ sage: phi.formal()
906
+ 7*t + 65474*t^2 + 511*t^3 + 61316*t^4 + 20548*t^5 + 45511*t^6 + 37285*t^7
907
+ + 48414*t^8 + 9022*t^9 + 24025*t^10 + 35986*t^11 + 55397*t^12 + 25199*t^13
908
+ + 18744*t^14 + 46142*t^15 + 9078*t^16 + 18030*t^17 + 47599*t^18
909
+ + 12158*t^19 + 50630*t^20 + 56449*t^21 + 43320*t^22 + O(t^23)
910
+ sage: phi.scaling_factor()
911
+ 7
912
+
913
+ ALGORITHM: The scaling factor is multiplicative under
914
+ composition, so we return the product of the individual
915
+ scaling factors associated to each factor.
916
+ """
917
+ return prod(phi.scaling_factor() for phi in self._phis)
918
+
919
+ def inseparable_degree(self):
920
+ r"""
921
+ Return the inseparable degree of this morphism.
922
+
923
+ Like the degree, the inseparable degree is multiplicative
924
+ under composition, so this method returns the product of
925
+ the inseparable degrees of the factors.
926
+
927
+ EXAMPLES::
928
+
929
+ sage: E = EllipticCurve(j=GF(11^5).random_element())
930
+ sage: phi = E.frobenius_isogeny(2) * E.scalar_multiplication(77)
931
+ sage: type(phi)
932
+ <class 'sage.schemes.elliptic_curves.hom_composite.EllipticCurveHom_composite'>
933
+ sage: phi.inseparable_degree()
934
+ 1331
935
+ """
936
+ return prod(phi.inseparable_degree() for phi in self._phis)
937
+
938
+ @property
939
+ def _rest(self):
940
+ """
941
+ Internal property such that ``self == self._rest * self._phis[0]``.
942
+
943
+ TESTS::
944
+
945
+ sage: E.<P, Q> = EllipticCurve(GF(5^2), [1, 2, 3, 3, 1])
946
+ sage: f = E.isogeny([P*3, Q*3])
947
+ sage: assert f == f._rest * f._phis[0]
948
+ """
949
+ return EllipticCurveHom_composite.from_factors(self._phis[1:], strict=False)
950
+
951
+ def kernel_points(self):
952
+ """
953
+ Return an iterator over the points in the kernel of this
954
+ elliptic-curve morphism.
955
+
956
+ EXAMPLES::
957
+
958
+ sage: E.<P, Q> = EllipticCurve(GF(5^2), [1, 2, 3, 3, 1])
959
+ sage: f = E.isogeny([P*3, Q*3])
960
+ sage: f
961
+ Composite morphism of degree 4 = 2^2:
962
+ From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 3*x + 1 over Finite Field in z2 of size 5^2
963
+ To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 3*x + 3 over Finite Field in z2 of size 5^2
964
+ sage: set(f.kernel_points())
965
+ {(0 : 1 : 0), (4 : 4 : 1), (2*z2 + 4 : 4*z2 + 4 : 1), (3*z2 + 1 : z2 + 3 : 1)}
966
+ """
967
+ yield from self.inverse_image(self.codomain().zero(), all=True)
968
+
969
+ def inverse_image(self, Q, /, *, all=False):
970
+ """
971
+ Return an arbitrary element ``P`` in the domain such that
972
+ ``self(P) == Q``, or raise ``ValueError`` if no such
973
+ element exists.
974
+
975
+ INPUT:
976
+
977
+ - ``Q`` -- a point
978
+ - ``all`` -- boolean; if ``True``, returns an iterator over all points
979
+ in the inverse image
980
+
981
+ EXAMPLES::
982
+
983
+ sage: E.<P, Q> = EllipticCurve(GF(5^2), [1, 2, 3, 3, 1])
984
+ sage: f = E.isogeny([P*3, Q*3])
985
+ sage: f
986
+ Composite morphism of degree 4 = 2^2:
987
+ From: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 3*x + 1 over Finite Field in z2 of size 5^2
988
+ To: Elliptic Curve defined by y^2 + x*y + 3*y = x^3 + 2*x^2 + 3*x + 3 over Finite Field in z2 of size 5^2
989
+ sage: f(f.inverse_image(f(Q))) == f(Q)
990
+ True
991
+ sage: E.scalar_multiplication(-1).inverse_image(P) == -P
992
+ True
993
+ sage: f.inverse_image(f.codomain().0)
994
+ Traceback (most recent call last):
995
+ ...
996
+ ValueError...
997
+ sage: len(list(f.inverse_image(f(Q), all=True)))
998
+ 4
999
+
1000
+ Test a large example. It should finish in a few seconds::
1001
+
1002
+ sage: p = 3 * 2^143 - 1
1003
+ sage: GF(p^2).inject_variables()
1004
+ Defining z2
1005
+ sage: E = EllipticCurve(GF(p^2), [1,0])
1006
+ sage: P = E.lift_x(31415926535897932384626433832795028841971 - z2)
1007
+ sage: f = E.isogeny(P, algorithm="factored")
1008
+ sage: Q = f(E.lift_x(2718281828459045235360287471352662497757 - z2)); Q
1009
+ (14253459515090351074737629944491750308703143*z2 + 17548601963968266930680314841240982076784493 : ... : 1)
1010
+ sage: f.inverse_image(Q) # long time
1011
+ (...)
1012
+
1013
+ TESTS:
1014
+
1015
+ Normally, a :class:`EllipticCurveHom_composite` has ``len(self._phis) > 1``,
1016
+ but if :meth:`from_factors` is called with ``strict=True``, or if the user
1017
+ constructs a :class:`EllipticCurveHom_composite` object directly, then it is
1018
+ possible to violate this condition. We test for this case::
1019
+
1020
+ sage: E.<P> = EllipticCurve(GF(5), [1, 2])
1021
+ sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite
1022
+ sage: f = EllipticCurveHom_composite(E, P*2); f
1023
+ Composite morphism of degree 2:
1024
+ From: Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 5
1025
+ To: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 5
1026
+ sage: len(f._phis)
1027
+ 1
1028
+ sage: f(f.inverse_image(f(P))) == f(P)
1029
+ True
1030
+ sage: set(f.inverse_image(f(P), all=True))
1031
+ {(1 : 2 : 1), (1 : 3 : 1)}
1032
+
1033
+ The current implementation guarantees :attr:`_phis` is not empty::
1034
+
1035
+ sage: f = EllipticCurveHom_composite.from_factors((), E); f
1036
+ Composite morphism of degree 1:
1037
+ From: Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 5
1038
+ To: Elliptic Curve defined by y^2 = x^3 + x + 2 over Finite Field of size 5
1039
+ sage: len(f._phis)
1040
+ 1
1041
+ sage: f.inverse_image(P) == P
1042
+ True
1043
+ """
1044
+ if len(self._phis) == 1:
1045
+ return self._phis[0].inverse_image(Q, all=all)
1046
+ if all:
1047
+ return (R for P in self._rest.inverse_image(Q, all=True) for R in self._phis[0].inverse_image(P, all=True))
1048
+ try:
1049
+ return next(self.inverse_image(Q, all=True))
1050
+ except StopIteration:
1051
+ raise ValueError
1052
+
1053
+ def push_subgroup(self, f):
1054
+ r"""
1055
+ Given a minimal polynomial (see :meth:`~EllipticCurveHom.minimal_polynomial`)
1056
+ of a subgroup `G` of the domain curve of this isogeny, return a minimal polynomial
1057
+ of the image of `G` under this isogeny.
1058
+
1059
+ ALGORITHM: iterative :meth:`EllipticCurveHom.push_subgroup()`
1060
+
1061
+ EXAMPLES::
1062
+
1063
+ sage: E = EllipticCurve(GF((2^61-1, 2)), [1,0])
1064
+ sage: phi = next(E.isogenies_degree(7)); phi
1065
+ Isogeny of degree 7
1066
+ from Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 2305843009213693951^2
1067
+ to Elliptic Curve defined by y^2 = x^3 + (595688734420561721*z2+584021682365204922)*x + (2058397526093132314*z2+490140893682260802) over Finite Field in z2 of size 2305843009213693951^2
1068
+ sage: psi = E.isogeny(E.lift_x(48), algorithm='factored'); psi
1069
+ Composite morphism of degree 36028797018963968 = 2^55:
1070
+ From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 2305843009213693951^2
1071
+ To: Elliptic Curve defined by y^2 = x^3 + 938942632807894005*x + 1238942515234646252 over Finite Field in z2 of size 2305843009213693951^2
1072
+ sage: f = phi.minimal_polynomial()
1073
+ sage: g = psi.push_subgroup(f)
1074
+ sage: h = psi.codomain().kernel_polynomial_from_divisor(g, phi.degree())
1075
+ sage: chi = psi.codomain().isogeny(h); chi
1076
+ Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 938942632807894005*x + 1238942515234646252 over Finite Field in z2 of size 2305843009213693951^2 to Elliptic Curve defined by y^2 = x^3 + (1406897314822267524*z2+1659665944678449850)*x + (650305521764753329*z2+1047269804324934563) over Finite Field in z2 of size 2305843009213693951^2
1077
+ sage: x = phi.kernel_polynomial().any_root()
1078
+ sage: K = E.change_ring(E.base_field().extension(2)).lift_x(x)
1079
+ sage: (chi * psi)._eval(K)
1080
+ (0 : 1 : 0)
1081
+ """
1082
+ for phi in self.factors():
1083
+ f = phi.push_subgroup(f)
1084
+ return f