passagemath-schemes 10.6.47__cp312-cp312-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 (311) 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.6.47.dist-info/METADATA +204 -0
  7. passagemath_schemes-10.6.47.dist-info/METADATA.bak +205 -0
  8. passagemath_schemes-10.6.47.dist-info/RECORD +311 -0
  9. passagemath_schemes-10.6.47.dist-info/WHEEL +6 -0
  10. passagemath_schemes-10.6.47.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 +9558 -0
  24. sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-312-darwin.so +0 -0
  25. sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
  26. sage/dynamics/arithmetic_dynamics/wehlerK3.py +2576 -0
  27. sage/lfunctions/all.py +18 -0
  28. sage/lfunctions/dokchitser.py +745 -0
  29. sage/lfunctions/pari.py +818 -0
  30. sage/lfunctions/zero_sums.cpython-312-darwin.so +0 -0
  31. sage/lfunctions/zero_sums.pyx +1847 -0
  32. sage/modular/abvar/abvar.py +5135 -0
  33. sage/modular/abvar/abvar_ambient_jacobian.py +413 -0
  34. sage/modular/abvar/abvar_newform.py +244 -0
  35. sage/modular/abvar/all.py +8 -0
  36. sage/modular/abvar/constructor.py +186 -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 +720 -0
  40. sage/modular/abvar/homspace.py +998 -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 +740 -0
  45. sage/modular/all.py +43 -0
  46. sage/modular/arithgroup/all.py +20 -0
  47. sage/modular/arithgroup/arithgroup_element.cpython-312-darwin.so +0 -0
  48. sage/modular/arithgroup/arithgroup_element.pyx +474 -0
  49. sage/modular/arithgroup/arithgroup_generic.py +1402 -0
  50. sage/modular/arithgroup/arithgroup_perm.py +2692 -0
  51. sage/modular/arithgroup/congroup.cpython-312-darwin.so +0 -0
  52. sage/modular/arithgroup/congroup.pyx +334 -0
  53. sage/modular/arithgroup/congroup_gamma.py +363 -0
  54. sage/modular/arithgroup/congroup_gamma0.py +692 -0
  55. sage/modular/arithgroup/congroup_gamma1.py +653 -0
  56. sage/modular/arithgroup/congroup_gammaH.py +1469 -0
  57. sage/modular/arithgroup/congroup_generic.py +628 -0
  58. sage/modular/arithgroup/congroup_sl2z.py +267 -0
  59. sage/modular/arithgroup/farey_symbol.cpython-312-darwin.so +0 -0
  60. sage/modular/arithgroup/farey_symbol.pyx +1066 -0
  61. sage/modular/arithgroup/tests.py +418 -0
  62. sage/modular/btquotients/all.py +4 -0
  63. sage/modular/btquotients/btquotient.py +3753 -0
  64. sage/modular/btquotients/pautomorphicform.py +2570 -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 +1109 -0
  69. sage/modular/cusps_nf.py +1270 -0
  70. sage/modular/dims.py +569 -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 +1065 -0
  77. sage/modular/hecke/algebra.py +746 -0
  78. sage/modular/hecke/all.py +20 -0
  79. sage/modular/hecke/ambient_module.py +1019 -0
  80. sage/modular/hecke/degenmap.py +119 -0
  81. sage/modular/hecke/element.py +325 -0
  82. sage/modular/hecke/hecke_operator.py +780 -0
  83. sage/modular/hecke/homspace.py +206 -0
  84. sage/modular/hecke/module.py +1767 -0
  85. sage/modular/hecke/morphism.py +174 -0
  86. sage/modular/hecke/submodule.py +989 -0
  87. sage/modular/hypergeometric_misc.cpython-312-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 +2017 -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 +1071 -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 +815 -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 +124 -0
  101. sage/modular/modform/ambient_g1.py +204 -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 +505 -0
  106. sage/modular/modform/eisenstein_submodule.py +663 -0
  107. sage/modular/modform/element.py +4131 -0
  108. sage/modular/modform/find_generators.py +59 -0
  109. sage/modular/modform/half_integral.py +154 -0
  110. sage/modular/modform/hecke_operator_on_qexp.py +247 -0
  111. sage/modular/modform/j_invariant.py +47 -0
  112. sage/modular/modform/l_series_gross_zagier.py +133 -0
  113. sage/modular/modform/l_series_gross_zagier_coeffs.cpython-312-darwin.so +0 -0
  114. sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
  115. sage/modular/modform/notes.py +45 -0
  116. sage/modular/modform/numerical.py +514 -0
  117. sage/modular/modform/periods.py +14 -0
  118. sage/modular/modform/ring.py +1257 -0
  119. sage/modular/modform/space.py +1860 -0
  120. sage/modular/modform/submodule.py +118 -0
  121. sage/modular/modform/tests.py +64 -0
  122. sage/modular/modform/theta.py +110 -0
  123. sage/modular/modform/vm_basis.py +381 -0
  124. sage/modular/modform/weight1.py +220 -0
  125. sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
  126. sage/modular/modform_hecketriangle/abstract_space.py +2528 -0
  127. sage/modular/modform_hecketriangle/all.py +30 -0
  128. sage/modular/modform_hecketriangle/analytic_type.py +590 -0
  129. sage/modular/modform_hecketriangle/constructor.py +416 -0
  130. sage/modular/modform_hecketriangle/element.py +351 -0
  131. sage/modular/modform_hecketriangle/functors.py +752 -0
  132. sage/modular/modform_hecketriangle/graded_ring.py +541 -0
  133. sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
  134. sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3352 -0
  135. sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1432 -0
  136. sage/modular/modform_hecketriangle/readme.py +1214 -0
  137. sage/modular/modform_hecketriangle/series_constructor.py +580 -0
  138. sage/modular/modform_hecketriangle/space.py +1037 -0
  139. sage/modular/modform_hecketriangle/subspace.py +423 -0
  140. sage/modular/modsym/all.py +17 -0
  141. sage/modular/modsym/ambient.py +3846 -0
  142. sage/modular/modsym/boundary.py +1420 -0
  143. sage/modular/modsym/element.py +336 -0
  144. sage/modular/modsym/g1list.py +178 -0
  145. sage/modular/modsym/ghlist.py +182 -0
  146. sage/modular/modsym/hecke_operator.py +73 -0
  147. sage/modular/modsym/manin_symbol.cpython-312-darwin.so +0 -0
  148. sage/modular/modsym/manin_symbol.pxd +5 -0
  149. sage/modular/modsym/manin_symbol.pyx +497 -0
  150. sage/modular/modsym/manin_symbol_list.py +1295 -0
  151. sage/modular/modsym/modsym.py +400 -0
  152. sage/modular/modsym/modular_symbols.py +384 -0
  153. sage/modular/modsym/p1list_nf.py +1241 -0
  154. sage/modular/modsym/relation_matrix.py +591 -0
  155. sage/modular/modsym/relation_matrix_pyx.cpython-312-darwin.so +0 -0
  156. sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
  157. sage/modular/modsym/space.py +2468 -0
  158. sage/modular/modsym/subspace.py +455 -0
  159. sage/modular/modsym/tests.py +375 -0
  160. sage/modular/multiple_zeta.py +2632 -0
  161. sage/modular/multiple_zeta_F_algebra.py +786 -0
  162. sage/modular/overconvergent/all.py +6 -0
  163. sage/modular/overconvergent/genus0.py +1878 -0
  164. sage/modular/overconvergent/hecke_series.py +1187 -0
  165. sage/modular/overconvergent/weightspace.py +778 -0
  166. sage/modular/pollack_stevens/all.py +4 -0
  167. sage/modular/pollack_stevens/distributions.py +874 -0
  168. sage/modular/pollack_stevens/fund_domain.py +1572 -0
  169. sage/modular/pollack_stevens/manin_map.py +859 -0
  170. sage/modular/pollack_stevens/modsym.py +1593 -0
  171. sage/modular/pollack_stevens/padic_lseries.py +417 -0
  172. sage/modular/pollack_stevens/sigma0.py +534 -0
  173. sage/modular/pollack_stevens/space.py +1076 -0
  174. sage/modular/quasimodform/all.py +3 -0
  175. sage/modular/quasimodform/element.py +845 -0
  176. sage/modular/quasimodform/ring.py +828 -0
  177. sage/modular/quatalg/all.py +3 -0
  178. sage/modular/quatalg/brandt.py +1642 -0
  179. sage/modular/ssmod/all.py +8 -0
  180. sage/modular/ssmod/ssmod.py +827 -0
  181. sage/rings/all__sagemath_schemes.py +1 -0
  182. sage/rings/polynomial/all__sagemath_schemes.py +1 -0
  183. sage/rings/polynomial/binary_form_reduce.py +585 -0
  184. sage/schemes/all.py +41 -0
  185. sage/schemes/berkovich/all.py +6 -0
  186. sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
  187. sage/schemes/berkovich/berkovich_space.py +748 -0
  188. sage/schemes/curves/affine_curve.py +2928 -0
  189. sage/schemes/curves/all.py +33 -0
  190. sage/schemes/curves/closed_point.py +434 -0
  191. sage/schemes/curves/constructor.py +381 -0
  192. sage/schemes/curves/curve.py +542 -0
  193. sage/schemes/curves/plane_curve_arrangement.py +1283 -0
  194. sage/schemes/curves/point.py +463 -0
  195. sage/schemes/curves/projective_curve.py +3026 -0
  196. sage/schemes/curves/zariski_vankampen.py +1932 -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 +1036 -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 +1102 -0
  208. sage/schemes/elliptic_curves/constructor.py +1552 -0
  209. sage/schemes/elliptic_curves/ec_database.py +175 -0
  210. sage/schemes/elliptic_curves/ell_curve_isogeny.py +3972 -0
  211. sage/schemes/elliptic_curves/ell_egros.py +459 -0
  212. sage/schemes/elliptic_curves/ell_field.py +2836 -0
  213. sage/schemes/elliptic_curves/ell_finite_field.py +3359 -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 +4787 -0
  220. sage/schemes/elliptic_curves/ell_rational_field.py +7368 -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 +1669 -0
  227. sage/schemes/elliptic_curves/gp_simon.py +152 -0
  228. sage/schemes/elliptic_curves/heegner.py +7335 -0
  229. sage/schemes/elliptic_curves/height.py +2109 -0
  230. sage/schemes/elliptic_curves/hom.py +1406 -0
  231. sage/schemes/elliptic_curves/hom_composite.py +934 -0
  232. sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
  233. sage/schemes/elliptic_curves/hom_scalar.py +531 -0
  234. sage/schemes/elliptic_curves/hom_sum.py +682 -0
  235. sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
  236. sage/schemes/elliptic_curves/homset.py +271 -0
  237. sage/schemes/elliptic_curves/isogeny_class.py +1521 -0
  238. sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
  239. sage/schemes/elliptic_curves/jacobian.py +237 -0
  240. sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
  241. sage/schemes/elliptic_curves/kraus.py +1014 -0
  242. sage/schemes/elliptic_curves/lseries_ell.py +943 -0
  243. sage/schemes/elliptic_curves/mod5family.py +105 -0
  244. sage/schemes/elliptic_curves/mod_poly.py +197 -0
  245. sage/schemes/elliptic_curves/mod_sym_num.cpython-312-darwin.so +0 -0
  246. sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
  247. sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
  248. sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
  249. sage/schemes/elliptic_curves/padics.py +1816 -0
  250. sage/schemes/elliptic_curves/period_lattice.py +2234 -0
  251. sage/schemes/elliptic_curves/period_lattice_region.cpython-312-darwin.so +0 -0
  252. sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
  253. sage/schemes/elliptic_curves/saturation.py +715 -0
  254. sage/schemes/elliptic_curves/sha_tate.py +1158 -0
  255. sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
  256. sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
  257. sage/schemes/hyperelliptic_curves/all.py +6 -0
  258. sage/schemes/hyperelliptic_curves/constructor.py +291 -0
  259. sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1914 -0
  260. sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
  261. sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +954 -0
  262. sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
  263. sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
  264. sage/schemes/hyperelliptic_curves/invariants.py +410 -0
  265. sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +315 -0
  266. sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
  267. sage/schemes/hyperelliptic_curves/jacobian_generic.py +419 -0
  268. sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
  269. sage/schemes/hyperelliptic_curves/jacobian_morphism.py +875 -0
  270. sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
  271. sage/schemes/hyperelliptic_curves/mestre.py +302 -0
  272. sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3871 -0
  273. sage/schemes/jacobians/abstract_jacobian.py +277 -0
  274. sage/schemes/jacobians/all.py +2 -0
  275. sage/schemes/overview.py +161 -0
  276. sage/schemes/plane_conics/all.py +22 -0
  277. sage/schemes/plane_conics/con_field.py +1296 -0
  278. sage/schemes/plane_conics/con_finite_field.py +158 -0
  279. sage/schemes/plane_conics/con_number_field.py +456 -0
  280. sage/schemes/plane_conics/con_rational_field.py +406 -0
  281. sage/schemes/plane_conics/con_rational_function_field.py +580 -0
  282. sage/schemes/plane_conics/constructor.py +249 -0
  283. sage/schemes/plane_quartics/all.py +2 -0
  284. sage/schemes/plane_quartics/quartic_constructor.py +71 -0
  285. sage/schemes/plane_quartics/quartic_generic.py +73 -0
  286. sage/schemes/riemann_surfaces/all.py +1 -0
  287. sage/schemes/riemann_surfaces/riemann_surface.py +4117 -0
  288. sage_wheels/share/cremona/cremona_mini.db +0 -0
  289. sage_wheels/share/ellcurves/rank0 +30427 -0
  290. sage_wheels/share/ellcurves/rank1 +31871 -0
  291. sage_wheels/share/ellcurves/rank10 +6 -0
  292. sage_wheels/share/ellcurves/rank11 +6 -0
  293. sage_wheels/share/ellcurves/rank12 +1 -0
  294. sage_wheels/share/ellcurves/rank14 +1 -0
  295. sage_wheels/share/ellcurves/rank15 +1 -0
  296. sage_wheels/share/ellcurves/rank17 +1 -0
  297. sage_wheels/share/ellcurves/rank19 +1 -0
  298. sage_wheels/share/ellcurves/rank2 +2388 -0
  299. sage_wheels/share/ellcurves/rank20 +1 -0
  300. sage_wheels/share/ellcurves/rank21 +1 -0
  301. sage_wheels/share/ellcurves/rank22 +1 -0
  302. sage_wheels/share/ellcurves/rank23 +1 -0
  303. sage_wheels/share/ellcurves/rank24 +1 -0
  304. sage_wheels/share/ellcurves/rank28 +1 -0
  305. sage_wheels/share/ellcurves/rank3 +836 -0
  306. sage_wheels/share/ellcurves/rank4 +10 -0
  307. sage_wheels/share/ellcurves/rank5 +5 -0
  308. sage_wheels/share/ellcurves/rank6 +5 -0
  309. sage_wheels/share/ellcurves/rank7 +5 -0
  310. sage_wheels/share/ellcurves/rank8 +6 -0
  311. 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)