passagemath-schemes 10.6.38__cp314-cp314t-macosx_13_0_arm64.whl

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

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.21.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.38.dist-info/METADATA +204 -0
  7. passagemath_schemes-10.6.38.dist-info/METADATA.bak +205 -0
  8. passagemath_schemes-10.6.38.dist-info/RECORD +314 -0
  9. passagemath_schemes-10.6.38.dist-info/WHEEL +6 -0
  10. passagemath_schemes-10.6.38.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-314t-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-314t-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-314t-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-314t-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-314t-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-314t-darwin.so +0 -0
  88. sage/modular/hypergeometric_misc.pxd +4 -0
  89. sage/modular/hypergeometric_misc.pyx +166 -0
  90. sage/modular/hypergeometric_motive.py +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-314t-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-314t-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-314t-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-314t-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-314t-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-314t-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,715 @@
1
+ # sage_setup: distribution = sagemath-schemes
2
+ # sage.doctest: needs sage.rings.finite_rings sage.rings.number_field
3
+ r"""
4
+ Saturation of Mordell-Weil groups of elliptic curves over number fields
5
+
6
+ Points `P_1`, `\dots`, `P_r` in `E(K)`, where `E` is an elliptic curve
7
+ over a number field `K`, are said to be `p`-saturated if no linear
8
+ combination `\sum n_iP_i` is divisible by `p` in `E(K)` except
9
+ trivially when all `n_i` are multiples of `p`. The points are said to
10
+ be saturated if they are `p`-saturated at all primes; this is always
11
+ true for all but finitely many primes since `E(K)` is a
12
+ finitely-generated Abelian group.
13
+
14
+ The process of `p`-saturating a given set of points is implemented
15
+ here. The naive algorithm simply checks all `(p^r-1)/(p-1)`
16
+ projective combinations of the points, testing each to see if it can
17
+ be divided by `p`. If this occurs then we replace one of the points
18
+ and continue. The function :meth:`p_saturation` does one step of
19
+ this, while :meth:`full_p_saturation` repeats until the points are
20
+ `p`-saturated. A more sophisticated algorithm for `p`-saturation is
21
+ implemented which is much more efficient for large `p` and `r`, and
22
+ involves computing the reduction of the points modulo auxiliary primes
23
+ to obtain linear conditions modulo `p` which must be satisfied by the
24
+ coefficients `a_i` of any nontrivial relation. When the points are
25
+ already `p`-saturated this sieving technique can prove their
26
+ saturation quickly.
27
+
28
+ The method :meth:`saturation` of the class :class:`EllipticCurve_number_field`
29
+ applies full `p`-saturation at any given set of primes, or can compute
30
+ a bound on the primes `p` at which the given points may not be
31
+ `p`-saturated. This involves computing a lower bound for the
32
+ canonical height of points of infinite order, together with estimates
33
+ from the geometry of numbers.
34
+
35
+ AUTHORS:
36
+
37
+ - Robert Bradshaw
38
+
39
+ - John Cremona
40
+ """
41
+ #*****************************************************************************
42
+ # Copyright (C) 2017 Robert Bradshaw <robertwb@math.washington.edu>
43
+ # John Cremona <john.cremona@gmail.com>
44
+ # William Stein <wstein@gmail.com>
45
+ #
46
+ # This program is free software: you can redistribute it and/or modify
47
+ # it under the terms of the GNU General Public License as published by
48
+ # the Free Software Foundation, either version 2 of the License, or
49
+ # (at your option) any later version.
50
+ # http://www.gnu.org/licenses/
51
+ #*****************************************************************************
52
+
53
+ from sage.rings.finite_rings.finite_field_constructor import GF
54
+ from sage.rings.integer_ring import ZZ
55
+ from sage.arith.misc import kronecker as kro
56
+ from sage.structure.sage_object import SageObject
57
+
58
+
59
+ def reduce_mod_q(x, amodq):
60
+ r"""The reduction of ``x`` modulo the prime ideal defined by ``amodq``.
61
+
62
+ INPUT:
63
+
64
+ - ``x`` -- an element of a number field `K`
65
+
66
+ - ``amodq`` -- an element of `GF(q)` which is a root mod `q` of
67
+ the defining polynomial of `K`. This defines a degree 1 prime
68
+ ideal `Q=(q,\alpha-a)` of `K=\QQ(\alpha)`, where `a \bmod q` =
69
+ ``amodq``.
70
+
71
+ OUTPUT: the image of ``x`` in the residue field of `K` at the prime `Q`
72
+
73
+ EXAMPLES::
74
+
75
+ sage: from sage.schemes.elliptic_curves.saturation import reduce_mod_q
76
+ sage: x = polygen(QQ)
77
+ sage: pol = x^3 - x^2 - 3*x + 1
78
+ sage: K.<a> = NumberField(pol)
79
+ sage: [(q, [(amodq, reduce_mod_q(1 - a + a^4, amodq))
80
+ ....: for amodq in sorted(pol.roots(GF(q), multiplicities=False))])
81
+ ....: for q in primes(50, 70)]
82
+ [(53, []),
83
+ (59, [(36, 28)]),
84
+ (61, [(40, 35)]),
85
+ (67, [(10, 8), (62, 28), (63, 60)])]
86
+ """
87
+ Fq = amodq.parent()
88
+ try:
89
+ return x.lift().change_ring(Fq)(amodq)
90
+ except AttributeError: # in case x is in QQ
91
+ return Fq(x)
92
+
93
+
94
+ class EllipticCurveSaturator(SageObject):
95
+ r"""
96
+ Class for saturating points on an elliptic curve over a number field.
97
+
98
+ INPUT:
99
+
100
+ - ``E`` -- an elliptic curve defined over a number field, or `\QQ`
101
+
102
+ - ``verbose`` -- boolean (default: ``False``); verbosity flag
103
+
104
+ .. NOTE::
105
+
106
+ This function is not normally called directly by users, who
107
+ may access the data via methods of the EllipticCurve
108
+ classes.
109
+ """
110
+ def __init__(self, E, verbose=False):
111
+ r"""
112
+ Initialize the saturator.
113
+
114
+ INPUT:
115
+
116
+ - ``E`` -- an elliptic curve defined over a number field
117
+
118
+ - ``verbose`` -- boolean (default: ``False``); verbosity flag
119
+ """
120
+ self._verbose = verbose
121
+ self._curve = E
122
+ self._N = E.discriminant().norm()
123
+ self._field = K = E.base_field()
124
+ if K.absolute_degree() == 1:
125
+ from sage.rings.rational_field import QQ
126
+ from sage.rings.polynomial.polynomial_ring import polygen
127
+ self._Kpol = polygen(QQ)
128
+ else:
129
+ self._Kpol = K.defining_polynomial()
130
+ self._D = self._Kpol.discriminant()
131
+ self._reductions = {}
132
+ self._lincombs = {}
133
+ self._torsion_gens = [t.element() for t in E.torsion_subgroup().gens()]
134
+ self._reductions = {}
135
+ # This will hold a dictionary with keys (q,aq) with q prime
136
+ # and aq a root of K's defining polynomial mod q, and values
137
+ # (n,gens) where n is the cardinality of the reduction of E
138
+ # and gens are generators of that reduction.
139
+
140
+ def add_reductions(self, q):
141
+ r"""
142
+ Add reduction data at primes above ``q`` if not already there.
143
+
144
+ INPUT:
145
+
146
+ - ``q`` -- a prime number not dividing the defining polynomial
147
+ of ``self.__field``
148
+
149
+ OUTPUT:
150
+
151
+ Returns nothing, but updates self._reductions dictionary for
152
+ key ``q`` to a dict whose keys are the roots of the defining
153
+ polynomial mod ``q`` and values tuples (``nq``, ``Eq``) where
154
+ ``Eq`` is an elliptic curve over `GF(q)` and ``nq`` its
155
+ cardinality. If ``q`` divides the conductor norm or order
156
+ discriminant nothing is added.
157
+
158
+ EXAMPLES:
159
+
160
+ Over `\QQ`::
161
+
162
+ sage: from sage.schemes.elliptic_curves.saturation import EllipticCurveSaturator
163
+
164
+ sage: # needs database_cremona_mini_ellcurve
165
+ sage: E = EllipticCurve('11a1')
166
+ sage: saturator = EllipticCurveSaturator(E)
167
+ sage: saturator._reductions
168
+ {}
169
+ sage: saturator.add_reductions(19)
170
+ sage: saturator._reductions
171
+ {19: {0: (20, Elliptic Curve defined by y^2 + y = x^3 + 18*x^2 + 9*x + 18
172
+ over Finite Field of size 19)}}
173
+
174
+ Over a number field::
175
+
176
+ sage: x = polygen(QQ); K.<a> = NumberField(x^2 + 2)
177
+ sage: E = EllipticCurve(K, [0,1,0,a,a])
178
+ sage: from sage.schemes.elliptic_curves.saturation import EllipticCurveSaturator
179
+ sage: saturator = EllipticCurveSaturator(E)
180
+ sage: for q in primes(20):
181
+ ....: saturator.add_reductions(q)
182
+ sage: saturator._reductions
183
+ {2: {},
184
+ 3: {},
185
+ 5: {},
186
+ 7: {},
187
+ 11: {3: (16, Elliptic Curve defined by y^2 = x^3 + x^2 + 3*x + 3
188
+ over Finite Field of size 11),
189
+ 8: (8, Elliptic Curve defined by y^2 = x^3 + x^2 + 8*x + 8
190
+ over Finite Field of size 11)},
191
+ 13: {},
192
+ 17: {7: (20, Elliptic Curve defined by y^2 = x^3 + x^2 + 7*x + 7
193
+ over Finite Field of size 17),
194
+ 10: (18, Elliptic Curve defined by y^2 = x^3 + x^2 + 10*x + 10
195
+ over Finite Field of size 17)},
196
+ 19: {6: (16, Elliptic Curve defined by y^2 = x^3 + x^2 + 6*x + 6
197
+ over Finite Field of size 19),
198
+ 13: (12, Elliptic Curve defined by y^2 = x^3 + x^2 + 13*x + 13
199
+ over Finite Field of size 19)}}
200
+ """
201
+ if q in self._reductions:
202
+ return
203
+ self._reductions[q] = redmodq = {}
204
+ if q.divides(self._N) or q.divides(self._D):
205
+ return
206
+ from sage.schemes.elliptic_curves.constructor import EllipticCurve
207
+ for amodq in sorted(self._Kpol.roots(GF(q), multiplicities=False)):
208
+ Eq = EllipticCurve([reduce_mod_q(ai, amodq) for ai in self._curve.ainvs()])
209
+ nq = Eq.cardinality()
210
+ redmodq[amodq] = (nq, Eq)
211
+
212
+ def full_p_saturation(self, Plist, p):
213
+ r"""Full `p`-saturation of ``Plist``.
214
+
215
+ INPUT:
216
+
217
+ - ``Plist`` -- list of independent points on one elliptic curve
218
+
219
+ - ``p`` -- integer; a prime number
220
+
221
+ OUTPUT:
222
+
223
+ (``newPlist``, ``exponent``) where ``newPlist`` has the same
224
+ length as ``Plist`` and spans the `p`-saturation of the span
225
+ of ``Plist``, which contains that span with index
226
+ ``p**exponent``.
227
+
228
+ EXAMPLES::
229
+
230
+ sage: # needs database_cremona_mini_ellcurve
231
+ sage: from sage.schemes.elliptic_curves.saturation import EllipticCurveSaturator
232
+ sage: E = EllipticCurve('389a')
233
+ sage: K.<i> = QuadraticField(-1)
234
+ sage: EK = E.change_ring(K)
235
+ sage: P = EK(1 + i, -1 - 2*i)
236
+ sage: saturator = EllipticCurveSaturator(EK, verbose=True)
237
+ sage: saturator.full_p_saturation([8*P], 2)
238
+ --starting full 2-saturation
239
+ Points were not 2-saturated, exponent was 3
240
+ ([(i + 1 : -2*i - 1 : 1)], 3)
241
+ sage: Q = EK(0, 0)
242
+ sage: R = EK(-1, 1)
243
+ sage: saturator = EllipticCurveSaturator(EK, verbose=False)
244
+ sage: saturator.full_p_saturation([P, Q, R], 3)
245
+ ([(i + 1 : -2*i - 1 : 1), (0 : 0 : 1), (-1 : 1 : 1)], 0)
246
+
247
+ An example where the points are not 7-saturated and we gain
248
+ index exponent 1. Running this example with verbose=True
249
+ would show that it uses the code for when the reduction has
250
+ `p`-rank 2 (which occurs for the reduction modulo `(16-5i)`),
251
+ which uses the Weil pairing::
252
+
253
+ sage: saturator.full_p_saturation([P, Q + 3*R, Q - 4*R], 7) # needs database_cremona_mini_ellcurve
254
+ ([(i + 1 : -2*i - 1 : 1),
255
+ (2869/676 : 154413/17576 : 1),
256
+ (-7095/502681 : -366258864/356400829 : 1)], 1)
257
+ """
258
+ if not Plist:
259
+ return Plist, ZZ.zero()
260
+
261
+ exponent = ZZ(0)
262
+
263
+ # To handle p-torsion, we must add any torsion generators whose
264
+ # order is divisible by p to the list of points. Note that it is
265
+ # not correct to add generators of the p-torsion here, we actually
266
+ # need generators of p-cotorsion. If there are any of these, we
267
+ # cannot use the supplied dict of linear combinations, so we reset
268
+ # this. The torsion points are removed before returning the
269
+ # saturated list.
270
+
271
+ verbose = self._verbose
272
+ if verbose:
273
+ print(" --starting full %s-saturation" % p)
274
+
275
+ n = len(Plist) # number of points supplied & to be returned
276
+ Plist = Plist + [T for T in self._torsion_gens if p.divides(T.order())]
277
+ nx = len(Plist) # number of points including relevant torsion
278
+ extra_torsion = nx-n
279
+ if extra_torsion:
280
+ if verbose:
281
+ print("Adding {} torsion generators before {}-saturation".format(extra_torsion,p))
282
+
283
+ res = self.p_saturation(Plist, p)
284
+ while res: # res is either False or (i, newP)
285
+ exponent += 1
286
+ Plist[res[0]] = res[1]
287
+ res = self.p_saturation(Plist, p)
288
+
289
+ if extra_torsion:
290
+ # remove the torsion points
291
+ if verbose:
292
+ print("Removing the torsion generators after %s-saturation" % p)
293
+ Plist = Plist[:n]
294
+
295
+ if verbose:
296
+ if exponent:
297
+ print("Points were not %s-saturated, exponent was %s" % (p,exponent))
298
+ else:
299
+ print("Points were %s-saturated" % p)
300
+
301
+ return (Plist, exponent)
302
+
303
+ def p_saturation(self, Plist, p, sieve=True):
304
+ r"""Checks whether the list of points is `p`-saturated.
305
+
306
+ INPUT:
307
+
308
+ - ``Plist`` -- list of independent points on one elliptic curve
309
+
310
+ - ``p`` -- integer; a prime number
311
+
312
+ - ``sieve`` -- boolean; if ``True``, use a sieve (when there are at
313
+ least 2 points), otherwise test all combinations
314
+
315
+ .. NOTE::
316
+
317
+ The sieve is much more efficient when the points are
318
+ saturated and the number of points or the prime are large.
319
+
320
+ OUTPUT:
321
+
322
+ Either ``False`` if the points are `p`-saturated, or (``i``,
323
+ ``newP``) if they are not `p`-saturated, in which case after
324
+ replacing the i'th point with ``newP``, the subgroup generated
325
+ contains that generated by ``Plist`` with index `p`.
326
+
327
+ EXAMPLES::
328
+
329
+ sage: # needs database_cremona_mini_ellcurve
330
+ sage: from sage.schemes.elliptic_curves.saturation import EllipticCurveSaturator
331
+ sage: E = EllipticCurve('389a')
332
+ sage: K.<i> = QuadraticField(-1)
333
+ sage: EK = E.change_ring(K)
334
+ sage: P = EK(1 + i, -1 - 2*i)
335
+ sage: saturator = EllipticCurveSaturator(EK)
336
+ sage: saturator.p_saturation([P], 2)
337
+ False
338
+ sage: saturator.p_saturation([2*P], 2)
339
+ (0, (i + 1 : -2*i - 1 : 1))
340
+ sage: Q = EK(0, 0)
341
+ sage: R = EK(-1, 1)
342
+ sage: saturator.p_saturation([P, Q, R], 3)
343
+ False
344
+
345
+ Here we see an example where 19-saturation is proved, with the
346
+ verbose flag set to ``True`` so that we can see what is going on::
347
+
348
+ sage: # needs database_cremona_mini_ellcurve
349
+ sage: saturator = EllipticCurveSaturator(EK, verbose=True)
350
+ sage: saturator.p_saturation([P, Q, R], 19)
351
+ Using sieve method to saturate...
352
+ E has 19-torsion over Finite Field of size 197, projecting points
353
+ --> [(15 : 168 : 1), (0 : 0 : 1), (196 : 1 : 1)]
354
+ --rank is now 1
355
+ E has 19-torsion over Finite Field of size 197, projecting points
356
+ --> [(184 : 27 : 1), (0 : 0 : 1), (196 : 1 : 1)]
357
+ --rank is now 2
358
+ E has 19-torsion over Finite Field of size 293, projecting points
359
+ --> [(139 : 16 : 1), (0 : 0 : 1), (292 : 1 : 1)]
360
+ --rank is now 3
361
+ Reached full rank: points were 19-saturated
362
+ False
363
+
364
+ An example where the points are not 11-saturated::
365
+
366
+ sage: # needs database_cremona_mini_ellcurve
367
+ sage: saturator = EllipticCurveSaturator(EK, verbose=False)
368
+ sage: res = saturator.p_saturation([P + 5*Q, P - 6*Q, R], 11); res
369
+ (0, (-5783311/14600041*i + 1396143/14600041
370
+ : 37679338314/55786756661*i + 3813624227/55786756661 : 1))
371
+
372
+ That means that the 0'th point may be replaced by the displayed
373
+ point to achieve an index gain of 11::
374
+
375
+ sage: saturator.p_saturation([res[1], P - 6*Q, R], 11) # needs database_cremona_mini_ellcurve
376
+ False
377
+
378
+ TESTS:
379
+
380
+ See :issue:`27387`::
381
+
382
+ sage: x = polygen(QQ)
383
+ sage: K.<a> = NumberField(x^2 - x - 26)
384
+ sage: E = EllipticCurve([a, 1 - a, 0, 93 - 16*a, 3150 - 560*a])
385
+ sage: P = E([65 - 35*a/3, (959*a-5377)/9])
386
+ sage: T = E.torsion_points()[0]
387
+ sage: from sage.schemes.elliptic_curves.saturation import EllipticCurveSaturator
388
+ sage: saturator = EllipticCurveSaturator(E, True)
389
+ sage: saturator.p_saturation([P, T], 2)
390
+ Using sieve method to saturate...
391
+ ...
392
+ -- points were not 2-saturated, gaining index 2
393
+ (1, (0 : 1 : 0))
394
+
395
+ A CM example where large sieving primes are needed (LMFDB
396
+ label 2.0.3.1-50625.1-CMb2)::
397
+
398
+ sage: x = polygen(QQ)
399
+ sage: K.<a> = NumberField(x^2 - x + 1)
400
+ sage: E = EllipticCurve(K, [0, 0, 1, -750, 7906])
401
+ sage: E.has_rational_cm()
402
+ True
403
+ sage: E.cm_discriminant()
404
+ -27
405
+ sage: points = [E([10, -38]), E([15/49*a + 760/49, 675/343*a - 884/343])]
406
+ sage: E.saturation(points, verbose=True) # long time (17s)
407
+ Computing lower height bound..
408
+ ..done: 7.168735020029907e-06
409
+ p-saturating for primes p < 132
410
+ ...
411
+ Saturating at p=131
412
+ --starting full 131-saturation
413
+ Using sieve method to saturate...
414
+ E has 131-torsion over Finite Field of size 617011, projecting points
415
+ --> [(10 : 616973 : 1), (592083 : 192224 : 1)]
416
+ --rank is now 1
417
+ --rank is now 2
418
+ Reached full rank: points were 131-saturated
419
+ Points were 131-saturated
420
+ --already 131-saturated
421
+ ([(10 : -38 : 1), (15/49*a + 760/49 : 675/343*a - 884/343 : 1)],
422
+ 1,
423
+ 0.123378097374749)
424
+ """
425
+ verbose = self._verbose
426
+ # This code does a lot of elliptic curve group structure
427
+ # computations, and would benefit immensely if those were sped
428
+ # up.
429
+ n = len(Plist)
430
+ if n == 0:
431
+ return False
432
+
433
+ if n == 1 and p == 2:
434
+ pts = Plist[0].division_points(p)
435
+ if pts:
436
+ return (0, pts[0])
437
+ else:
438
+ return False
439
+
440
+ E = self._curve
441
+
442
+ if not sieve:
443
+ from sage.groups.generic import multiples
444
+ from sage.schemes.projective.projective_space import ProjectiveSpace
445
+
446
+ mults = [list(multiples(P, p)) for P in Plist[:-1]] + [list(multiples(Plist[-1],2))]
447
+ E0 = E(0)
448
+
449
+ for v in ProjectiveSpace(GF(p),n-1): # an iterator
450
+ w = tuple(int(x) for x in v)
451
+ P = sum([m[c] for m,c in zip(mults,w)],E0)
452
+ pts = P.division_points(p)
453
+ if pts:
454
+ if verbose:
455
+ print(" points not saturated at {}, increasing index by {}".format(p,p))
456
+ # w will certainly have a coordinate equal to 1
457
+ return (w.index(1), pts[0])
458
+ # we only get here if no linear combination is divisible by p,
459
+ # so the points are p-saturated:
460
+ return False
461
+
462
+ # Now we use the more sophisticated sieve to either prove
463
+ # p-saturation, or compute a much smaller list of possible points
464
+ # to test for p-divisibility:
465
+
466
+ if verbose:
467
+ print("Using sieve method to saturate...")
468
+ from sage.matrix.constructor import matrix
469
+ from sage.sets.primes import Primes
470
+
471
+ A = matrix(GF(p), 0, n)
472
+ rankA = 0
473
+ count = 0
474
+
475
+ # We reduce the curve modulo primes Q of degree 1 above
476
+ # rational primes q chosen as follows: we avoid primes of bad
477
+ # reduction and primes dividing the discriminant of the
478
+ # defining polynomial of the field, so that we can avoid
479
+ # constructing number field primes entirely and just look for
480
+ # roots amodq of the defining polynomial mod q, then reduction
481
+ # of the curve is easy.
482
+
483
+ # We also avoid primes dividing the denominators of any of the
484
+ # points: the points would reduce to 0 modulo such primes
485
+ # anyway, and this way reduction of the points is also easy.
486
+
487
+ # Lastly, there is a special case when E has rational CM by
488
+ # some discriminant D. In the non-split case (kro(D,p)=-1)
489
+ # the image of the mod-p Galois representation is cyclic of
490
+ # order p^2-1 and there will be no p-torsion mod Q unless
491
+ # Frob(Q) has trivial image; a necessary condition for this is
492
+ # q=1 (mod p) so we restrict to such q. That way the density
493
+ # of q for which there is a point of order p is 1/(p+1)
494
+ # instead of 1/(p^2-1). This test was put in after running
495
+ # many tests: for example, LMFDB curve 2.0.3.1-50625.1-CMb2
496
+ # has saturation index bound 132 and to saturate at p=131
497
+ # requires q=617011. (In the split case the density is 1/(p-1)
498
+ # and there is no simple test.)
499
+
500
+ avoid = [self._N, self._D] + [P[0].denominator_ideal().norm() for P in Plist]
501
+ cm_test = E.has_rational_cm() and kro(E.cm_discriminant(), p) == -1
502
+ for q in Primes():
503
+ if any(q.divides(m) for m in avoid):
504
+ continue
505
+ if cm_test and not p.divides(q-1):
506
+ continue
507
+ self.add_reductions(q) # does nothing if key q is already there
508
+ for amodq in self._reductions[q]:
509
+ (nq, Eq) = self._reductions[q][amodq]
510
+ if not p.divides(nq):
511
+ continue
512
+ if verbose:
513
+ print("E has %s-torsion over %s, projecting points" % (p,GF(q)))
514
+ projPlist = [Eq([reduce_mod_q(c, amodq) for c in pt]) for pt in Plist]
515
+ if verbose:
516
+ print(" --> %s" % projPlist)
517
+ try:
518
+ vecs = p_projections(Eq, projPlist, p)
519
+ except ValueError:
520
+ vecs = []
521
+ for v in vecs:
522
+ A = matrix(A.rows()+[v])
523
+ newrank = A.rank()
524
+ if verbose:
525
+ print(" --rank is now %s" % newrank)
526
+ if newrank == n:
527
+ if verbose:
528
+ print("Reached full rank: points were %s-saturated" % p)
529
+ return False
530
+ if newrank == rankA:
531
+ count += 1
532
+ if count == 15:
533
+ if verbose:
534
+ print("! rank same for 15 steps, checking kernel...")
535
+ # no increase in rank for the last 15 primes Q
536
+ # find the points in the kernel and call the no-sieve version
537
+ vecs = A.right_kernel().basis()
538
+ if verbose:
539
+ print("kernel vectors: %s" % vecs)
540
+ Rlist = [sum([int(vi)*Pi for vi,Pi in zip(v,Plist)],E(0))
541
+ for v in vecs]
542
+ if verbose:
543
+ print("points generating kernel: %s" % Rlist)
544
+
545
+ # If the nullity of A were 1 (the usual
546
+ # case) we take any nonzero vector in its
547
+ # kernel and compute that linear
548
+ # combination of the points, giving a
549
+ # point which is certainly a p-multiple
550
+ # modulo 15 primes Q, and we test if it
551
+ # actually is a p-multiple:
552
+ if len(Rlist) == 1:
553
+ R = Rlist[0]
554
+ pts = R.division_points(p)
555
+ if pts:
556
+ pt = pts[0]
557
+ v = vecs[0]
558
+ # replace one of the original
559
+ # points with this one; we can
560
+ # replace any for which the
561
+ # coefficient of v is nonzero
562
+ if verbose:
563
+ print("-- points were not {}-saturated, gaining index {}".format(p,p))
564
+ j = next(i for i,x in enumerate(v) if x)
565
+ return (j, pt)
566
+ else: # R is not a p-multiple so the
567
+ # points were p-saturated
568
+ return False
569
+
570
+ # Else we call the non-sieve version with
571
+ # a list of points which are all
572
+ # p-multiples modulo 15 primes, and we
573
+ # will just try to divide all linear
574
+ # combinations of them
575
+ res = self.p_saturation(Rlist, p, sieve=False)
576
+ if res:
577
+ jj, R = res
578
+ v = vecs[jj]
579
+ # The v-linear combination of Rlist
580
+ # really is p*R. Now to enlarge the
581
+ # span, we may replce the j'th point
582
+ # in Plist with R, where v[j] is
583
+ # nonzero.
584
+ if verbose:
585
+ print("-- points were not {}-saturated, gaining index {}".format(p,p))
586
+ j = next(i for i,x in enumerate(v) if x)
587
+ return (j, R)
588
+ else:
589
+ # points really were saturated
590
+ if verbose:
591
+ print("-- points were %s-saturated" % p)
592
+ return False
593
+ else: # rank went up but is <n; carry on using more Qs
594
+ rankA = newrank
595
+ count = 0
596
+
597
+
598
+ def p_projections(Eq, Plist, p, debug=False):
599
+ r"""
600
+
601
+ INPUT:
602
+
603
+ - ``Eq`` -- an elliptic curve over a finite field
604
+
605
+ - ``Plist`` -- list of points on `Eq`
606
+
607
+ - ``p`` -- a prime number
608
+
609
+ OUTPUT:
610
+
611
+ A list of `r\le2` vectors in `\GF{p^n}`, the images of the points in
612
+ `G \otimes \GF{p}`, where `r` is the number of vectors is the
613
+ `p`-rank of `Eq`.
614
+
615
+ ALGORITHM:
616
+
617
+ First project onto the `p`-primary part of `Eq`. If that has
618
+ `p`-rank 1 (i.e. is cyclic), use discrete logs there to define a
619
+ map to `\GF{p}`, otherwise use the Weil pairing to define two
620
+ independent maps to `\GF{p}`.
621
+
622
+ EXAMPLES:
623
+
624
+ This curve has three independent rational points::
625
+
626
+ sage: E = EllipticCurve([0,0,1,-7,6])
627
+
628
+ We reduce modulo `409` where its order is `3^2\cdot7^2`; the
629
+ `3`-primary part is non-cyclic while the `7`-primary part is
630
+ cyclic of order `49`::
631
+
632
+ sage: F = GF(409)
633
+ sage: EF = E.change_ring(F)
634
+ sage: G = EF.abelian_group()
635
+ sage: G
636
+ Additive abelian group isomorphic to Z/147 + Z/3
637
+ embedded in Abelian group of points on Elliptic Curve
638
+ defined by y^2 + y = x^3 + 402*x + 6 over Finite Field of size 409
639
+ sage: G.order().factor()
640
+ 3^2 * 7^2
641
+
642
+ We construct three points and project them to the `p`-primary
643
+ parts for `p=2,3,5,7`, yielding 0,2,0,1 vectors of length 3 modulo
644
+ `p` respectively. The exact vectors output depend on the computed
645
+ generators of `G`::
646
+
647
+ sage: Plist = [EF([-2,3]), EF([0,2]), EF([1,0])]
648
+ sage: from sage.schemes.elliptic_curves.saturation import p_projections
649
+ sage: [(p, p_projections(EF, Plist, p)) for p in primes(11)] # random
650
+ [(2, []), (3, [(0, 2, 2), (2, 2, 1)]), (5, []), (7, [(5, 1, 1)])]
651
+ sage: [(p, len(p_projections(EF, Plist, p))) for p in primes(11)]
652
+ [(2, 0), (3, 2), (5, 0), (7, 1)]
653
+ """
654
+ if debug:
655
+ print("In p_projections(Eq,Plist,p) with Eq = {}, Plist = {}, p = {}".format(Eq,Plist,p))
656
+ n = Eq.cardinality()
657
+ m = n.prime_to_m_part(p) # prime-to-p part of order
658
+ if debug:
659
+ print("m={}, n={}".format(m,n))
660
+ if m == n: # p-primary part trivial, nothing to do
661
+ return []
662
+ G = Eq.abelian_group()
663
+ if debug:
664
+ print("gens = {}".format(G.gens()))
665
+
666
+ # project onto p-primary part
667
+
668
+ pts = [m*pt for pt in Plist]
669
+ gens = [m*g.element() for g in G.gens()]
670
+ gens = [g for g in gens if g]
671
+ if debug:
672
+ print("gens for {}-primary part of G: {}".format(p, gens))
673
+ print("{}*points: {}".format(m,pts))
674
+ from sage.groups.generic import discrete_log as dlog
675
+ from sage.modules.free_module_element import vector
676
+ Fp = GF(p)
677
+
678
+ # If the p-primary part is cyclic we use elliptic discrete logs directly:
679
+
680
+ if len(gens) == 1:
681
+ g = gens[0]
682
+ pp = g.order()
683
+ if debug:
684
+ print("Cyclic case, taking dlogs to base {} of order {}".format(g,pp))
685
+ # logs are well-defined mod pp, hence mod p
686
+ v = [dlog(pt, g, ord=pp, operation='+') for pt in pts]
687
+ if debug:
688
+ print("dlogs: {}".format(v))
689
+ return [vector(Fp, v)]
690
+
691
+ # We make no assumption about which generator order divides the
692
+ # other, since conventions differ!
693
+
694
+ orders = [g.order() for g in gens]
695
+ p1, p2 = min(orders), max(orders)
696
+ g1, g2 = gens
697
+ if debug:
698
+ print("Non-cyclic case, orders = {}, p1={}, p2={}, g1={}, g2={}".format(orders,p1,p2,g1,g2))
699
+
700
+ # Now the p-primary part of the reduction is non-cyclic of
701
+ # exponent p2, and we use the Weil pairing, whose values are p1'th
702
+ # roots of unity with p1|p2, together with discrete log in the
703
+ # multiplicative group.
704
+
705
+ zeta = g1.weil_pairing(g2, p2) # a primitive p1'th root of unity
706
+ if debug:
707
+ print("wp of gens = {} with order {}".format(zeta, zeta.multiplicative_order()))
708
+ assert zeta.multiplicative_order() == p1, "Weil pairing error during saturation: p={}, G={}, Plist={}".format(p, G, Plist)
709
+
710
+ # logs are well-defined mod p1, hence mod p
711
+
712
+ return [vector(Fp, [dlog(pt.weil_pairing(g1, p2), zeta,
713
+ ord=p1, operation='*') for pt in pts]),
714
+ vector(Fp, [dlog(pt.weil_pairing(g2, p2), zeta,
715
+ ord=p1, operation='*') for pt in pts])]