passagemath-schemes 10.6.40__cp314-cp314-macosx_13_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of passagemath-schemes might be problematic. Click here for more details.

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