passagemath-schemes 10.8.1a4__cp314-cp314t-macosx_13_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (312) hide show
  1. passagemath_schemes/.dylibs/libflint.22.0.dylib +0 -0
  2. passagemath_schemes/.dylibs/libgmp.10.dylib +0 -0
  3. passagemath_schemes/.dylibs/libgmpxx.4.dylib +0 -0
  4. passagemath_schemes/.dylibs/libmpfr.6.dylib +0 -0
  5. passagemath_schemes/__init__.py +3 -0
  6. passagemath_schemes-10.8.1a4.dist-info/METADATA +203 -0
  7. passagemath_schemes-10.8.1a4.dist-info/METADATA.bak +204 -0
  8. passagemath_schemes-10.8.1a4.dist-info/RECORD +312 -0
  9. passagemath_schemes-10.8.1a4.dist-info/WHEEL +6 -0
  10. passagemath_schemes-10.8.1a4.dist-info/top_level.txt +3 -0
  11. sage/all__sagemath_schemes.py +23 -0
  12. sage/databases/all__sagemath_schemes.py +7 -0
  13. sage/databases/cremona.py +1723 -0
  14. sage/dynamics/all__sagemath_schemes.py +2 -0
  15. sage/dynamics/arithmetic_dynamics/affine_ds.py +1083 -0
  16. sage/dynamics/arithmetic_dynamics/all.py +14 -0
  17. sage/dynamics/arithmetic_dynamics/berkovich_ds.py +1101 -0
  18. sage/dynamics/arithmetic_dynamics/dynamical_semigroup.py +1543 -0
  19. sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +2426 -0
  20. sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +1169 -0
  21. sage/dynamics/arithmetic_dynamics/generic_ds.py +663 -0
  22. sage/dynamics/arithmetic_dynamics/product_projective_ds.py +339 -0
  23. sage/dynamics/arithmetic_dynamics/projective_ds.py +9556 -0
  24. sage/dynamics/arithmetic_dynamics/projective_ds_helper.cpython-314t-darwin.so +0 -0
  25. sage/dynamics/arithmetic_dynamics/projective_ds_helper.pyx +301 -0
  26. sage/dynamics/arithmetic_dynamics/wehlerK3.py +2578 -0
  27. sage/lfunctions/all.py +18 -0
  28. sage/lfunctions/dokchitser.py +727 -0
  29. sage/lfunctions/pari.py +971 -0
  30. sage/lfunctions/zero_sums.cpython-314t-darwin.so +0 -0
  31. sage/lfunctions/zero_sums.pyx +1847 -0
  32. sage/modular/abvar/abvar.py +5132 -0
  33. sage/modular/abvar/abvar_ambient_jacobian.py +414 -0
  34. sage/modular/abvar/abvar_newform.py +246 -0
  35. sage/modular/abvar/all.py +8 -0
  36. sage/modular/abvar/constructor.py +187 -0
  37. sage/modular/abvar/cuspidal_subgroup.py +371 -0
  38. sage/modular/abvar/finite_subgroup.py +896 -0
  39. sage/modular/abvar/homology.py +721 -0
  40. sage/modular/abvar/homspace.py +989 -0
  41. sage/modular/abvar/lseries.py +415 -0
  42. sage/modular/abvar/morphism.py +935 -0
  43. sage/modular/abvar/torsion_point.py +274 -0
  44. sage/modular/abvar/torsion_subgroup.py +741 -0
  45. sage/modular/all.py +43 -0
  46. sage/modular/arithgroup/all.py +20 -0
  47. sage/modular/arithgroup/arithgroup_element.cpython-314t-darwin.so +0 -0
  48. sage/modular/arithgroup/arithgroup_element.pyx +474 -0
  49. sage/modular/arithgroup/arithgroup_generic.py +1406 -0
  50. sage/modular/arithgroup/arithgroup_perm.py +2692 -0
  51. sage/modular/arithgroup/congroup.cpython-314t-darwin.so +0 -0
  52. sage/modular/arithgroup/congroup.pyx +334 -0
  53. sage/modular/arithgroup/congroup_gamma.py +361 -0
  54. sage/modular/arithgroup/congroup_gamma0.py +692 -0
  55. sage/modular/arithgroup/congroup_gamma1.py +659 -0
  56. sage/modular/arithgroup/congroup_gammaH.py +1491 -0
  57. sage/modular/arithgroup/congroup_generic.py +630 -0
  58. sage/modular/arithgroup/congroup_sl2z.py +266 -0
  59. sage/modular/arithgroup/farey_symbol.cpython-314t-darwin.so +0 -0
  60. sage/modular/arithgroup/farey_symbol.pyx +1067 -0
  61. sage/modular/arithgroup/tests.py +425 -0
  62. sage/modular/btquotients/all.py +4 -0
  63. sage/modular/btquotients/btquotient.py +3736 -0
  64. sage/modular/btquotients/pautomorphicform.py +2564 -0
  65. sage/modular/buzzard.py +100 -0
  66. sage/modular/congroup.py +29 -0
  67. sage/modular/congroup_element.py +13 -0
  68. sage/modular/cusps.py +1107 -0
  69. sage/modular/cusps_nf.py +1270 -0
  70. sage/modular/dims.py +571 -0
  71. sage/modular/dirichlet.py +3310 -0
  72. sage/modular/drinfeld_modform/all.py +2 -0
  73. sage/modular/drinfeld_modform/element.py +446 -0
  74. sage/modular/drinfeld_modform/ring.py +773 -0
  75. sage/modular/drinfeld_modform/tutorial.py +236 -0
  76. sage/modular/etaproducts.py +1076 -0
  77. sage/modular/hecke/algebra.py +725 -0
  78. sage/modular/hecke/all.py +19 -0
  79. sage/modular/hecke/ambient_module.py +994 -0
  80. sage/modular/hecke/degenmap.py +119 -0
  81. sage/modular/hecke/element.py +302 -0
  82. sage/modular/hecke/hecke_operator.py +736 -0
  83. sage/modular/hecke/homspace.py +185 -0
  84. sage/modular/hecke/module.py +1744 -0
  85. sage/modular/hecke/morphism.py +139 -0
  86. sage/modular/hecke/submodule.py +970 -0
  87. sage/modular/hypergeometric_misc.cpython-314t-darwin.so +0 -0
  88. sage/modular/hypergeometric_misc.pxd +4 -0
  89. sage/modular/hypergeometric_misc.pyx +166 -0
  90. sage/modular/hypergeometric_motive.py +2020 -0
  91. sage/modular/local_comp/all.py +2 -0
  92. sage/modular/local_comp/liftings.py +292 -0
  93. sage/modular/local_comp/local_comp.py +1070 -0
  94. sage/modular/local_comp/smoothchar.py +1825 -0
  95. sage/modular/local_comp/type_space.py +748 -0
  96. sage/modular/modform/all.py +30 -0
  97. sage/modular/modform/ambient.py +817 -0
  98. sage/modular/modform/ambient_R.py +177 -0
  99. sage/modular/modform/ambient_eps.py +306 -0
  100. sage/modular/modform/ambient_g0.py +120 -0
  101. sage/modular/modform/ambient_g1.py +199 -0
  102. sage/modular/modform/constructor.py +545 -0
  103. sage/modular/modform/cuspidal_submodule.py +708 -0
  104. sage/modular/modform/defaults.py +14 -0
  105. sage/modular/modform/eis_series.py +487 -0
  106. sage/modular/modform/eisenstein_submodule.py +663 -0
  107. sage/modular/modform/element.py +4105 -0
  108. sage/modular/modform/half_integral.py +154 -0
  109. sage/modular/modform/hecke_operator_on_qexp.py +247 -0
  110. sage/modular/modform/j_invariant.py +47 -0
  111. sage/modular/modform/l_series_gross_zagier.py +127 -0
  112. sage/modular/modform/l_series_gross_zagier_coeffs.cpython-314t-darwin.so +0 -0
  113. sage/modular/modform/l_series_gross_zagier_coeffs.pyx +177 -0
  114. sage/modular/modform/notes.py +45 -0
  115. sage/modular/modform/numerical.py +514 -0
  116. sage/modular/modform/periods.py +14 -0
  117. sage/modular/modform/ring.py +1257 -0
  118. sage/modular/modform/space.py +1859 -0
  119. sage/modular/modform/submodule.py +118 -0
  120. sage/modular/modform/tests.py +64 -0
  121. sage/modular/modform/theta.py +110 -0
  122. sage/modular/modform/vm_basis.py +380 -0
  123. sage/modular/modform/weight1.py +221 -0
  124. sage/modular/modform_hecketriangle/abstract_ring.py +1932 -0
  125. sage/modular/modform_hecketriangle/abstract_space.py +2527 -0
  126. sage/modular/modform_hecketriangle/all.py +30 -0
  127. sage/modular/modform_hecketriangle/analytic_type.py +590 -0
  128. sage/modular/modform_hecketriangle/constructor.py +416 -0
  129. sage/modular/modform_hecketriangle/element.py +351 -0
  130. sage/modular/modform_hecketriangle/functors.py +752 -0
  131. sage/modular/modform_hecketriangle/graded_ring.py +541 -0
  132. sage/modular/modform_hecketriangle/graded_ring_element.py +2225 -0
  133. sage/modular/modform_hecketriangle/hecke_triangle_group_element.py +3349 -0
  134. sage/modular/modform_hecketriangle/hecke_triangle_groups.py +1426 -0
  135. sage/modular/modform_hecketriangle/readme.py +1214 -0
  136. sage/modular/modform_hecketriangle/series_constructor.py +580 -0
  137. sage/modular/modform_hecketriangle/space.py +1037 -0
  138. sage/modular/modform_hecketriangle/subspace.py +423 -0
  139. sage/modular/modsym/all.py +17 -0
  140. sage/modular/modsym/ambient.py +3844 -0
  141. sage/modular/modsym/boundary.py +1420 -0
  142. sage/modular/modsym/element.py +336 -0
  143. sage/modular/modsym/g1list.py +178 -0
  144. sage/modular/modsym/ghlist.py +182 -0
  145. sage/modular/modsym/hecke_operator.py +73 -0
  146. sage/modular/modsym/manin_symbol.cpython-314t-darwin.so +0 -0
  147. sage/modular/modsym/manin_symbol.pxd +5 -0
  148. sage/modular/modsym/manin_symbol.pyx +497 -0
  149. sage/modular/modsym/manin_symbol_list.py +1291 -0
  150. sage/modular/modsym/modsym.py +400 -0
  151. sage/modular/modsym/modular_symbols.py +384 -0
  152. sage/modular/modsym/p1list_nf.py +1241 -0
  153. sage/modular/modsym/relation_matrix.py +591 -0
  154. sage/modular/modsym/relation_matrix_pyx.cpython-314t-darwin.so +0 -0
  155. sage/modular/modsym/relation_matrix_pyx.pyx +108 -0
  156. sage/modular/modsym/space.py +2468 -0
  157. sage/modular/modsym/subspace.py +455 -0
  158. sage/modular/modsym/tests.py +376 -0
  159. sage/modular/multiple_zeta.py +2635 -0
  160. sage/modular/multiple_zeta_F_algebra.py +789 -0
  161. sage/modular/overconvergent/all.py +6 -0
  162. sage/modular/overconvergent/genus0.py +1879 -0
  163. sage/modular/overconvergent/hecke_series.py +1187 -0
  164. sage/modular/overconvergent/weightspace.py +776 -0
  165. sage/modular/pollack_stevens/all.py +4 -0
  166. sage/modular/pollack_stevens/distributions.py +874 -0
  167. sage/modular/pollack_stevens/fund_domain.py +1572 -0
  168. sage/modular/pollack_stevens/manin_map.py +856 -0
  169. sage/modular/pollack_stevens/modsym.py +1590 -0
  170. sage/modular/pollack_stevens/padic_lseries.py +417 -0
  171. sage/modular/pollack_stevens/sigma0.py +534 -0
  172. sage/modular/pollack_stevens/space.py +1078 -0
  173. sage/modular/quasimodform/all.py +3 -0
  174. sage/modular/quasimodform/element.py +846 -0
  175. sage/modular/quasimodform/ring.py +826 -0
  176. sage/modular/quatalg/all.py +3 -0
  177. sage/modular/quatalg/brandt.py +1642 -0
  178. sage/modular/ssmod/all.py +8 -0
  179. sage/modular/ssmod/ssmod.py +827 -0
  180. sage/rings/all__sagemath_schemes.py +1 -0
  181. sage/rings/polynomial/all__sagemath_schemes.py +1 -0
  182. sage/rings/polynomial/binary_form_reduce.py +585 -0
  183. sage/schemes/all.py +41 -0
  184. sage/schemes/berkovich/all.py +6 -0
  185. sage/schemes/berkovich/berkovich_cp_element.py +2582 -0
  186. sage/schemes/berkovich/berkovich_space.py +700 -0
  187. sage/schemes/curves/affine_curve.py +2924 -0
  188. sage/schemes/curves/all.py +33 -0
  189. sage/schemes/curves/closed_point.py +434 -0
  190. sage/schemes/curves/constructor.py +397 -0
  191. sage/schemes/curves/curve.py +542 -0
  192. sage/schemes/curves/plane_curve_arrangement.py +1283 -0
  193. sage/schemes/curves/point.py +463 -0
  194. sage/schemes/curves/projective_curve.py +3203 -0
  195. sage/schemes/curves/weighted_projective_curve.py +106 -0
  196. sage/schemes/curves/zariski_vankampen.py +1931 -0
  197. sage/schemes/cyclic_covers/all.py +2 -0
  198. sage/schemes/cyclic_covers/charpoly_frobenius.py +320 -0
  199. sage/schemes/cyclic_covers/constructor.py +137 -0
  200. sage/schemes/cyclic_covers/cycliccover_finite_field.py +1309 -0
  201. sage/schemes/cyclic_covers/cycliccover_generic.py +310 -0
  202. sage/schemes/elliptic_curves/BSD.py +991 -0
  203. sage/schemes/elliptic_curves/Qcurves.py +592 -0
  204. sage/schemes/elliptic_curves/addition_formulas_ring.py +94 -0
  205. sage/schemes/elliptic_curves/all.py +49 -0
  206. sage/schemes/elliptic_curves/cardinality.py +609 -0
  207. sage/schemes/elliptic_curves/cm.py +1103 -0
  208. sage/schemes/elliptic_curves/constructor.py +1530 -0
  209. sage/schemes/elliptic_curves/ec_database.py +175 -0
  210. sage/schemes/elliptic_curves/ell_curve_isogeny.py +3971 -0
  211. sage/schemes/elliptic_curves/ell_egros.py +457 -0
  212. sage/schemes/elliptic_curves/ell_field.py +2837 -0
  213. sage/schemes/elliptic_curves/ell_finite_field.py +3249 -0
  214. sage/schemes/elliptic_curves/ell_generic.py +3760 -0
  215. sage/schemes/elliptic_curves/ell_local_data.py +1207 -0
  216. sage/schemes/elliptic_curves/ell_modular_symbols.py +775 -0
  217. sage/schemes/elliptic_curves/ell_number_field.py +4220 -0
  218. sage/schemes/elliptic_curves/ell_padic_field.py +107 -0
  219. sage/schemes/elliptic_curves/ell_point.py +4944 -0
  220. sage/schemes/elliptic_curves/ell_rational_field.py +7184 -0
  221. sage/schemes/elliptic_curves/ell_tate_curve.py +671 -0
  222. sage/schemes/elliptic_curves/ell_torsion.py +436 -0
  223. sage/schemes/elliptic_curves/ell_wp.py +352 -0
  224. sage/schemes/elliptic_curves/formal_group.py +760 -0
  225. sage/schemes/elliptic_curves/gal_reps.py +1459 -0
  226. sage/schemes/elliptic_curves/gal_reps_number_field.py +1663 -0
  227. sage/schemes/elliptic_curves/gp_simon.py +152 -0
  228. sage/schemes/elliptic_curves/heegner.py +7328 -0
  229. sage/schemes/elliptic_curves/height.py +2108 -0
  230. sage/schemes/elliptic_curves/hom.py +1788 -0
  231. sage/schemes/elliptic_curves/hom_composite.py +1084 -0
  232. sage/schemes/elliptic_curves/hom_fractional.py +544 -0
  233. sage/schemes/elliptic_curves/hom_frobenius.py +522 -0
  234. sage/schemes/elliptic_curves/hom_scalar.py +531 -0
  235. sage/schemes/elliptic_curves/hom_sum.py +681 -0
  236. sage/schemes/elliptic_curves/hom_velusqrt.py +1290 -0
  237. sage/schemes/elliptic_curves/homset.py +271 -0
  238. sage/schemes/elliptic_curves/isogeny_class.py +1523 -0
  239. sage/schemes/elliptic_curves/isogeny_small_degree.py +2797 -0
  240. sage/schemes/elliptic_curves/jacobian.py +247 -0
  241. sage/schemes/elliptic_curves/kodaira_symbol.py +344 -0
  242. sage/schemes/elliptic_curves/kraus.py +1014 -0
  243. sage/schemes/elliptic_curves/lseries_ell.py +915 -0
  244. sage/schemes/elliptic_curves/mod5family.py +105 -0
  245. sage/schemes/elliptic_curves/mod_poly.py +197 -0
  246. sage/schemes/elliptic_curves/mod_sym_num.cpython-314t-darwin.so +0 -0
  247. sage/schemes/elliptic_curves/mod_sym_num.pyx +3796 -0
  248. sage/schemes/elliptic_curves/modular_parametrization.py +305 -0
  249. sage/schemes/elliptic_curves/padic_lseries.py +1793 -0
  250. sage/schemes/elliptic_curves/padics.py +1816 -0
  251. sage/schemes/elliptic_curves/period_lattice.py +2234 -0
  252. sage/schemes/elliptic_curves/period_lattice_region.cpython-314t-darwin.so +0 -0
  253. sage/schemes/elliptic_curves/period_lattice_region.pyx +722 -0
  254. sage/schemes/elliptic_curves/saturation.py +716 -0
  255. sage/schemes/elliptic_curves/sha_tate.py +1158 -0
  256. sage/schemes/elliptic_curves/weierstrass_morphism.py +1117 -0
  257. sage/schemes/elliptic_curves/weierstrass_transform.py +200 -0
  258. sage/schemes/hyperelliptic_curves/all.py +6 -0
  259. sage/schemes/hyperelliptic_curves/constructor.py +369 -0
  260. sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py +1948 -0
  261. sage/schemes/hyperelliptic_curves/hyperelliptic_g2.py +192 -0
  262. sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +936 -0
  263. sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py +1332 -0
  264. sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py +84 -0
  265. sage/schemes/hyperelliptic_curves/invariants.py +410 -0
  266. sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py +312 -0
  267. sage/schemes/hyperelliptic_curves/jacobian_g2.py +32 -0
  268. sage/schemes/hyperelliptic_curves/jacobian_generic.py +437 -0
  269. sage/schemes/hyperelliptic_curves/jacobian_homset.py +186 -0
  270. sage/schemes/hyperelliptic_curves/jacobian_morphism.py +878 -0
  271. sage/schemes/hyperelliptic_curves/kummer_surface.py +99 -0
  272. sage/schemes/hyperelliptic_curves/mestre.py +302 -0
  273. sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +3863 -0
  274. sage/schemes/jacobians/abstract_jacobian.py +277 -0
  275. sage/schemes/jacobians/all.py +2 -0
  276. sage/schemes/overview.py +161 -0
  277. sage/schemes/plane_conics/all.py +22 -0
  278. sage/schemes/plane_conics/con_field.py +1296 -0
  279. sage/schemes/plane_conics/con_finite_field.py +158 -0
  280. sage/schemes/plane_conics/con_number_field.py +456 -0
  281. sage/schemes/plane_conics/con_rational_field.py +406 -0
  282. sage/schemes/plane_conics/con_rational_function_field.py +581 -0
  283. sage/schemes/plane_conics/constructor.py +249 -0
  284. sage/schemes/plane_quartics/all.py +2 -0
  285. sage/schemes/plane_quartics/quartic_constructor.py +71 -0
  286. sage/schemes/plane_quartics/quartic_generic.py +53 -0
  287. sage/schemes/riemann_surfaces/all.py +1 -0
  288. sage/schemes/riemann_surfaces/riemann_surface.py +4177 -0
  289. sage_wheels/share/cremona/cremona_mini.db +0 -0
  290. sage_wheels/share/ellcurves/rank0 +30427 -0
  291. sage_wheels/share/ellcurves/rank1 +31871 -0
  292. sage_wheels/share/ellcurves/rank10 +6 -0
  293. sage_wheels/share/ellcurves/rank11 +6 -0
  294. sage_wheels/share/ellcurves/rank12 +1 -0
  295. sage_wheels/share/ellcurves/rank14 +1 -0
  296. sage_wheels/share/ellcurves/rank15 +1 -0
  297. sage_wheels/share/ellcurves/rank17 +1 -0
  298. sage_wheels/share/ellcurves/rank19 +1 -0
  299. sage_wheels/share/ellcurves/rank2 +2388 -0
  300. sage_wheels/share/ellcurves/rank20 +1 -0
  301. sage_wheels/share/ellcurves/rank21 +1 -0
  302. sage_wheels/share/ellcurves/rank22 +1 -0
  303. sage_wheels/share/ellcurves/rank23 +1 -0
  304. sage_wheels/share/ellcurves/rank24 +1 -0
  305. sage_wheels/share/ellcurves/rank28 +1 -0
  306. sage_wheels/share/ellcurves/rank3 +836 -0
  307. sage_wheels/share/ellcurves/rank4 +10 -0
  308. sage_wheels/share/ellcurves/rank5 +5 -0
  309. sage_wheels/share/ellcurves/rank6 +5 -0
  310. sage_wheels/share/ellcurves/rank7 +5 -0
  311. sage_wheels/share/ellcurves/rank8 +6 -0
  312. sage_wheels/share/ellcurves/rank9 +7 -0
@@ -0,0 +1,3863 @@
1
+ # sage_setup: distribution = sagemath-schemes
2
+ r"""
3
+ Computation of Frobenius matrix on Monsky-Washnitzer cohomology
4
+
5
+ The most interesting functions to be exported here are
6
+ :func:`matrix_of_frobenius` and :func:`adjusted_prec`.
7
+
8
+ Currently this code is limited to the case `p \geq 5` (no
9
+ `GF(p^n)` for `n > 1`), and only handles the
10
+ elliptic curve case (not more general hyperelliptic curves).
11
+
12
+ REFERENCES:
13
+
14
+ - [Ked2001]_
15
+
16
+ - [Edix]_
17
+
18
+ AUTHORS:
19
+
20
+ - David Harvey and Robert Bradshaw: initial code developed at the 2006
21
+ MSRI graduate workshop, working with Jennifer Balakrishnan and Liang
22
+ Xiao
23
+
24
+ - David Harvey (2006-08): cleaned up, rewrote some chunks, lots more
25
+ documentation, added Newton iteration method, added more complete
26
+ 'trace trick', integrated better into Sage.
27
+
28
+ - David Harvey (2007-02): added algorithm with sqrt(p) complexity
29
+ (removed in May 2007 due to better C++ implementation)
30
+
31
+ - Robert Bradshaw (2007-03): keep track of exact form in reduction
32
+ algorithms
33
+
34
+ - Robert Bradshaw (2007-04): generalization to hyperelliptic curves
35
+
36
+ - Julian Rueth (2014-05-09): improved caching
37
+ """
38
+
39
+ # ****************************************************************************
40
+ # Copyright (C) 2006 William Stein <wstein@gmail.com>
41
+ # 2006 Robert Bradshaw <robertwb@math.washington.edu>
42
+ # 2006 David Harvey <dmharvey@math.harvard.edu>
43
+ # 2014 Julian Rueth <julian.rueth@fsfe.org>
44
+ #
45
+ # Distributed under the terms of the GNU General Public License (GPL)
46
+ # https://www.gnu.org/licenses/
47
+ # ****************************************************************************
48
+
49
+ from sage.arith.misc import binomial
50
+ from sage.arith.misc import integer_ceil as ceil
51
+ from sage.categories.algebras import Algebras
52
+ from sage.categories.integral_domains import IntegralDomains
53
+ from sage.matrix.constructor import matrix
54
+ from sage.misc.cachefunc import cached_method
55
+ from sage.misc.lazy_import import lazy_import
56
+ from sage.misc.repr import repr_lincomb
57
+ from sage.modules.free_module import FreeModule
58
+ from sage.modules.free_module_element import FreeModuleElement, vector
59
+ from sage.modules.module import Module
60
+ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing as Integers
61
+ from sage.rings.infinity import Infinity
62
+ from sage.rings.integer import Integer
63
+ from sage.rings.integer_ring import ZZ
64
+ from sage.rings.laurent_series_ring import LaurentSeriesRing
65
+ from sage.rings.polynomial.polynomial_element import Polynomial
66
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
67
+ from sage.rings.power_series_ring import PowerSeriesRing
68
+ from sage.rings.rational import Rational
69
+ from sage.rings.rational_field import QQ, RationalField as Rationals
70
+ from sage.schemes.elliptic_curves.constructor import EllipticCurve
71
+ from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic
72
+ from sage.schemes.hyperelliptic_curves.constructor import HyperellipticCurve
73
+ from sage.schemes.hyperelliptic_curves.hyperelliptic_generic import HyperellipticCurve_generic
74
+ from sage.structure.element import ModuleElement
75
+ from sage.structure.parent import Parent
76
+ from sage.structure.richcmp import richcmp
77
+ from sage.structure.unique_representation import UniqueRepresentation
78
+
79
+ lazy_import('sage.functions.log', 'log')
80
+ lazy_import('sage.rings.lazy_series_ring', 'LazyLaurentSeriesRing')
81
+ lazy_import('sage.rings.padics.factory', 'Qp', as_='pAdicField')
82
+
83
+
84
+ class SpecialCubicQuotientRingElement(ModuleElement):
85
+ """
86
+ An element of a :class:`SpecialCubicQuotientRing`.
87
+ """
88
+ def __init__(self, parent, p0, p1, p2, check=True):
89
+ """
90
+ Construct the element `p_0 + p_1*x + p_2*x^2`, where
91
+ the `p_i` are polynomials in `T`.
92
+
93
+ INPUT:
94
+
95
+ - ``parent`` -- a :class:`SpecialCubicQuotientRing`
96
+
97
+ - ``p0``, ``p1``, ``p2`` -- coefficients; must be coercible
98
+ into parent.poly_ring()
99
+
100
+ - ``check`` -- boolean (default: ``True``); whether to carry
101
+ out coercion
102
+
103
+ EXAMPLES::
104
+
105
+ sage: B.<t> = PolynomialRing(Integers(125))
106
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
107
+ sage: from sage.schemes.hyperelliptic_curves.monsky_washnitzer import SpecialCubicQuotientRingElement
108
+ sage: SpecialCubicQuotientRingElement(R, 2, 3, 4)
109
+ (2) + (3)*x + (4)*x^2
110
+
111
+ TESTS::
112
+
113
+ sage: B.<t> = PolynomialRing(Integers(125))
114
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
115
+ sage: TestSuite(R).run()
116
+ sage: p = R.create_element(t, t^2 - 2, 3)
117
+ sage: -p
118
+ (124*T) + (124*T^2 + 2)*x + (122)*x^2
119
+ """
120
+ if not isinstance(parent, SpecialCubicQuotientRing):
121
+ raise TypeError(f"parent (={parent}) must be a SpecialCubicQuotientRing")
122
+
123
+ ModuleElement.__init__(self, parent)
124
+
125
+ if check:
126
+ poly_ring = parent._poly_ring
127
+ p0 = poly_ring(p0)
128
+ p1 = poly_ring(p1)
129
+ p2 = poly_ring(p2)
130
+
131
+ self._triple = (p0, p1, p2)
132
+
133
+ def coeffs(self):
134
+ """
135
+ Return list of three lists of coefficients, corresponding to the
136
+ `x^0`, `x^1`, `x^2` coefficients.
137
+
138
+ The lists are zero padded to the same length. The list entries
139
+ belong to the base ring.
140
+
141
+ EXAMPLES::
142
+
143
+ sage: B.<t> = PolynomialRing(Integers(125))
144
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
145
+ sage: p = R.create_element(t, t^2 - 2, 3)
146
+ sage: p.coeffs()
147
+ [[0, 1, 0], [123, 0, 1], [3, 0, 0]]
148
+ """
149
+ coeffs = [column.coefficients(sparse=False) for column in self._triple]
150
+ degree = max([len(x) for x in coeffs])
151
+ base_ring = self.parent().base_ring()
152
+ for column in coeffs:
153
+ column.extend([base_ring(0)] * (degree - len(column)))
154
+ return coeffs
155
+
156
+ def __bool__(self) -> bool:
157
+ """
158
+ EXAMPLES::
159
+
160
+ sage: B.<t> = PolynomialRing(Integers(125))
161
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
162
+ sage: x, T = R.gens()
163
+ sage: not x
164
+ False
165
+ sage: not T
166
+ False
167
+ sage: not R.create_element(0, 0, 0)
168
+ True
169
+ """
170
+ return bool(self._triple[0]) or bool(self._triple[1]) or bool(self._triple[2])
171
+
172
+ def _richcmp_(self, other, op) -> bool:
173
+ """
174
+ EXAMPLES::
175
+
176
+ sage: B.<t> = PolynomialRing(Integers(125))
177
+ sage: x, t = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4)).gens()
178
+ sage: x == t
179
+ False
180
+ sage: x == x
181
+ True
182
+ sage: x == x + x - x
183
+ True
184
+ """
185
+ return richcmp(self._triple, other._triple, op)
186
+
187
+ def _repr_(self) -> str:
188
+ """
189
+ EXAMPLES::
190
+
191
+ sage: B.<t> = PolynomialRing(Integers(125))
192
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
193
+ sage: x, T = R.gens()
194
+ sage: x + T*x - 2*T^2
195
+ (123*T^2) + (T + 1)*x + (0)*x^2
196
+ """
197
+ return "(%s) + (%s)*x + (%s)*x^2" % self._triple
198
+
199
+ def _latex_(self) -> str:
200
+ """
201
+ EXAMPLES::
202
+
203
+ sage: B.<t> = PolynomialRing(Integers(125))
204
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
205
+ sage: x, T = R.gens()
206
+ sage: f = x + T*x - 2*T^2
207
+ sage: latex(f)
208
+ (123 T^{2}) + (T + 1)x + (0)x^2
209
+ """
210
+ return ("(%s) + (%s)x + (%s)x^2"
211
+ % tuple(column._latex_() for column in self._triple))
212
+
213
+ def _add_(self, other):
214
+ """
215
+ EXAMPLES::
216
+
217
+ sage: B.<t> = PolynomialRing(Integers(125))
218
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
219
+ sage: f = R.create_element(2, t, t^2 - 3)
220
+ sage: g = R.create_element(3 + t, -t, t)
221
+ sage: f + g
222
+ (T + 5) + (0)*x + (T^2 + T + 122)*x^2
223
+ """
224
+ P = self.parent()
225
+ return P.element_class(P,
226
+ self._triple[0] + other._triple[0],
227
+ self._triple[1] + other._triple[1],
228
+ self._triple[2] + other._triple[2],
229
+ check=False)
230
+
231
+ def _sub_(self, other):
232
+ """
233
+ EXAMPLES::
234
+
235
+ sage: B.<t> = PolynomialRing(Integers(125))
236
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
237
+ sage: f = R.create_element(2, t, t^2 - 3)
238
+ sage: g = R.create_element(3 + t, -t, t)
239
+ sage: f - g
240
+ (124*T + 124) + (2*T)*x + (T^2 + 124*T + 122)*x^2
241
+ """
242
+ P = self.parent()
243
+ return P.element_class(P,
244
+ self._triple[0] - other._triple[0],
245
+ self._triple[1] - other._triple[1],
246
+ self._triple[2] - other._triple[2],
247
+ check=False)
248
+
249
+ def shift(self, n):
250
+ """
251
+ Return this element multiplied by `T^n`.
252
+
253
+ EXAMPLES::
254
+
255
+ sage: B.<t> = PolynomialRing(Integers(125))
256
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
257
+ sage: f = R.create_element(2, t, t^2 - 3)
258
+ sage: f
259
+ (2) + (T)*x + (T^2 + 122)*x^2
260
+ sage: f.shift(1)
261
+ (2*T) + (T^2)*x + (T^3 + 122*T)*x^2
262
+ sage: f.shift(2)
263
+ (2*T^2) + (T^3)*x + (T^4 + 122*T^2)*x^2
264
+ """
265
+ P = self.parent()
266
+ return P.element_class(P,
267
+ self._triple[0].shift(n),
268
+ self._triple[1].shift(n),
269
+ self._triple[2].shift(n),
270
+ check=False)
271
+
272
+ def scalar_multiply(self, scalar):
273
+ """
274
+ Multiply this element by a scalar, i.e. just multiply each
275
+ coefficient of `x^j` by the scalar.
276
+
277
+ INPUT:
278
+
279
+ - ``scalar`` -- either an element of ``base_ring``, or an
280
+ element of ``poly_ring``
281
+
282
+ EXAMPLES::
283
+
284
+ sage: B.<t> = PolynomialRing(Integers(125))
285
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
286
+ sage: x, T = R.gens()
287
+ sage: f = R.create_element(2, t, t^2 - 3)
288
+ sage: f
289
+ (2) + (T)*x + (T^2 + 122)*x^2
290
+ sage: f.scalar_multiply(2)
291
+ (4) + (2*T)*x + (2*T^2 + 119)*x^2
292
+ sage: f.scalar_multiply(t)
293
+ (2*T) + (T^2)*x + (T^3 + 122*T)*x^2
294
+ """
295
+ P = self.parent()
296
+ scalar = P._poly_ring(scalar)
297
+ return P.element_class(P,
298
+ scalar * self._triple[0],
299
+ scalar * self._triple[1],
300
+ scalar * self._triple[2],
301
+ check=False)
302
+
303
+ def square(self):
304
+ """
305
+ Return the square of the element.
306
+
307
+ EXAMPLES::
308
+
309
+ sage: B.<t> = PolynomialRing(Integers(125))
310
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
311
+ sage: x, T = R.gens()
312
+
313
+ ::
314
+
315
+ sage: f = R.create_element(1 + 2*t + 3*t^2, 4 + 7*t + 9*t^2, 3 + 5*t + 11*t^2)
316
+ sage: f.square()
317
+ (73*T^5 + 16*T^4 + 38*T^3 + 39*T^2 + 70*T + 120)
318
+ + (121*T^5 + 113*T^4 + 73*T^3 + 8*T^2 + 51*T + 61)*x
319
+ + (18*T^4 + 60*T^3 + 22*T^2 + 108*T + 31)*x^2
320
+ """
321
+ return self * self
322
+
323
+ def _mul_(self, other):
324
+ """
325
+ EXAMPLES::
326
+
327
+ sage: B.<t> = PolynomialRing(Integers(125))
328
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
329
+ sage: x, T = R.gens()
330
+
331
+ ::
332
+
333
+ sage: f = R.create_element(1 + 2*t + 3*t^2, 4 + 7*t + 9*t^2, 3 + 5*t + 11*t^2)
334
+ sage: g = R.create_element(4 + 3*t + 7*t^2, 2 + 3*t + t^2, 8 + 4*t + 6*t^2)
335
+ sage: f * g
336
+ (65*T^5 + 27*T^4 + 33*T^3 + 75*T^2 + 120*T + 57)
337
+ + (66*T^5 + T^4 + 123*T^3 + 95*T^2 + 24*T + 50)*x
338
+ + (45*T^4 + 75*T^3 + 37*T^2 + 2*T + 52)*x^2
339
+ """
340
+ # Here we do Toom-Cook three-way multiplication, which reduces
341
+ # the naive 9 polynomial multiplications to only 5 polynomial
342
+ # multiplications.
343
+
344
+ a0, a1, a2 = self._triple
345
+ b0, b1, b2 = other._triple
346
+ M = self.parent()._speedup_matrix
347
+
348
+ if self is other:
349
+ # faster method if we are squaring
350
+ p0 = a0 * a0
351
+ temp = a0 + 2*a1 + 4*a2
352
+ p1 = temp * temp
353
+ temp = a0 + a1 + a2
354
+ p2 = temp * temp
355
+ temp = 4*a0 + 2*a1 + a2
356
+ p3 = temp * temp
357
+ p4 = a2 * a2
358
+
359
+ else:
360
+ p0 = a0 * b0
361
+ p1 = (a0 + 2*a1 + 4*a2) * (b0 + 2*b1 + 4*b2)
362
+ p2 = (a0 + a1 + a2) * (b0 + b1 + b2)
363
+ p3 = (4*a0 + 2*a1 + a2) * (4*b0 + 2*b1 + b2)
364
+ p4 = a2 * b2
365
+
366
+ q1 = p1 - p0 - 16*p4
367
+ q2 = p2 - p0 - p4
368
+ q3 = p3 - 16*p0 - p4
369
+
370
+ c0 = p0
371
+ c1 = M[0]*q1 + M[1]*q2 + M[2]*q3
372
+ c2 = M[3]*q1 + M[4]*q2 + M[5]*q3
373
+ c3 = M[6]*q1 + M[7]*q2 + M[8]*q3
374
+ c4 = p4
375
+
376
+ # Now the product is c0 + c1 x + c2 x^2 + c3 x^3 + c4 x^4.
377
+ # We need to reduce mod y = x^3 + ax + b and return result.
378
+
379
+ parent = self.parent()
380
+ T = parent._poly_generator
381
+ b = parent._b
382
+ a = parent._a
383
+
384
+ # todo: These lines are necessary to get binop stuff working
385
+ # for certain base rings, e.g. when we compute b*c3 in the
386
+ # final line. They shouldn't be necessary. Need to fix this
387
+ # somewhere else in Sage.
388
+ a = parent._poly_ring(a)
389
+ b = parent._poly_ring(b)
390
+
391
+ return parent.element_class(parent,
392
+ -b*c3 + c0 + c3*T,
393
+ -b*c4 - a*c3 + c1 + c4*T,
394
+ -a*c4 + c2,
395
+ check=False)
396
+
397
+
398
+ class SpecialCubicQuotientRing(UniqueRepresentation, Parent):
399
+ r"""
400
+ Specialised class for representing the quotient ring
401
+ `R[x,T]/(T - x^3 - ax - b)`, where `R` is an
402
+ arbitrary commutative base ring (in which 2 and 3 are invertible),
403
+ `a` and `b` are elements of that ring.
404
+
405
+ Polynomials are represented internally in the form
406
+ `p_0 + p_1 x + p_2 x^2` where the `p_i` are
407
+ polynomials in `T`. Multiplication of polynomials always
408
+ reduces high powers of `x` (i.e. beyond `x^2`) to
409
+ powers of `T`.
410
+
411
+ Hopefully this ring is faster than a general quotient ring because
412
+ it uses the special structure of this ring to speed multiplication
413
+ (which is the dominant operation in the frobenius matrix
414
+ calculation). I haven't actually tested this theory though...
415
+
416
+ .. TODO::
417
+
418
+ Eventually we will want to run this in characteristic 3, so we
419
+ need to: (a) Allow `Q(x)` to contain an `x^2` term, and (b) Remove
420
+ the requirement that 3 be invertible. Currently this is used in
421
+ the Toom-Cook algorithm to speed multiplication.
422
+
423
+ EXAMPLES::
424
+
425
+ sage: B.<t> = PolynomialRing(Integers(125))
426
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
427
+ sage: R
428
+ SpecialCubicQuotientRing over Ring of integers modulo 125
429
+ with polynomial T = x^3 + 124*x + 94
430
+ sage: TestSuite(R).run()
431
+
432
+ Get generators::
433
+
434
+ sage: x, T = R.gens()
435
+ sage: x
436
+ (0) + (1)*x + (0)*x^2
437
+ sage: T
438
+ (T) + (0)*x + (0)*x^2
439
+
440
+ Coercions::
441
+
442
+ sage: R(7)
443
+ (7) + (0)*x + (0)*x^2
444
+
445
+ Create elements directly from polynomials::
446
+
447
+ sage: A = R.poly_ring()
448
+ sage: A
449
+ Univariate Polynomial Ring in T over Ring of integers modulo 125
450
+ sage: z = A.gen()
451
+ sage: R.create_element(z^2, z+1, 3)
452
+ (T^2) + (T + 1)*x + (3)*x^2
453
+
454
+ Some arithmetic::
455
+
456
+ sage: x^3
457
+ (T + 31) + (1)*x + (0)*x^2
458
+ sage: 3 * x**15 * T**2 + x - T
459
+ (3*T^7 + 90*T^6 + 110*T^5 + 20*T^4 + 58*T^3 + 26*T^2 + 124*T) +
460
+ (15*T^6 + 110*T^5 + 35*T^4 + 63*T^2 + 1)*x +
461
+ (30*T^5 + 40*T^4 + 8*T^3 + 38*T^2)*x^2
462
+
463
+ Retrieve coefficients (output is zero-padded)::
464
+
465
+ sage: x^10
466
+ (3*T^2 + 61*T + 8) + (T^3 + 93*T^2 + 12*T + 40)*x + (3*T^2 + 61*T + 9)*x^2
467
+ sage: (x^10).coeffs()
468
+ [[8, 61, 3, 0], [40, 12, 93, 1], [9, 61, 3, 0]]
469
+
470
+ .. TODO::
471
+
472
+ write an example checking multiplication of these polynomials
473
+ against Sage's ordinary quotient ring arithmetic. I cannot seem
474
+ to get the quotient ring stuff happening right now...
475
+ """
476
+ def __init__(self, Q, laurent_series=False):
477
+ """
478
+ Constructor.
479
+
480
+ INPUT:
481
+
482
+ - ``Q`` -- a polynomial of the form
483
+ `Q(x) = x^3 + ax + b`, where `a`, `b` belong to a ring in which
484
+ 2, 3 are invertible.
485
+
486
+ - ``laurent_series`` -- boolean (default: ``False``); whether or not to allow
487
+ negative powers of `T`
488
+
489
+ EXAMPLES::
490
+
491
+ sage: B.<t> = PolynomialRing(Integers(125))
492
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
493
+ sage: R
494
+ SpecialCubicQuotientRing over Ring of integers modulo 125
495
+ with polynomial T = x^3 + 124*x + 94
496
+
497
+ ::
498
+
499
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 + 2*t^2 - t + B(1/4))
500
+ Traceback (most recent call last):
501
+ ...
502
+ ValueError: Q (=t^3 + 2*t^2 + 124*t + 94) must be of the form x^3 + ax + b
503
+
504
+ ::
505
+
506
+ sage: B.<t> = PolynomialRing(Integers(10))
507
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + 1)
508
+ Traceback (most recent call last):
509
+ ...
510
+ ArithmeticError: 2 and 3 must be invertible in the coefficient ring
511
+ (=Ring of integers modulo 10) of Q
512
+ """
513
+ if not isinstance(Q, Polynomial):
514
+ raise TypeError("Q (=%s) must be a polynomial" % Q)
515
+
516
+ if Q.degree() != 3 or not Q[2].is_zero():
517
+ raise ValueError("Q (=%s) must be of the form x^3 + ax + b" % Q)
518
+
519
+ base_ring = Q.parent().base_ring()
520
+
521
+ if not base_ring(6).is_unit():
522
+ raise ArithmeticError("2 and 3 must be invertible in the "
523
+ "coefficient ring (=%s) of Q" % base_ring)
524
+
525
+ self._a = Q[1]
526
+ self._b = Q[0]
527
+ if laurent_series:
528
+ self._poly_ring = LaurentSeriesRing(base_ring, 'T') # R[T]
529
+ else:
530
+ self._poly_ring = PolynomialRing(base_ring, 'T') # R[T]
531
+ self._poly_generator = self._poly_ring.gen(0) # the generator T
532
+ Parent.__init__(self, base=base_ring,
533
+ category=Algebras(base_ring).Commutative())
534
+
535
+ # Precompute a matrix that is used in the Toom-Cook multiplication.
536
+ # This is where we need 2 and 3 invertible.
537
+
538
+ # a good description of Toom-Cook is online at:
539
+ # https://gmplib.org/manual/Multiplication-Algorithms
540
+ m = matrix(QQ, [[1, -12, 2], [-3, 30, -3], [2, -12, 1]]) / 6
541
+ self._speedup_matrix = m.change_ring(base_ring).list()
542
+
543
+ def _repr_(self) -> str:
544
+ """
545
+ String representation.
546
+
547
+ EXAMPLES::
548
+
549
+ sage: B.<t> = PolynomialRing(Integers(125))
550
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
551
+ sage: R
552
+ SpecialCubicQuotientRing over Ring of integers modulo 125
553
+ with polynomial T = x^3 + 124*x + 94
554
+ """
555
+ return "SpecialCubicQuotientRing over %s with polynomial T = %s" % \
556
+ (self.base_ring(), PolynomialRing(self.base_ring(), 'x')(
557
+ [self._b, self._a, 0, 1]))
558
+
559
+ def poly_ring(self):
560
+ """
561
+ Return the underlying polynomial ring in `T`.
562
+
563
+ EXAMPLES::
564
+
565
+ sage: B.<t> = PolynomialRing(Integers(125))
566
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
567
+ sage: R.poly_ring()
568
+ Univariate Polynomial Ring in T over Ring of integers modulo 125
569
+ """
570
+ return self._poly_ring
571
+
572
+ def gens(self) -> tuple:
573
+ """
574
+ Return (x, T) where x and T are the generators of the ring
575
+ (as elements *of this ring*).
576
+
577
+ EXAMPLES::
578
+
579
+ sage: B.<t> = PolynomialRing(Integers(125))
580
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
581
+ sage: x, T = R.gens()
582
+ sage: x
583
+ (0) + (1)*x + (0)*x^2
584
+ sage: T
585
+ (T) + (0)*x + (0)*x^2
586
+ """
587
+ zero = self._poly_ring.zero()
588
+ one = self._poly_ring.one()
589
+ return (self.element_class(self, zero, one, zero, check=False),
590
+ self.element_class(self, self._poly_generator, zero, zero,
591
+ check=False))
592
+
593
+ def _element_constructor_(self, *args, check=True):
594
+ """
595
+ Create the element `p_0 + p_1*x + p_2*x^2`, where the `p_i`
596
+ are polynomials in `T`.
597
+
598
+ INPUT:
599
+
600
+ - ``p0``, ``p1``, ``p2`` -- coefficients; must be coercible
601
+ into poly_ring()
602
+
603
+ - ``check`` -- boolean (default: ``True``); whether to carry
604
+ out coercion
605
+
606
+ EXAMPLES::
607
+
608
+ sage: B.<t> = PolynomialRing(Integers(125))
609
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
610
+ sage: A, z = R.poly_ring().objgen()
611
+ sage: R.create_element(z^2, z+1, 3) # indirect doctest
612
+ (T^2) + (T + 1)*x + (3)*x^2
613
+ """
614
+ if len(args) == 1 and args[0] in self.base_ring():
615
+ p0 = self._poly_ring.coerce(args[0])
616
+ p1 = p2 = self._poly_ring.zero()
617
+ else:
618
+ p0, p1, p2 = args
619
+ return self.element_class(self, p0, p1, p2, check=check)
620
+
621
+ create_element = _element_constructor_
622
+
623
+ @cached_method
624
+ def one(self):
625
+ """
626
+ Return the unit of ``self``.
627
+
628
+ EXAMPLES::
629
+
630
+ sage: B.<t> = PolynomialRing(Integers(125))
631
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
632
+ sage: R.one()
633
+ (1) + (0)*x + (0)*x^2
634
+ """
635
+ R = self._poly_ring
636
+ return self.element_class(self, R.one(), R.zero(), R.zero(), check=False)
637
+
638
+ def _coerce_map_from_(self, R):
639
+ """
640
+ Coercion system.
641
+
642
+ EXAMPLES::
643
+
644
+ sage: Z125 = Integers(125)
645
+ sage: B.<t> = PolynomialRing(Z125)
646
+ sage: R = monsky_washnitzer.SpecialCubicQuotientRing(t^3 - t + B(1/4))
647
+ sage: R.has_coerce_map_from(Z125)
648
+ True
649
+ """
650
+ return self._poly_ring.has_coerce_map_from(R)
651
+
652
+ Element = SpecialCubicQuotientRingElement
653
+
654
+
655
+ def transpose_list(input) -> list[list]:
656
+ """
657
+ INPUT:
658
+
659
+ - ``input`` -- list of lists, each list of the same length
660
+
661
+ OUTPUT: list of lists such that ``output[i][j] = input[j][i]``
662
+
663
+ EXAMPLES::
664
+
665
+ sage: from sage.schemes.hyperelliptic_curves.monsky_washnitzer import transpose_list
666
+ sage: L = [[1, 2], [3, 4], [5, 6]]
667
+ sage: transpose_list(L)
668
+ [[1, 3, 5], [2, 4, 6]]
669
+ """
670
+ w = len(input[0])
671
+ return [[input_j[i] for input_j in input] for i in range(w)]
672
+
673
+
674
+ def helper_matrix(Q):
675
+ r"""
676
+ Compute the (constant) matrix used to calculate the linear
677
+ combinations of the `d(x^i y^j)` needed to eliminate the
678
+ negative powers of `y` in the cohomology (i.e., in
679
+ :func:`reduce_negative`).
680
+
681
+ INPUT:
682
+
683
+ - ``Q`` -- cubic polynomial
684
+
685
+ EXAMPLES::
686
+
687
+ sage: t = polygen(QQ,'t')
688
+ sage: from sage.schemes.hyperelliptic_curves.monsky_washnitzer import helper_matrix
689
+ sage: helper_matrix(t**3-4*t-691)
690
+ [ 64/12891731 -16584/12891731 4297329/12891731]
691
+ [ 6219/12891731 -32/12891731 8292/12891731]
692
+ [ -24/12891731 6219/12891731 -32/12891731]
693
+ """
694
+ a = Q[1]
695
+ b = Q[0]
696
+
697
+ # Discriminant (should be invertible for a curve of good reduction)
698
+ D = 4*a**3 + 27*b**2
699
+ Dinv = D**(-1) # NB do not use 1/D
700
+
701
+ # This is the inverse of the matrix
702
+ # [ a, -3b, 0 ]
703
+ # [ 0, -2a, -3b ]
704
+ # [ 3, 0, -2a ]
705
+
706
+ return Dinv * matrix([[4*a**2, -6*b*a, 9*b**2],
707
+ [-9*b, -2*a**2, 3*b*a],
708
+ [6*a, -9*b, -2*a**2]])
709
+
710
+
711
+ def lift(x):
712
+ r"""
713
+ Try to call ``x.lift()``, presumably from the `p`-adics to `\ZZ`.
714
+
715
+ If this fails, it assumes the input is a power series, and tries to
716
+ lift it to a power series over `\QQ`.
717
+
718
+ This function is just a very kludgy solution to the problem of
719
+ trying to make the reduction code (below) work over both `\ZZ_p` and
720
+ `\ZZ_p[[t]]`.
721
+
722
+ EXAMPLES::
723
+
724
+ sage: # needs sage.rings.padics
725
+ sage: from sage.schemes.hyperelliptic_curves.monsky_washnitzer import lift
726
+ sage: l = lift(Qp(13)(131)); l
727
+ 131
728
+ sage: l.parent()
729
+ Integer Ring
730
+ sage: x = PowerSeriesRing(Qp(17),'x').gen()
731
+ sage: l = lift(4 + 5*x + 17*x**6); l
732
+ 4 + 5*t + 17*t^6
733
+ sage: l.parent()
734
+ Power Series Ring in t over Rational Field
735
+ """
736
+ try:
737
+ return x.lift()
738
+ except AttributeError:
739
+ return PowerSeriesRing(Rationals(), "t")(x.list(), x.prec())
740
+
741
+
742
+ def reduce_negative(Q, p, coeffs, offset, exact_form=None):
743
+ """
744
+ Apply cohomology relations to incorporate negative powers of
745
+ `y` into the `y^0` term.
746
+
747
+ INPUT:
748
+
749
+ - ``p`` -- prime
750
+
751
+ - ``Q`` -- cubic polynomial
752
+
753
+ - ``coeffs`` -- list of length 3 lists. The
754
+ `i`-th list ``[a, b, c]`` represents
755
+ `y^{2(i - offset)} (a + bx + cx^2) dx/y`.
756
+
757
+ - ``offset`` -- nonnegative integer
758
+
759
+ OUTPUT:
760
+
761
+ The reduction is performed in-place. The output is placed
762
+ in coeffs[offset]. Note that coeffs[i] will be meaningless for i
763
+ offset after this function is finished.
764
+
765
+ EXAMPLES::
766
+
767
+ sage: R.<x> = Integers(5^3)['x']
768
+ sage: Q = x^3 - x + R(1/4)
769
+ sage: coeffs = [[10, 15, 20], [1, 2, 3], [4, 5, 6], [7, 8, 9]]
770
+ sage: coeffs = [[R.base_ring()(a) for a in row] for row in coeffs]
771
+ sage: monsky_washnitzer.reduce_negative(Q, 5, coeffs, 3)
772
+ sage: coeffs[3]
773
+ [28, 52, 9]
774
+
775
+ ::
776
+
777
+ sage: R.<x> = Integers(7^3)['x']
778
+ sage: Q = x^3 - x + R(1/4)
779
+ sage: coeffs = [[7, 14, 21], [1, 2, 3], [4, 5, 6], [7, 8, 9]]
780
+ sage: coeffs = [[R.base_ring()(a) for a in row] for row in coeffs]
781
+ sage: monsky_washnitzer.reduce_negative(Q, 7, coeffs, 3)
782
+ sage: coeffs[3]
783
+ [245, 332, 9]
784
+ """
785
+
786
+ m = helper_matrix(Q).list()
787
+ base_ring = Q.base_ring()
788
+ next_a = coeffs[0]
789
+
790
+ if exact_form is not None:
791
+ x = exact_form.parent().gen(0)
792
+ y = exact_form.parent()(exact_form.parent().base_ring().gen(0))
793
+
794
+ try:
795
+ three_j_plus_5 = 5 - base_ring(6*offset)
796
+ three_j_plus_7 = 7 - base_ring(6*offset)
797
+ six = base_ring(6)
798
+
799
+ for i in range(offset):
800
+
801
+ j = 2*(i-offset)
802
+ a = next_a
803
+ next_a = coeffs[i+1]
804
+
805
+ # todo: the following divisions will sometimes involve
806
+ # a division by (a power of) p. In all cases, we know (from
807
+ # Kedlaya's estimates) that the answer should be p-integral.
808
+ # However, since we're working over $Z/p^k Z$, we're not allowed
809
+ # to "divide by p". So currently we lift to Q, divide, and coerce
810
+ # back. Eventually, when pAdicInteger is implemented, and plays
811
+ # nicely with pAdicField, we should reimplement this stuff
812
+ # using pAdicInteger.
813
+
814
+ if (p.divides(j+1)):
815
+ # need to lift here to perform the division
816
+ a[0] = base_ring(lift(a[0]) / (j+1))
817
+ a[1] = base_ring(lift(a[1]) / (j+1))
818
+ a[2] = base_ring(lift(a[2]) / (j+1))
819
+ else:
820
+ j_plus_1_inv = ~base_ring(j+1)
821
+ a[0] = a[0] * j_plus_1_inv
822
+ a[1] = a[1] * j_plus_1_inv
823
+ a[2] = a[2] * j_plus_1_inv
824
+
825
+ c1 = m[3]*a[0] + m[4]*a[1] + m[5]*a[2]
826
+ c2 = m[6]*a[0] + m[7]*a[1] + m[8]*a[2]
827
+ next_a[0] = next_a[0] - three_j_plus_5 * c1
828
+ next_a[1] = next_a[1] - three_j_plus_7 * c2
829
+
830
+ three_j_plus_7 = three_j_plus_7 + six
831
+ three_j_plus_5 = three_j_plus_5 + six
832
+
833
+ if exact_form is not None:
834
+ c0 = m[0]*a[0] + m[1]*a[1] + m[2]*a[2]
835
+ exact_form += (c0 + c1*x + c2 * x**2) * y**(j+1)
836
+
837
+ except NotImplementedError:
838
+ raise NotImplementedError("It looks like you've found a "
839
+ "non-integral matrix of Frobenius! "
840
+ "(Q=%s, p=%s)\nTime to write a paper." % (Q, p))
841
+
842
+ coeffs[int(offset)] = next_a
843
+
844
+ return exact_form
845
+
846
+
847
+ def reduce_positive(Q, p, coeffs, offset, exact_form=None):
848
+ """
849
+ Apply cohomology relations to incorporate positive powers of
850
+ `y` into the `y^0` term.
851
+
852
+ INPUT:
853
+
854
+ - ``Q`` -- cubic polynomial
855
+
856
+ - ``coeffs`` -- list of length 3 lists. The
857
+ `i`-th list [a, b, c] represents
858
+ `y^{2(i - offset)} (a + bx + cx^2) dx/y`.
859
+
860
+ - ``offset`` -- nonnegative integer
861
+
862
+ OUTPUT:
863
+
864
+ The reduction is performed in-place. The output is placed
865
+ in coeffs[offset]. Note that coeffs[i] will be meaningless for i
866
+ offset after this function is finished.
867
+
868
+ EXAMPLES::
869
+
870
+ sage: R.<x> = Integers(5^3)['x']
871
+ sage: Q = x^3 - x + R(1/4)
872
+
873
+ ::
874
+
875
+ sage: coeffs = [[1, 2, 3], [10, 15, 20]]
876
+ sage: coeffs = [[R.base_ring()(a) for a in row] for row in coeffs]
877
+ sage: monsky_washnitzer.reduce_positive(Q, 5, coeffs, 0)
878
+ sage: coeffs[0]
879
+ [16, 102, 88]
880
+
881
+ ::
882
+
883
+ sage: coeffs = [[9, 8, 7], [10, 15, 20]]
884
+ sage: coeffs = [[R.base_ring()(a) for a in row] for row in coeffs]
885
+ sage: monsky_washnitzer.reduce_positive(Q, 5, coeffs, 0)
886
+ sage: coeffs[0]
887
+ [24, 108, 92]
888
+ """
889
+
890
+ base_ring = Q.base_ring()
891
+ next_a = coeffs[len(coeffs) - 1]
892
+
893
+ Qa = Q[1]
894
+ Qb = Q[0]
895
+
896
+ A = 2*Qa
897
+ B = 3*Qb
898
+
899
+ offset = Integer(offset)
900
+
901
+ if exact_form is not None:
902
+ x = exact_form.parent().gen(0)
903
+ y = exact_form.parent().base_ring().gen(0)
904
+ # y = exact_form.parent()(exact_form.parent().base_ring().gen(0))
905
+
906
+ for i in range(len(coeffs)-1, offset, -1):
907
+ j = 2*(i-offset) - 2
908
+ a = next_a
909
+ next_a = coeffs[i-1]
910
+
911
+ a[0] = a[0] - Qa*a[2]/3 # subtract d(y^j + 3)
912
+ if exact_form is not None:
913
+ exact_form += Q.base_ring()(a[2].lift() / (3*j+9)) * y**(j+3)
914
+
915
+ # todo: see comments about pAdicInteger in reduceNegative()
916
+
917
+ # subtract off c1 of d(x y^j + 1), and
918
+ if p.divides(3*j + 5):
919
+ c1 = base_ring(lift(a[0]) / (3*j + 5))
920
+ else:
921
+ c1 = a[0] / (3*j + 5)
922
+
923
+ # subtract off c2 of d(x^2 y^j + 1)
924
+ if p.divides(3*j + 7):
925
+ c2 = base_ring(lift(a[1]) / (3*j + 7))
926
+ else:
927
+ c2 = a[1] / (3*j + 7)
928
+
929
+ next_a[0] = next_a[0] + B*c1*(j+1)
930
+ next_a[1] = next_a[1] + A*c1*(j+1) + B*c2*(j+1)
931
+ next_a[2] = next_a[2] + A*c2*(j+1)
932
+
933
+ if exact_form is not None:
934
+ exact_form += (c1*x + c2 * x**2) * y**(j+1)
935
+
936
+ coeffs[int(offset)] = next_a
937
+
938
+ return exact_form
939
+
940
+
941
+ def reduce_zero(Q, coeffs, offset, exact_form=None):
942
+ """
943
+ Apply cohomology relation to incorporate `x^2 y^0` term
944
+ into `x^0 y^0` and `x^1 y^0` terms.
945
+
946
+ INPUT:
947
+
948
+ - ``Q`` -- cubic polynomial
949
+
950
+ - ``coeffs`` -- list of length 3 lists. The
951
+ `i`-th list [a, b, c] represents
952
+ `y^{2(i - offset)} (a + bx + cx^2) dx/y`.
953
+
954
+ - ``offset`` -- nonnegative integer
955
+
956
+ OUTPUT:
957
+
958
+ The reduction is performed in-place. The output is placed
959
+ in coeffs[offset]. This method completely ignores coeffs[i] for i
960
+ != offset.
961
+
962
+ EXAMPLES::
963
+
964
+ sage: R.<x> = Integers(5^3)['x']
965
+ sage: Q = x^3 - x + R(1/4)
966
+ sage: coeffs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
967
+ sage: coeffs = [[R.base_ring()(a) for a in row] for row in coeffs]
968
+ sage: monsky_washnitzer.reduce_zero(Q, coeffs, 1)
969
+ sage: coeffs[1]
970
+ [6, 5, 0]
971
+ """
972
+
973
+ a = coeffs[int(offset)]
974
+ if a[2] == 0:
975
+ return exact_form
976
+
977
+ Qa = Q[1]
978
+
979
+ a[0] = a[0] - a[2]*Qa/3 # $3x^2 dx/y = -a dx/y$
980
+
981
+ coeffs[int(offset)] = a
982
+
983
+ if exact_form is not None:
984
+ y = exact_form.parent()(exact_form.parent().base_ring().gen(0))
985
+ exact_form += Q.base_ring()(a[2] / 3) * y
986
+
987
+ a[2] = 0
988
+
989
+ coeffs[int(offset)] = a
990
+ return exact_form
991
+
992
+
993
+ def reduce_all(Q, p, coeffs, offset, compute_exact_form=False):
994
+ """
995
+ Apply cohomology relations to reduce all terms to a linear
996
+ combination of `dx/y` and `x dx/y`.
997
+
998
+ INPUT:
999
+
1000
+ - ``Q`` -- cubic polynomial
1001
+
1002
+ - ``coeffs`` -- list of length 3 lists. The
1003
+ `i`-th list [a, b, c] represents
1004
+ `y^{2(i - offset)} (a + bx + cx^2) dx/y`.
1005
+
1006
+ - ``offset`` -- nonnegative integer
1007
+
1008
+ OUTPUT:
1009
+
1010
+ - ``A``, ``B`` -- pair such that the input differential is
1011
+ cohomologous to (A + Bx) dx/y
1012
+
1013
+ .. NOTE::
1014
+
1015
+ The algorithm operates in-place, so the data in coeffs is
1016
+ destroyed.
1017
+
1018
+ EXAMPLES::
1019
+
1020
+ sage: R.<x> = Integers(5^3)['x']
1021
+ sage: Q = x^3 - x + R(1/4)
1022
+ sage: coeffs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
1023
+ sage: coeffs = [[R.base_ring()(a) for a in row] for row in coeffs]
1024
+ sage: monsky_washnitzer.reduce_all(Q, 5, coeffs, 1)
1025
+ (21, 106)
1026
+ """
1027
+
1028
+ R = Q.base_ring()
1029
+
1030
+ if compute_exact_form:
1031
+ # exact_form = SpecialCubicQuotientRing(Q, laurent_series=True)(0)
1032
+ exact_form = PolynomialRing(LaurentSeriesRing(Q.base_ring(), 'y'), 'x').zero()
1033
+ # t = (Q.base_ring().order().factor())[0]
1034
+ # from sage.rings.padics.qp import pAdicField
1035
+ # exact_form = PolynomialRing(LaurentSeriesRing(pAdicField(p, t[1]), 'y'), 'x')(0)
1036
+ else:
1037
+ exact_form = None
1038
+
1039
+ while len(coeffs) <= offset:
1040
+ coeffs.append([R(0), R(0), R(0)])
1041
+
1042
+ exact_form = reduce_negative(Q, p, coeffs, offset, exact_form)
1043
+ exact_form = reduce_positive(Q, p, coeffs, offset, exact_form)
1044
+ exact_form = reduce_zero(Q, coeffs, offset, exact_form)
1045
+
1046
+ if exact_form is None:
1047
+ return coeffs[int(offset)][0], coeffs[int(offset)][1]
1048
+ else:
1049
+ return (coeffs[int(offset)][0], coeffs[int(offset)][1]), exact_form
1050
+
1051
+
1052
+ def frobenius_expansion_by_newton(Q, p, M):
1053
+ r"""
1054
+ Compute the action of Frobenius on `dx/y` and on
1055
+ `x dx/y`, using Newton's method (as suggested in Kedlaya's
1056
+ paper [Ked2001]_).
1057
+
1058
+ (This function does *not* yet use the cohomology relations - that
1059
+ happens afterwards in the "reduction" step.)
1060
+
1061
+ More specifically, it finds `F_0` and `F_1` in
1062
+ the quotient ring `R[x, T]/(T - Q(x))`, such that
1063
+
1064
+ .. MATH::
1065
+
1066
+ F( dx/y) = T^{-r} F0 dx/y, \text{\ and\ } F(x dx/y) = T^{-r} F1 dx/y
1067
+
1068
+ where
1069
+
1070
+ .. MATH::
1071
+
1072
+ r = ( (2M-3)p - 1 )/2.
1073
+
1074
+
1075
+ (Here `T` is `y^2 = z^{-2}`, and `R` is the
1076
+ coefficient ring of `Q`.)
1077
+
1078
+ `F_0` and `F_1` are computed in the
1079
+ :class:`SpecialCubicQuotientRing` associated to `Q`, so all powers
1080
+ of `x^j` for `j \geq 3` are reduced to powers of
1081
+ `T`.
1082
+
1083
+ INPUT:
1084
+
1085
+ - ``Q`` -- cubic polynomial of the form
1086
+ `Q(x) = x^3 + ax + b`, whose coefficient ring is a
1087
+ `Z/(p^M)Z`-algebra
1088
+
1089
+ - ``p`` -- residue characteristic of the `p`-adic field
1090
+
1091
+ - ``M`` -- `p`-adic precision of the coefficient ring
1092
+ (this will be used to determine the number of Newton iterations)
1093
+
1094
+ OUTPUT:
1095
+
1096
+ - ``F0``, ``F1`` -- elements of
1097
+ ``SpecialCubicQuotientRing(Q)``, as described above
1098
+
1099
+ - ``r`` -- nonnegative integer, as described above
1100
+
1101
+ EXAMPLES::
1102
+
1103
+ sage: from sage.schemes.hyperelliptic_curves.monsky_washnitzer import frobenius_expansion_by_newton
1104
+ sage: R.<x> = Integers(5^3)['x']
1105
+ sage: Q = x^3 - x + R(1/4)
1106
+ sage: frobenius_expansion_by_newton(Q,5,3)
1107
+ ((25*T^5 + 75*T^3 + 100*T^2 + 100*T + 100) + (5*T^6 + 80*T^5 + 100*T^3
1108
+ + 25*T + 50)*x + (55*T^5 + 50*T^4 + 75*T^3 + 25*T^2 + 25*T + 25)*x^2,
1109
+ (5*T^8 + 15*T^7 + 95*T^6 + 10*T^5 + 25*T^4 + 25*T^3 + 100*T^2 + 50)
1110
+ + (65*T^7 + 55*T^6 + 70*T^5 + 100*T^4 + 25*T^2 + 100*T)*x
1111
+ + (15*T^6 + 115*T^5 + 75*T^4 + 100*T^3 + 50*T^2 + 75*T + 75)*x^2, 7)
1112
+ """
1113
+
1114
+ S = SpecialCubicQuotientRing(Q)
1115
+ x, _ = S.gens() # T = y^2
1116
+ base_ring = S.base_ring()
1117
+
1118
+ # When we compute Frob(1/y) we actually only need precision M-1, since
1119
+ # we're going to multiply by p at the end anyway.
1120
+ M = float(M - 1)
1121
+
1122
+ # Kedlaya sets s = Q(x^p)/T^p = 1 + p T^{-p} E, where
1123
+ # E = (Q(x^p) - Q(x)^p) / p (has integral coefficients).
1124
+ # Then he computes s^{-1/2} in S, using Newton's method to find
1125
+ # successive approximations. We follow this plan, but we normalise our
1126
+ # approximations so that we only ever need positive powers of T.
1127
+
1128
+ # Start by setting r = Q(x^p)/2 = 1/2 T^p s.
1129
+ # (The 1/2 is for convenience later on.)
1130
+ x_to_p_less_one = x**(p-1)
1131
+ x_to_p = x_to_p_less_one * x
1132
+ x_to_p_cubed = x_to_p.square() * x_to_p
1133
+ r = (base_ring(1) / base_ring(2)) * (x_to_p_cubed + Q[1]*x_to_p + S(Q[0]))
1134
+
1135
+ # todo: this next loop would be clearer if it used the newton_method_sizes()
1136
+ # function
1137
+
1138
+ # We will start with a hard-coded initial approximation, which we provide
1139
+ # up to precision 3. First work out what precision is best to start with.
1140
+ if M <= 3:
1141
+ initial_precision = M
1142
+ elif ceil(log(M/2, 2)) == ceil(log(M/3, 2)):
1143
+ # In this case there is no advantage to starting with precision three,
1144
+ # because we'll overshoot at the end. E.g. suppose the final precision
1145
+ # is 8. If we start with precision 2, we need two iterations to get us
1146
+ # to 8. If we start at precision 3, we will still need two iterations,
1147
+ # but we do more work along the way. So may as well start with only 2.
1148
+ initial_precision = 2
1149
+ else:
1150
+ initial_precision = 3
1151
+
1152
+ # Now compute the first approximation. In the main loop below, X is the
1153
+ # normalised approximation, and k is the precision. More specifically,
1154
+ # X = T^{p(k-1)} x_i, where x_i is an approximation to s^{-1/2}, and the
1155
+ # approximation is correct mod p^k.
1156
+ if initial_precision == 1:
1157
+ k = 1
1158
+ X = S(1)
1159
+ elif initial_precision == 2:
1160
+ # approximation is 3/2 - 1/2 s
1161
+ k = 2
1162
+ X = S(base_ring(3) / base_ring(2)).shift(p) - r
1163
+ elif initial_precision == 3:
1164
+ # approximation is (15 - 10 s + 3 s^2) / 8
1165
+ k = 3
1166
+ X = (base_ring(1) / base_ring(8)) * (S(15).shift(2*p)
1167
+ - (base_ring(20) * r).shift(p) +
1168
+ (base_ring(12) * r.square()))
1169
+ # The key to the following calculation is that the T^{-m} coefficient
1170
+ # of every x_i is divisible by p^(ceil(m/p)) (for m >= 0). Therefore if
1171
+ # we are only expecting an answer correct mod p^k, we can truncate
1172
+ # beyond the T^{-(k-1)p} term without any problems.
1173
+
1174
+ # todo: what would be really nice is to be able to work in a lower
1175
+ # precision *coefficient ring* when we start the iteration, and move up to
1176
+ # higher precision rings as the iteration proceeds. This would be feasible
1177
+ # over Integers(p**n), but quite complicated (maybe impossible) over a more
1178
+ # general base ring. This might give a decent constant factor speedup;
1179
+ # or it might not, depending on how much the last iteration dominates the
1180
+ # whole runtime. My guess is that it isn't worth the effort.
1181
+
1182
+ three_halves = base_ring(3) / base_ring(2)
1183
+
1184
+ # Newton iteration loop
1185
+ while k < M:
1186
+ # target_k = k' = precision we want our answer to be after this iteration
1187
+ target_k = 2*k
1188
+
1189
+ # This prevents us overshooting. For example if the current precision
1190
+ # is 3 and we want to get to 10, we're better off going up to 5
1191
+ # instead of 6, because it is less work to get from 5 to 10 than it
1192
+ # is to get from 6 to 10.
1193
+ if ceil(log(M/target_k, 2)) == ceil(log(M/(target_k-1), 2)):
1194
+ target_k -= 1
1195
+
1196
+ # temp = T^{p(3k-2)} 1/2 s x_i^3
1197
+ temp = X.square() * (X * r)
1198
+
1199
+ # We know that the final result is only going to be correct mod
1200
+ # p^(target_k), so we might as well truncate the extraneous terms now.
1201
+ # temp = T^{p(k'-1)} 1/2 s x_i^3
1202
+ temp = temp.shift(-p*(3*k - target_k - 1))
1203
+
1204
+ # X = T^{p(k'-1)} (3/2 x_i - 1/2 s x_i^3)
1205
+ # = T^{p(k'-1)} x_{i+1}
1206
+ X = (three_halves * X).shift(p*(target_k - k)) - temp
1207
+
1208
+ k = target_k
1209
+
1210
+ # Now k should equal M, since we're up to the correct precision
1211
+ assert k == M, "Oops, something went wrong in the iteration"
1212
+
1213
+ # We should have s^{-1/2} correct to precision M.
1214
+ # The following line can be uncommented to verify this.
1215
+ # (It is a slow verification though, can double the whole computation time.)
1216
+
1217
+ # assert (p * X.square() * r * base_ring(2)).coeffs() == \
1218
+ # R(p).shift(p*(2*M - 1)).coeffs()
1219
+
1220
+ # Finally incorporate frobenius of dx and x dx, and choose offset that
1221
+ # compensates for our normalisations by powers of T.
1222
+ F0 = base_ring(p) * x_to_p_less_one * X
1223
+ F1 = F0 * x_to_p
1224
+ offset = ((2*k-1)*p - 1)/2
1225
+
1226
+ return F0, F1, offset
1227
+
1228
+
1229
+ def frobenius_expansion_by_series(Q, p, M):
1230
+ r"""
1231
+ Compute the action of Frobenius on `dx/y` and on `x dx/y`, using a
1232
+ series expansion.
1233
+
1234
+ (This function computes the same thing as
1235
+ frobenius_expansion_by_newton(), using a different method.
1236
+ Theoretically the Newton method should be asymptotically faster,
1237
+ when the precision gets large. However, in practice, this functions
1238
+ seems to be marginally faster for moderate precision, so I'm
1239
+ keeping it here until I figure out exactly why it is faster.)
1240
+
1241
+ (This function does *not* yet use the cohomology relations - that
1242
+ happens afterwards in the "reduction" step.)
1243
+
1244
+ More specifically, it finds F0 and F1 in the quotient ring
1245
+ `R[x, T]/(T - Q(x))`, such that
1246
+ `F( dx/y) = T^{-r} F0 dx/y`, and
1247
+ `F(x dx/y) = T^{-r} F1 dx/y` where
1248
+ `r = ( (2M-3)p - 1 )/2`. (Here `T` is `y^2 = z^{-2}`,
1249
+ and `R` is the coefficient ring of `Q`.)
1250
+
1251
+ `F_0` and `F_1` are computed in the
1252
+ :class:`SpecialCubicQuotientRing` associated to `Q`, so all powers
1253
+ of `x^j` for `j \geq 3` are reduced to powers of
1254
+ `T`.
1255
+
1256
+ It uses the sum
1257
+
1258
+ .. MATH::
1259
+
1260
+ F0 = \sum_{k=0}^{M-2} \binom{-1/2}{k} p x^{p-1} E^k T^{(M-2-k)p}
1261
+
1262
+ and
1263
+
1264
+ .. MATH::
1265
+
1266
+ F1 = x^p F0,
1267
+
1268
+ where `E = Q(x^p) - Q(x)^p`.
1269
+
1270
+ INPUT:
1271
+
1272
+ - ``Q`` -- cubic polynomial of the form
1273
+ `Q(x) = x^3 + ax + b`, whose coefficient ring is a
1274
+ `\ZZ/(p^M)\ZZ` -algebra
1275
+
1276
+ - ``p`` -- residue characteristic of the `p`-adic field
1277
+
1278
+ - ``M`` -- `p`-adic precision of the coefficient ring
1279
+ (this will be used to determine the number of terms in the
1280
+ series)
1281
+
1282
+ OUTPUT:
1283
+
1284
+ - ``F0``, ``F1`` -- elements of
1285
+ ``SpecialCubicQuotientRing(Q)``, as described above
1286
+
1287
+ - ``r`` -- nonnegative integer, as described above
1288
+
1289
+ EXAMPLES::
1290
+
1291
+ sage: from sage.schemes.hyperelliptic_curves.monsky_washnitzer import frobenius_expansion_by_series
1292
+ sage: R.<x> = Integers(5^3)['x']
1293
+ sage: Q = x^3 - x + R(1/4)
1294
+ sage: frobenius_expansion_by_series(Q,5,3) # needs sage.libs.pari
1295
+ ((25*T^5 + 75*T^3 + 100*T^2 + 100*T + 100) + (5*T^6 + 80*T^5 + 100*T^3
1296
+ + 25*T + 50)*x + (55*T^5 + 50*T^4 + 75*T^3 + 25*T^2 + 25*T + 25)*x^2,
1297
+ (5*T^8 + 15*T^7 + 95*T^6 + 10*T^5 + 25*T^4 + 25*T^3 + 100*T^2 + 50)
1298
+ + (65*T^7 + 55*T^6 + 70*T^5 + 100*T^4 + 25*T^2 + 100*T)*x
1299
+ + (15*T^6 + 115*T^5 + 75*T^4 + 100*T^3 + 50*T^2 + 75*T + 75)*x^2, 7)
1300
+ """
1301
+
1302
+ S = SpecialCubicQuotientRing(Q)
1303
+ x, _ = S.gens()
1304
+ base_ring = S.base_ring()
1305
+
1306
+ x_to_p_less_1 = x**(p-1)
1307
+ x_to_p = x_to_p_less_1 * x
1308
+
1309
+ # compute frobQ = Q(x^p)
1310
+ x_to_p_squared = x_to_p * x_to_p
1311
+ x_to_p_cubed = x_to_p_squared * x_to_p
1312
+ frobQ = x_to_p_cubed + Q[1]*x_to_p + Q[0]*S.one()
1313
+ # anticipating the day when p = 3 is supported:
1314
+ # frobQ = x_to_p_cubed + Q[2]*x_to_p_squared + Q[1]*x_to_p + Q[0]*S(1)
1315
+
1316
+ E = frobQ - S.one().shift(p) # E = Q(x^p) - Q(x)^p
1317
+
1318
+ offset = int(((2*M-3)*p-1) / 2)
1319
+ term = p * x_to_p_less_1
1320
+ F0 = term.shift((M-2) * p)
1321
+
1322
+ # todo: Possible speedup idea, perhaps by a factor of 2, but
1323
+ # it requires a lot of work:
1324
+ # Note that p divides E, so p^k divides E^k. So when we are
1325
+ # working with high powers of E, we're doing a lot more work
1326
+ # in the multiplications than we need to. To take advantage of
1327
+ # this we would need some protocol for "lowering the precision"
1328
+ # of a SpecialCubicQuotientRing. This would be quite messy to
1329
+ # do properly over an arbitrary base ring. Perhaps it is
1330
+ # feasible to do for the most common case (i.e. Z/p^nZ).
1331
+ # (but it probably won't save much time unless p^n is very
1332
+ # large, because the machine word size is probably pretty
1333
+ # big anyway.)
1334
+
1335
+ for k in range(1, int(M - 1)):
1336
+ term = term * E
1337
+ c = base_ring(binomial(QQ((-1, 2)), k))
1338
+ F0 += (term * c).shift((M - k - 2) * p)
1339
+
1340
+ return F0, F0 * x_to_p, offset
1341
+
1342
+
1343
+ def adjusted_prec(p, prec):
1344
+ r"""
1345
+ Compute how much precision is required in ``matrix_of_frobenius`` to
1346
+ get an answer correct to ``prec`` `p`-adic digits.
1347
+
1348
+ The issue is that the algorithm used in
1349
+ :func:`matrix_of_frobenius` sometimes performs divisions by `p`,
1350
+ so precision is lost during the algorithm.
1351
+
1352
+ The estimate returned by this function is based on Kedlaya's result
1353
+ (Lemmas 2 and 3 of [Ked2001]_),
1354
+ which implies that if we start with `M` `p`-adic
1355
+ digits, the total precision loss is at most
1356
+ `1 + \lfloor \log_p(2M-3) \rfloor` `p`-adic
1357
+ digits. (This estimate is somewhat less than the amount you would
1358
+ expect by naively counting the number of divisions by
1359
+ `p`.)
1360
+
1361
+ INPUT:
1362
+
1363
+ - ``p`` -- a prime ``p >= 5``
1364
+
1365
+ - ``prec`` -- integer; desired output precision, ``prec >= 1``
1366
+
1367
+ OUTPUT: adjusted precision (usually slightly more than ``prec``)
1368
+
1369
+ EXAMPLES::
1370
+
1371
+ sage: from sage.schemes.hyperelliptic_curves.monsky_washnitzer import adjusted_prec
1372
+ sage: adjusted_prec(5,2)
1373
+ 3
1374
+ """
1375
+ # initial estimate:
1376
+ if prec <= 2:
1377
+ defect = 0
1378
+ adjusted = 2
1379
+ else:
1380
+ defect = Integer(2 * prec - 3).exact_log(p)
1381
+ adjusted = prec + defect - 1
1382
+
1383
+ # increase it until we have enough
1384
+ while adjusted - defect - 1 < prec:
1385
+ adjusted += 1
1386
+
1387
+ return adjusted
1388
+
1389
+
1390
+ def matrix_of_frobenius(Q, p, M, trace=None, compute_exact_forms=False):
1391
+ r"""
1392
+ Compute the matrix of Frobenius on Monsky-Washnitzer cohomology,
1393
+ with respect to the basis `(dx/y, x dx/y)`.
1394
+
1395
+ INPUT:
1396
+
1397
+ - ``Q`` -- cubic polynomial `Q(x) = x^3 + ax + b`
1398
+ defining an elliptic curve `E` by
1399
+ `y^2 = Q(x)`. The coefficient ring of `Q` should be a
1400
+ `\ZZ/(p^M)\ZZ`-algebra in which the matrix of
1401
+ frobenius will be constructed.
1402
+
1403
+ - ``p`` -- prime >= 5 for which E has good reduction
1404
+
1405
+ - ``M`` -- integer >= 2; `p` -adic precision of the coefficient ring
1406
+
1407
+ - ``trace`` -- (optional) the trace of the matrix, if
1408
+ known in advance. This is easy to compute because it is just the
1409
+ `a_p` of the curve. If the trace is supplied,
1410
+ matrix_of_frobenius will use it to speed the computation (i.e. we
1411
+ know the determinant is `p`, so we have two conditions, so
1412
+ really only column of the matrix needs to be computed. it is
1413
+ actually a little more complicated than that, but that's the basic
1414
+ idea.) If trace=None, then both columns will be computed
1415
+ independently, and you can get a strong indication of correctness
1416
+ by verifying the trace afterwards.
1417
+
1418
+ .. WARNING::
1419
+
1420
+ THE RESULT WILL NOT NECESSARILY BE CORRECT TO M p-ADIC
1421
+ DIGITS. If you want prec digits of precision, you need to use
1422
+ the function adjusted_prec(), and then you need to reduce the
1423
+ answer mod `p^{\mathrm{prec}}` at the end.
1424
+
1425
+ OUTPUT:
1426
+
1427
+ `2 \times 2` matrix of Frobenius acting on Monsky-Washnitzer cohomology,
1428
+ with entries in the coefficient ring of ``Q``.
1429
+
1430
+ EXAMPLES:
1431
+
1432
+ A simple example::
1433
+
1434
+ sage: p = 5
1435
+ sage: prec = 3
1436
+ sage: M = monsky_washnitzer.adjusted_prec(p, prec); M
1437
+ 4
1438
+ sage: R.<x> = PolynomialRing(Integers(p**M))
1439
+ sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 - x + R(1/4), p, M)
1440
+ sage: A
1441
+ [340 62]
1442
+ [ 70 533]
1443
+
1444
+ But the result is only accurate to ``prec`` digits::
1445
+
1446
+ sage: B = A.change_ring(Integers(p**prec))
1447
+ sage: B
1448
+ [90 62]
1449
+ [70 33]
1450
+
1451
+ Check trace (123 = -2 mod 125) and determinant::
1452
+
1453
+ sage: B.det()
1454
+ 5
1455
+ sage: B.trace()
1456
+ 123
1457
+ sage: EllipticCurve([-1, 1/4]).ap(5)
1458
+ -2
1459
+
1460
+ Try using the trace to speed up the calculation::
1461
+
1462
+ sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 - x + R(1/4),
1463
+ ....: p, M, -2)
1464
+ sage: A
1465
+ [ 90 62]
1466
+ [320 533]
1467
+
1468
+ Hmmm... it looks different, but that's because the trace of our
1469
+ first answer was only -2 modulo `5^3`, not -2 modulo
1470
+ `5^5`. So the right answer is::
1471
+
1472
+ sage: A.change_ring(Integers(p**prec))
1473
+ [90 62]
1474
+ [70 33]
1475
+
1476
+ Check it works with only one digit of precision::
1477
+
1478
+ sage: p = 5
1479
+ sage: prec = 1
1480
+ sage: M = monsky_washnitzer.adjusted_prec(p, prec)
1481
+ sage: R.<x> = PolynomialRing(Integers(p**M))
1482
+ sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 - x + R(1/4), p, M)
1483
+ sage: A.change_ring(Integers(p))
1484
+ [0 2]
1485
+ [0 3]
1486
+
1487
+ Here is an example that is particularly badly conditioned for
1488
+ using the trace trick::
1489
+
1490
+ sage: # needs sage.libs.pari
1491
+ sage: p = 11
1492
+ sage: prec = 3
1493
+ sage: M = monsky_washnitzer.adjusted_prec(p, prec)
1494
+ sage: R.<x> = PolynomialRing(Integers(p**M))
1495
+ sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 + 7*x + 8, p, M)
1496
+ sage: A.change_ring(Integers(p**prec))
1497
+ [1144 176]
1498
+ [ 847 185]
1499
+
1500
+ The problem here is that the top-right entry is divisible by 11,
1501
+ and the bottom-left entry is divisible by `11^2`. So when
1502
+ you apply the trace trick, neither `F(dx/y)` nor
1503
+ `F(x dx/y)` is enough to compute the whole matrix to the
1504
+ desired precision, even if you try increasing the target precision
1505
+ by one. Nevertheless, ``matrix_of_frobenius`` knows
1506
+ how to get the right answer by evaluating `F((x+1) dx/y)`
1507
+ instead::
1508
+
1509
+ sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 + 7*x + 8, p, M, -2)
1510
+ sage: A.change_ring(Integers(p**prec))
1511
+ [1144 176]
1512
+ [ 847 185]
1513
+
1514
+ The running time is about ``O(p*prec**2)`` (times some logarithmic
1515
+ factors), so it is feasible to run on fairly large primes, or
1516
+ precision (or both?!?!)::
1517
+
1518
+ sage: # long time, needs sage.libs.pari
1519
+ sage: p = 10007
1520
+ sage: prec = 2
1521
+ sage: M = monsky_washnitzer.adjusted_prec(p, prec)
1522
+ sage: R.<x> = PolynomialRing(Integers(p**M))
1523
+ sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 - x + R(1/4), p, M)
1524
+ sage: B = A.change_ring(Integers(p**prec)); B
1525
+ [74311982 57996908]
1526
+ [95877067 25828133]
1527
+ sage: B.det()
1528
+ 10007
1529
+ sage: B.trace()
1530
+ 66
1531
+ sage: EllipticCurve([-1, 1/4]).ap(10007)
1532
+ 66
1533
+
1534
+ ::
1535
+
1536
+ sage: # long time, needs sage.libs.pari
1537
+ sage: p = 5
1538
+ sage: prec = 300
1539
+ sage: M = monsky_washnitzer.adjusted_prec(p, prec)
1540
+ sage: R.<x> = PolynomialRing(Integers(p**M))
1541
+ sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 - x + R(1/4), p, M)
1542
+ sage: B = A.change_ring(Integers(p**prec))
1543
+ sage: B.det()
1544
+ 5
1545
+ sage: -B.trace()
1546
+ 2
1547
+ sage: EllipticCurve([-1, 1/4]).ap(5)
1548
+ -2
1549
+
1550
+ Let us check consistency of the results for a range of precisions::
1551
+
1552
+ sage: # long time, needs sage.libs.pari
1553
+ sage: p = 5
1554
+ sage: max_prec = 60
1555
+ sage: M = monsky_washnitzer.adjusted_prec(p, max_prec)
1556
+ sage: R.<x> = PolynomialRing(Integers(p**M))
1557
+ sage: A = monsky_washnitzer.matrix_of_frobenius(x^3 - x + R(1/4), p, M)
1558
+ sage: A = A.change_ring(Integers(p**max_prec))
1559
+ sage: result = []
1560
+ sage: for prec in range(1, max_prec):
1561
+ ....: M = monsky_washnitzer.adjusted_prec(p, prec)
1562
+ ....: R.<x> = PolynomialRing(Integers(p^M),'x')
1563
+ ....: B = monsky_washnitzer.matrix_of_frobenius(x^3 - x + R(1/4), p, M)
1564
+ ....: B = B.change_ring(Integers(p**prec))
1565
+ ....: result.append(B == A.change_ring(Integers(p**prec)))
1566
+ sage: result == [True] * (max_prec - 1)
1567
+ True
1568
+
1569
+ The remaining examples discuss what happens when you take the
1570
+ coefficient ring to be a power series ring; i.e. in effect you're
1571
+ looking at a family of curves.
1572
+
1573
+ The code does in fact work...
1574
+
1575
+ ::
1576
+
1577
+ sage: # needs sage.libs.pari
1578
+ sage: p = 11
1579
+ sage: prec = 3
1580
+ sage: M = monsky_washnitzer.adjusted_prec(p, prec)
1581
+ sage: S.<t> = PowerSeriesRing(Integers(p**M), default_prec=4)
1582
+ sage: a = 7 + t + 3*t^2
1583
+ sage: b = 8 - 6*t + 17*t^2
1584
+ sage: R.<x> = PolynomialRing(S)
1585
+ sage: Q = x**3 + a*x + b
1586
+ sage: A = monsky_washnitzer.matrix_of_frobenius(Q, p, M) # long time
1587
+ sage: B = A.change_ring(PowerSeriesRing(Integers(p**prec), 't', # long time
1588
+ ....: default_prec=4)); B
1589
+ [1144 + 264*t + 841*t^2 + 1025*t^3 + O(t^4) 176 + 1052*t + 216*t^2 + 523*t^3 + O(t^4)]
1590
+ [ 847 + 668*t + 81*t^2 + 424*t^3 + O(t^4) 185 + 341*t + 171*t^2 + 642*t^3 + O(t^4)]
1591
+
1592
+ The trace trick should work for power series rings too, even in the
1593
+ badly-conditioned case. Unfortunately I do not know how to compute
1594
+ the trace in advance, so I am not sure exactly how this would help.
1595
+ Also, I suspect the running time will be dominated by the
1596
+ expansion, so the trace trick will not really speed things up anyway.
1597
+ Another problem is that the determinant is not always p::
1598
+
1599
+ sage: B.det() # long time
1600
+ 11 + 484*t^2 + 451*t^3 + O(t^4)
1601
+
1602
+ However, it appears that the determinant always has the property
1603
+ that if you substitute t - 11t, you do get the constant series p
1604
+ (mod p\*\*prec). Similarly for the trace. And since the parameter
1605
+ only really makes sense when it is divisible by p anyway, perhaps
1606
+ this is not a problem after all.
1607
+ """
1608
+ M = int(M)
1609
+ if M < 2:
1610
+ raise ValueError("M (=%s) must be at least 2" % M)
1611
+
1612
+ base_ring = Q.base_ring()
1613
+
1614
+ # Expand out frobenius of dx/y and x dx/y.
1615
+ # (You can substitute frobenius_expansion_by_series here, that will work
1616
+ # as well. See its docstring for some performance notes.)
1617
+ F0, F1, offset = frobenius_expansion_by_newton(Q, p, M)
1618
+ # F0, F1, offset = frobenius_expansion_by_series(Q, p, M)
1619
+
1620
+ if compute_exact_forms:
1621
+ # we need to do all the work to get the exact expressions f such that F(x^i dx/y) = df + \sum a_i x^i dx/y
1622
+ F0_coeffs = transpose_list(F0.coeffs())
1623
+ F0_reduced, f_0 = reduce_all(Q, p, F0_coeffs, offset, True)
1624
+
1625
+ F1_coeffs = transpose_list(F1.coeffs())
1626
+ F1_reduced, f_1 = reduce_all(Q, p, F1_coeffs, offset, True)
1627
+
1628
+ elif M == 2:
1629
+ # This implies that only one digit of precision is valid, so we only need
1630
+ # to reduce the second column. Also, the trace doesn't help at all.
1631
+
1632
+ F0_reduced = [base_ring(0), base_ring(0)]
1633
+
1634
+ F1_coeffs = transpose_list(F1.coeffs())
1635
+ F1_reduced = reduce_all(Q, p, F1_coeffs, offset)
1636
+
1637
+ elif trace is None:
1638
+ # No trace provided, just reduce F(dx/y) and F(x dx/y) separately.
1639
+
1640
+ F0_coeffs = transpose_list(F0.coeffs())
1641
+ F0_reduced = reduce_all(Q, p, F0_coeffs, offset)
1642
+
1643
+ F1_coeffs = transpose_list(F1.coeffs())
1644
+ F1_reduced = reduce_all(Q, p, F1_coeffs, offset)
1645
+
1646
+ else:
1647
+ # Trace has been provided.
1648
+
1649
+ # In most cases this can be used to quickly compute F(dx/y) from
1650
+ # F(x dx/y). However, if we're unlucky, the (dx/y)-component of
1651
+ # F(x dx/y) (i.e. the top-right corner of the matrix) may be divisible
1652
+ # by p, in which case there isn't enough information to get the
1653
+ # (x dx/y)-component of F(dx/y) to the desired precision. When this
1654
+ # happens, it turns out that F((x+1) dx/y) always *does* give enough
1655
+ # information (together with the trace) to get both columns to the
1656
+ # desired precision.
1657
+
1658
+ # First however we need a quick way of telling whether the top-right
1659
+ # corner is divisible by p, i.e. we want to compute the second column
1660
+ # of the matrix mod p. We could do this by just running the entire
1661
+ # algorithm with M = 2 (which assures precision 1). Luckily, we've
1662
+ # already done most of the work by computing F1 to high precision; so
1663
+ # all we need to do is extract the coefficients that would correspond
1664
+ # to the first term of the series, and run the reduction on them.
1665
+
1666
+ # todo: actually we only need to do this reduction step mod p^2, not
1667
+ # mod p^M, which is what the code currently does. If the base ring
1668
+ # is Integers(p^M), then it is easy. Otherwise it is tricky to construct
1669
+ # the right ring, I don't know how to do it.
1670
+
1671
+ F1_coeffs = transpose_list(F1.coeffs())
1672
+ F1_modp_coeffs = F1_coeffs[int((M-2)*p):]
1673
+ # make a copy, because reduce_all will destroy the coefficients:
1674
+ F1_modp_coeffs = [list(row) for row in F1_modp_coeffs]
1675
+ F1_modp_offset = offset - (M-2)*p
1676
+ F1_modp_reduced = reduce_all(Q, p, F1_modp_coeffs, F1_modp_offset)
1677
+
1678
+ if F1_modp_reduced[0].is_unit():
1679
+ # If the first entry is invertible mod p, then F(x dx/y) is sufficient
1680
+ # to get the whole matrix.
1681
+
1682
+ F1_reduced = reduce_all(Q, p, F1_coeffs, offset)
1683
+
1684
+ F0_reduced = [base_ring(trace) - F1_reduced[1], None]
1685
+ # using that the determinant is p:
1686
+ F0_reduced[1] = (F0_reduced[0] * F1_reduced[1] - base_ring(p)) \
1687
+ / F1_reduced[0]
1688
+
1689
+ else:
1690
+ # If the first entry is zero mod p, then F((x+1) dx/y) will be sufficient
1691
+ # to get the whole matrix. (Here we are using the fact that the second
1692
+ # entry *cannot* be zero mod p. This is guaranteed by some results in
1693
+ # section 3.2 of ``Computation of p-adic Heights and Log Convergence''
1694
+ # by Mazur, Stein, Tate. But let's quickly check it anyway :-))
1695
+ msg = "The second entry in the second column "
1696
+ msg += "should be invertible mod p!"
1697
+ assert F1_modp_reduced[1].is_unit(), msg
1698
+
1699
+ G0_coeffs = transpose_list((F0 + F1).coeffs())
1700
+ G0_reduced = reduce_all(Q, p, G0_coeffs, offset)
1701
+
1702
+ # Now G0_reduced expresses F((x+1) dx/y) in terms of dx/y and x dx/y.
1703
+ # Re-express this in terms of (x+1) dx/y and x dx/y.
1704
+ H0_reduced = [G0_reduced[0], G0_reduced[1] - G0_reduced[0]]
1705
+
1706
+ # The thing we're about to divide by better be a unit.
1707
+ msg = "The second entry in this column "
1708
+ msg += "should be invertible mod p!"
1709
+ assert H0_reduced[1].is_unit(), msg
1710
+
1711
+ # Figure out the second column using the trace...
1712
+ H1_reduced = [None, base_ring(trace) - H0_reduced[0]]
1713
+ # ... and using that the determinant is p:
1714
+ H1_reduced[0] = (H0_reduced[0] * H1_reduced[1] - base_ring(p)) \
1715
+ / H0_reduced[1]
1716
+
1717
+ # Finally, change back to the usual basis (dx/y, x dx/y)
1718
+ F1_reduced = [H1_reduced[0],
1719
+ H1_reduced[0] + H1_reduced[1]]
1720
+ F0_reduced = [H0_reduced[0] - F1_reduced[0],
1721
+ H0_reduced[0] + H0_reduced[1] - F1_reduced[1]]
1722
+
1723
+ # One more sanity check: our final result should be congruent mod p
1724
+ # to the approximation we used earlier.
1725
+ msg = "The output matrix is not congruent mod p "
1726
+ msg += "to the approximation found earlier!"
1727
+ assert not (
1728
+ (F1_reduced[0] - F1_modp_reduced[0]).is_unit() or
1729
+ (F1_reduced[1] - F1_modp_reduced[1]).is_unit() or
1730
+ F0_reduced[0].is_unit() or F0_reduced[1].is_unit()), msg
1731
+
1732
+ if compute_exact_forms:
1733
+ return matrix(base_ring, 2, 2, [F0_reduced[0], F1_reduced[0],
1734
+ F0_reduced[1], F1_reduced[1]]), f_0, f_1
1735
+ else:
1736
+ return matrix(base_ring, 2, 2, [F0_reduced[0], F1_reduced[0],
1737
+ F0_reduced[1], F1_reduced[1]])
1738
+
1739
+
1740
+ # ****************************************************************************
1741
+ # This is a generalization of the above functionality for hyperelliptic curves.
1742
+ #
1743
+ # THIS IS A WORK IN PROGRESS.
1744
+ #
1745
+ # I tried to embed must stuff into the rings themselves rather than
1746
+ # just extract and manipulate lists of coefficients. Hence the implementations
1747
+ # below are much less optimized, so are much slower, but should hopefully be
1748
+ # easier to follow. (E.g. one can print/make sense of intermediate results.)
1749
+ #
1750
+ # AUTHOR:
1751
+ # -- Robert Bradshaw (2007-04)
1752
+ #
1753
+ # ****************************************************************************
1754
+
1755
+
1756
+ def matrix_of_frobenius_hyperelliptic(Q, p=None, prec=None, M=None):
1757
+ r"""
1758
+ Compute the matrix of Frobenius on Monsky-Washnitzer cohomology,
1759
+ with respect to the basis `(dx/2y, x dx/2y, ...x^{d-2} dx/2y)`, where
1760
+ `d` is the degree of `Q`.
1761
+
1762
+ INPUT:
1763
+
1764
+ - ``Q`` -- monic polynomial `Q(x)`
1765
+
1766
+ - ``p`` -- prime `\geq 5` for which `E` has good reduction
1767
+
1768
+ - ``prec`` -- (optional) `p`-adic precision of the coefficient ring
1769
+
1770
+ - ``M`` -- (optional) adjusted `p`-adic precision of the coefficient ring
1771
+
1772
+ OUTPUT:
1773
+
1774
+ `(d-1)` x `(d-1)` matrix `M` of Frobenius on Monsky-Washnitzer cohomology,
1775
+ and list of differentials \{f_i \} such that
1776
+
1777
+ .. MATH::
1778
+
1779
+ \phi^* (x^i dx/2y) = df_i + M[i]*vec(dx/2y, ..., x^{d-2} dx/2y)
1780
+
1781
+ EXAMPLES::
1782
+
1783
+ sage: # needs sage.rings.padics
1784
+ sage: p = 5
1785
+ sage: prec = 3
1786
+ sage: R.<x> = QQ['x']
1787
+ sage: A,f = monsky_washnitzer.matrix_of_frobenius_hyperelliptic(x^5 - 2*x + 3, p, prec)
1788
+ sage: A
1789
+ [ 4*5 + O(5^3) 5 + 2*5^2 + O(5^3) 2 + 3*5 + 2*5^2 + O(5^3) 2 + 5 + 5^2 + O(5^3)]
1790
+ [ 3*5 + 5^2 + O(5^3) 3*5 + O(5^3) 4*5 + O(5^3) 2 + 5^2 + O(5^3)]
1791
+ [ 4*5 + 4*5^2 + O(5^3) 3*5 + 2*5^2 + O(5^3) 5 + 3*5^2 + O(5^3) 2*5 + 2*5^2 + O(5^3)]
1792
+ [ 5^2 + O(5^3) 5 + 4*5^2 + O(5^3) 4*5 + 3*5^2 + O(5^3) 2*5 + O(5^3)]
1793
+ """
1794
+ try:
1795
+ from sage.misc.profiler import Profiler
1796
+ except ImportError:
1797
+ def prof():
1798
+ pass
1799
+ else:
1800
+ prof = Profiler()
1801
+
1802
+ prof("setup")
1803
+ if p is None:
1804
+ try:
1805
+ K = Q.base_ring()
1806
+ p = K.prime()
1807
+ prec = K.precision_cap()
1808
+ except AttributeError:
1809
+ raise ValueError("p and prec must be specified if Q is not "
1810
+ "defined over a p-adic ring")
1811
+ if M is None:
1812
+ M = adjusted_prec(p, prec)
1813
+ extra_prec_ring = Integers(p**M)
1814
+ # extra_prec_ring = pAdicField(p, M) # SLOW!
1815
+
1816
+ real_prec_ring = pAdicField(p, prec) # pAdicField(p, prec) # To capped absolute?
1817
+ S = SpecialHyperellipticQuotientRing(Q, extra_prec_ring, True)
1818
+ MW = S.monsky_washnitzer()
1819
+ prof("frob basis elements")
1820
+ F = MW.frob_basis_elements(M, p)
1821
+
1822
+ prof("rationalize")
1823
+ # do reduction over Q in case we have non-integral entries (and it is so much faster than padics)
1824
+ rational_S = S.change_ring(QQ)
1825
+ # this is a hack until pAdics are fast
1826
+ # (They are in the latest development bundle, but its not standard and I'd need to merge.
1827
+ # (it will periodically cast into this ring to reduce coefficient size)
1828
+ rational_S._prec_cap = p**M
1829
+ rational_S._p = p
1830
+ # S._p = p
1831
+ # rational_S(F[0]).reduce_fast()
1832
+ # prof("reduce others")
1833
+
1834
+ # rational_S = S.change_ring(pAdicField(p, M))
1835
+ F = [rational_S(F_i) for F_i in F]
1836
+
1837
+ prof("reduce")
1838
+ reduced = [F_i.reduce_fast(True) for F_i in F]
1839
+
1840
+ # but the coeffs are WAY more precision than they need to be
1841
+
1842
+ prof("make matrix")
1843
+ # now take care of precision capping
1844
+ M = matrix(real_prec_ring, [a for f, a in reduced])
1845
+ for i in range(M.ncols()):
1846
+ for j in range(M.nrows()):
1847
+ M[i, j] = M[i, j].add_bigoh(prec)
1848
+ return M.transpose(), [f for f, a in reduced]
1849
+
1850
+
1851
+ class SpecialHyperellipticQuotientElement(ModuleElement):
1852
+ r"""
1853
+ Element in the Hyperelliptic quotient ring.
1854
+
1855
+ EXAMPLES::
1856
+
1857
+ sage: R.<x> = QQ['x']
1858
+ sage: E = HyperellipticCurve(x^5 - 36*x + 1)
1859
+ sage: x,y = E.monsky_washnitzer_gens()
1860
+ sage: MW = x.parent()
1861
+ sage: MW(x + x**2 + y - 77)
1862
+ -(77-y)*1 + x + x^2
1863
+ """
1864
+ def __init__(self, parent, val=0, offset=0, check=True):
1865
+ """
1866
+ Elements in the Hyperelliptic quotient ring.
1867
+
1868
+ EXAMPLES::
1869
+
1870
+ sage: R.<x> = QQ['x']
1871
+ sage: E = HyperellipticCurve(x^5 - 36*x + 1)
1872
+ sage: x,y = E.monsky_washnitzer_gens()
1873
+ sage: MW = x.parent()
1874
+ sage: elt = MW(x + x**2 + y - 77)
1875
+ sage: TestSuite(elt).run()
1876
+ """
1877
+ ModuleElement.__init__(self, parent)
1878
+ if not check:
1879
+ self._f = parent._poly_ring(val, check=False)
1880
+ return
1881
+ if isinstance(val, SpecialHyperellipticQuotientElement):
1882
+ R = parent.base_ring()
1883
+ self._f = parent._poly_ring([a.change_ring(R) for a in val._f])
1884
+ return
1885
+ if isinstance(val, tuple):
1886
+ val, offset = val
1887
+ if isinstance(val, list) and val and isinstance(val[0], FreeModuleElement):
1888
+ val = transpose_list(val)
1889
+ self._f = parent._poly_ring(val)
1890
+ if offset != 0:
1891
+ self._f = self._f.parent()([a << offset for a in self._f], check=False)
1892
+
1893
+ def _richcmp_(self, other, op) -> bool:
1894
+ """
1895
+ Compare the elements.
1896
+
1897
+ EXAMPLES::
1898
+
1899
+ sage: R.<x> = QQ['x']
1900
+ sage: E = HyperellipticCurve(x^5 - 36*x + 1)
1901
+ sage: x,y = E.monsky_washnitzer_gens()
1902
+ sage: x == x
1903
+ True
1904
+ sage: x > y
1905
+ True
1906
+ """
1907
+ return richcmp(self._f, other._f, op)
1908
+
1909
+ def change_ring(self, R):
1910
+ """
1911
+ Return the same element after changing the base ring to `R`.
1912
+
1913
+ EXAMPLES::
1914
+
1915
+ sage: R.<x> = QQ['x']
1916
+ sage: E = HyperellipticCurve(x^5 - 36*x + 1)
1917
+ sage: x,y = E.monsky_washnitzer_gens()
1918
+ sage: MW = x.parent()
1919
+ sage: z = MW(x + x**2 + y - 77)
1920
+ sage: z.change_ring(AA).parent() # needs sage.rings.number_field
1921
+ SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = x^5 - 36*x + 1)
1922
+ over Algebraic Real Field
1923
+ """
1924
+ return self.parent().change_ring(R)(self)
1925
+
1926
+ def __call__(self, *x):
1927
+ """
1928
+ Evaluate ``self`` at given arguments.
1929
+
1930
+ EXAMPLES::
1931
+
1932
+ sage: R.<x> = QQ['x']
1933
+ sage: E = HyperellipticCurve(x^5 - 36*x + 1)
1934
+ sage: x,y = E.monsky_washnitzer_gens()
1935
+ sage: MW = x.parent()
1936
+ sage: z = MW(x + x**2 + y - 77); z
1937
+ -(77-y)*1 + x + x^2
1938
+ sage: z(66)
1939
+ 4345 + y
1940
+ sage: z(5,4)
1941
+ -43
1942
+ """
1943
+ return self._f(*x)
1944
+
1945
+ def __invert__(self):
1946
+ """
1947
+ Return the inverse of ``self``.
1948
+
1949
+ The general element in our ring is not invertible, but `y` may
1950
+ be. We do not want to pass to the fraction field.
1951
+
1952
+ EXAMPLES::
1953
+
1954
+ sage: R.<x> = QQ['x']
1955
+ sage: E = HyperellipticCurve(x^5 - 36*x + 1)
1956
+ sage: x,y = E.monsky_washnitzer_gens()
1957
+ sage: MW = x.parent()
1958
+ sage: z = y**(-1) # indirect doctest
1959
+ sage: z.parent()
1960
+ SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = x^5 - 36*x + 1)
1961
+ over Rational Field
1962
+
1963
+ sage: z = (x+y)**(-1) # indirect doctest
1964
+ Traceback (most recent call last):
1965
+ ...
1966
+ ZeroDivisionError: element not invertible
1967
+ """
1968
+ if self._f.degree() == 0 and self._f[0].is_unit():
1969
+ P = self.parent()
1970
+ return P.element_class(P, ~self._f[0])
1971
+ else:
1972
+ raise ZeroDivisionError("element not invertible")
1973
+
1974
+ def __bool__(self):
1975
+ """
1976
+ Return ``True`` iff ``self`` is not zero.
1977
+
1978
+ EXAMPLES::
1979
+
1980
+ sage: R.<x> = QQ['x']
1981
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
1982
+ sage: x,y = E.monsky_washnitzer_gens()
1983
+ sage: bool(x)
1984
+ True
1985
+ """
1986
+ return bool(self._f)
1987
+
1988
+ def __eq__(self, other):
1989
+ """
1990
+ Return ``True`` iff ``self`` is equal to ``other``.
1991
+
1992
+ EXAMPLES::
1993
+
1994
+ sage: R.<x> = QQ['x']
1995
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
1996
+ sage: x,y = E.monsky_washnitzer_gens()
1997
+ sage: x == y # indirect doctest
1998
+ False
1999
+ """
2000
+ if not isinstance(other, SpecialHyperellipticQuotientElement):
2001
+ other = self.parent()(other)
2002
+ return self._f == other._f
2003
+
2004
+ def _add_(self, other):
2005
+ """
2006
+ Return the sum of two elements.
2007
+
2008
+ EXAMPLES::
2009
+
2010
+ sage: R.<x> = QQ['x']
2011
+ sage: E = HyperellipticCurve(x^5 - 36*x + 1)
2012
+ sage: x,y = E.monsky_washnitzer_gens()
2013
+ sage: x + y
2014
+ y*1 + x
2015
+ """
2016
+ P = self.parent()
2017
+ return P.element_class(P, self._f + other._f)
2018
+
2019
+ def _sub_(self, other):
2020
+ """
2021
+ Return the difference of two elements.
2022
+
2023
+ EXAMPLES::
2024
+
2025
+ sage: R.<x> = QQ['x']
2026
+ sage: E = HyperellipticCurve(x^5 - 36*x + 1)
2027
+ sage: x,y = E.monsky_washnitzer_gens()
2028
+ sage: y - x
2029
+ y*1 - x
2030
+ """
2031
+ P = self.parent()
2032
+ return P.element_class(P, self._f - other._f)
2033
+
2034
+ def _mul_(self, other):
2035
+ """
2036
+ Return the product of two elements.
2037
+
2038
+ EXAMPLES::
2039
+
2040
+ sage: R.<x> = QQ['x']
2041
+ sage: E = HyperellipticCurve(x^5 - 36*x + 1)
2042
+ sage: x,y = E.monsky_washnitzer_gens()
2043
+ sage: y*x
2044
+ y*x
2045
+ """
2046
+ # over Laurent series, addition and subtraction can be
2047
+ # expensive, and the degree of this poly is small enough that
2048
+ # Karatsuba actually hurts significantly in some cases
2049
+ if self._f[0].valuation() + other._f[0].valuation() > -200:
2050
+ prod = self._f._mul_generic(other._f)
2051
+ else:
2052
+ prod = self._f * other._f
2053
+ v = prod.list()
2054
+ parent = self.parent()
2055
+ Q_coeffs = parent._Q_coeffs
2056
+ n = len(Q_coeffs) - 1
2057
+ y2 = self.parent()._series_ring_y << 1
2058
+ for i in range(len(v)-1, n-1, -1):
2059
+ for j in range(n):
2060
+ v[i-n+j] -= Q_coeffs[j] * v[i]
2061
+ v[i-n] += y2 * v[i]
2062
+ P = self.parent()
2063
+ return P.element_class(P, v[0:n])
2064
+
2065
+ def _rmul_(self, c):
2066
+ """
2067
+ Return the product of ``self`` with `c` on the left.
2068
+
2069
+ EXAMPLES::
2070
+
2071
+ sage: R.<x> = QQ['x']
2072
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2073
+ sage: x,y = E.monsky_washnitzer_gens()
2074
+ sage: x._rmul_(y) # needs sage.rings.real_interval_field
2075
+ y*1*x
2076
+ """
2077
+ P = self.parent()
2078
+ if not c:
2079
+ return P.zero()
2080
+ ret = [c*a for a in self._f.list(copy=False)]
2081
+ while ret and not ret[-1]: # strip off trailing 0s
2082
+ ret.pop()
2083
+ return P.element_class(P, ret, check=False)
2084
+
2085
+ def _lmul_(self, c):
2086
+ """
2087
+ Return the product of ``self`` with `c` on the right.
2088
+
2089
+ EXAMPLES::
2090
+
2091
+ sage: R.<x> = QQ['x']
2092
+ sage: E = HyperellipticCurve(x^5-3*x+1)
2093
+ sage: x,y = E.monsky_washnitzer_gens()
2094
+ sage: x._lmul_(y) # needs sage.rings.real_interval_field
2095
+ y*1*x
2096
+ """
2097
+ P = self.parent()
2098
+ if not c:
2099
+ return P.zero()
2100
+ ret = [a*c for a in self._f.list(copy=False)]
2101
+ while ret and not ret[-1]: # strip off trailing 0s
2102
+ ret.pop()
2103
+ return P.element_class(P, ret, check=False)
2104
+
2105
+ def __lshift__(self, k):
2106
+ """
2107
+ Return the left shift of ``self`` by `k`.
2108
+
2109
+ EXAMPLES::
2110
+
2111
+ sage: R.<x> = QQ['x']
2112
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2113
+ sage: x,y = E.monsky_washnitzer_gens()
2114
+ sage: x.__lshift__(3)
2115
+ y^3*x
2116
+ """
2117
+ coeffs = self._f.list(copy=False)
2118
+ P = self.parent()
2119
+ return P.element_class(P, [a << k for a in coeffs], check=False)
2120
+
2121
+ def __rshift__(self, k):
2122
+ """
2123
+ Return the right shift of ``self`` by `k`.
2124
+
2125
+ EXAMPLES::
2126
+
2127
+ sage: R.<x> = QQ['x']
2128
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2129
+ sage: x,y = E.monsky_washnitzer_gens()
2130
+ sage: y.__rshift__(3)
2131
+ (y^-2)*1
2132
+ """
2133
+ coeffs = self._f.list(copy=False)
2134
+ P = self.parent()
2135
+ return P.element_class(P, [a >> k for a in coeffs], check=False)
2136
+
2137
+ def truncate_neg(self, n):
2138
+ """
2139
+ Return ``self`` minus its terms of degree less than `n` wrt `y`.
2140
+
2141
+ EXAMPLES::
2142
+
2143
+ sage: R.<x> = QQ['x']
2144
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2145
+ sage: x,y = E.monsky_washnitzer_gens()
2146
+ sage: (x + 3*y + 7*x*2*y**4).truncate_neg(1)
2147
+ 3*y*1 + 14*y^4*x
2148
+ """
2149
+ coeffs = self._f.list(copy=False)
2150
+ P = self.parent()
2151
+ return P.element_class(P, [a.truncate_neg(n) for a in coeffs], check=False)
2152
+
2153
+ def _repr_(self):
2154
+ """
2155
+ Return a string representation of ``self``.
2156
+
2157
+ EXAMPLES::
2158
+
2159
+ sage: R.<x> = QQ['x']
2160
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2161
+ sage: x,y = E.monsky_washnitzer_gens()
2162
+ sage: (x + 3*y)._repr_()
2163
+ '3*y*1 + x'
2164
+ """
2165
+ x = PolynomialRing(QQ, 'x').gen(0)
2166
+ coeffs = self._f.list()
2167
+ return repr_lincomb([(x**i, coeffs[i]) for i in range(len(coeffs))])
2168
+
2169
+ def _latex_(self):
2170
+ r"""
2171
+ Return a LateX string for ``self``.
2172
+
2173
+ EXAMPLES::
2174
+
2175
+ sage: R.<x> = QQ['x']
2176
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2177
+ sage: x,y = E.monsky_washnitzer_gens()
2178
+ sage: (x + 3*y)._latex_()
2179
+ '3y 1 + x'
2180
+ """
2181
+ x = PolynomialRing(QQ, 'x').gen(0)
2182
+ coeffs = self._f.list()
2183
+ return repr_lincomb([(x**i, coeffs[i]) for i in range(len(coeffs))], is_latex=True)
2184
+
2185
+ def diff(self):
2186
+ """
2187
+ Return the differential of ``self``.
2188
+
2189
+ EXAMPLES::
2190
+
2191
+ sage: R.<x> = QQ['x']
2192
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2193
+ sage: x,y = E.monsky_washnitzer_gens()
2194
+ sage: (x + 3*y).diff()
2195
+ (-(9-2*y)*1 + 15*x^4) dx/2y
2196
+ """
2197
+ # try:
2198
+ # return self._diff_x
2199
+ # except AttributeError:
2200
+ # pass
2201
+
2202
+ # d(self) = A dx + B dy
2203
+ # = (2y A + BQ') dx/2y
2204
+ P = self.parent()
2205
+ R = P.base_ring()
2206
+ v = self._f.list()
2207
+ n = len(v)
2208
+ A = P([R(i) * v[i] for i in range(1, n)])
2209
+ B = P([a.derivative() for a in v])
2210
+ dQ = P._dQ
2211
+ return P._monsky_washnitzer((R(2) * A << 1) + dQ * B)
2212
+ # self._diff = self.parent()._monsky_washnitzer(two_y * A + dQ * B)
2213
+ # return self._diff
2214
+
2215
+ def extract_pow_y(self, k):
2216
+ r"""
2217
+ Return the coefficients of `y^k` in ``self`` as a list.
2218
+
2219
+ EXAMPLES::
2220
+
2221
+ sage: R.<x> = QQ['x']
2222
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2223
+ sage: x,y = E.monsky_washnitzer_gens()
2224
+ sage: (x + 3*y + 9*x*y).extract_pow_y(1)
2225
+ [3, 9, 0, 0, 0]
2226
+ """
2227
+ v = [a[k] for a in self._f.list()]
2228
+ v += [ZZ.zero()] * (self.parent()._n - len(v))
2229
+ return v
2230
+
2231
+ def min_pow_y(self):
2232
+ r"""
2233
+ Return the minimal degree of ``self`` with respect to `y`.
2234
+
2235
+ EXAMPLES::
2236
+
2237
+ sage: R.<x> = QQ['x']
2238
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2239
+ sage: x,y = E.monsky_washnitzer_gens()
2240
+ sage: (x + 3*y).min_pow_y()
2241
+ 0
2242
+ """
2243
+ if self._f.degree() == -1:
2244
+ return ZZ.zero()
2245
+ return min([a.valuation() for a in self._f.list()])
2246
+
2247
+ def max_pow_y(self):
2248
+ r"""
2249
+ Return the maximal degree of ``self`` with respect to `y`.
2250
+
2251
+ EXAMPLES::
2252
+
2253
+ sage: R.<x> = QQ['x']
2254
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2255
+ sage: x,y = E.monsky_washnitzer_gens()
2256
+ sage: (x + 3*y).max_pow_y()
2257
+ 1
2258
+ """
2259
+ if self._f.degree() == -1:
2260
+ return ZZ.zero()
2261
+ return max([a.degree() for a in self._f.list()])
2262
+
2263
+ def coeffs(self, R=None):
2264
+ r"""
2265
+ Return the raw coefficients of this element.
2266
+
2267
+ INPUT:
2268
+
2269
+ - ``R`` -- an (optional) base-ring in which to cast the coefficients
2270
+
2271
+ OUTPUT:
2272
+
2273
+ - ``coeffs`` -- list of coefficients of powers of `x` for each power
2274
+ of `y`
2275
+
2276
+ - ``n`` -- an offset indicating the power of `y` of the first list
2277
+ element
2278
+
2279
+ EXAMPLES::
2280
+
2281
+ sage: R.<x> = QQ['x']
2282
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2283
+ sage: x,y = E.monsky_washnitzer_gens()
2284
+ sage: x.coeffs()
2285
+ ([(0, 1, 0, 0, 0)], 0)
2286
+ sage: y.coeffs()
2287
+ ([(0, 0, 0, 0, 0), (1, 0, 0, 0, 0)], 0)
2288
+
2289
+ sage: a = sum(n*x^n for n in range(5)); a
2290
+ x + 2*x^2 + 3*x^3 + 4*x^4
2291
+ sage: a.coeffs()
2292
+ ([(0, 1, 2, 3, 4)], 0)
2293
+ sage: a.coeffs(Qp(7)) # needs sage.rings.padics
2294
+ ([(0, 1 + O(7^20), 2 + O(7^20), 3 + O(7^20), 4 + O(7^20))], 0)
2295
+ sage: (a*y).coeffs()
2296
+ ([(0, 0, 0, 0, 0), (0, 1, 2, 3, 4)], 0)
2297
+ sage: (a*y^-2).coeffs()
2298
+ ([(0, 1, 2, 3, 4), (0, 0, 0, 0, 0), (0, 0, 0, 0, 0)], -2)
2299
+
2300
+ Note that the coefficient list is transposed compared to how they
2301
+ are stored and printed::
2302
+
2303
+ sage: a*y^-2
2304
+ (y^-2)*x + (2*y^-2)*x^2 + (3*y^-2)*x^3 + (4*y^-2)*x^4
2305
+
2306
+ A more complicated example::
2307
+
2308
+ sage: a = x^20*y^-3 - x^11*y^2; a
2309
+ (y^-3-4*y^-1+6*y-4*y^3+y^5)*1 - (12*y^-3-36*y^-1+36*y+y^2-12*y^3-2*y^4+y^6)*x
2310
+ + (54*y^-3-108*y^-1+54*y+6*y^2-6*y^4)*x^2 - (108*y^-3-108*y^-1+9*y^2)*x^3
2311
+ + (81*y^-3)*x^4
2312
+ sage: raw, offset = a.coeffs()
2313
+ sage: a.min_pow_y()
2314
+ -3
2315
+ sage: offset
2316
+ -3
2317
+ sage: raw
2318
+ [(1, -12, 54, -108, 81),
2319
+ (0, 0, 0, 0, 0),
2320
+ (-4, 36, -108, 108, 0),
2321
+ (0, 0, 0, 0, 0),
2322
+ (6, -36, 54, 0, 0),
2323
+ (0, -1, 6, -9, 0),
2324
+ (-4, 12, 0, 0, 0),
2325
+ (0, 2, -6, 0, 0),
2326
+ (1, 0, 0, 0, 0),
2327
+ (0, -1, 0, 0, 0)]
2328
+ sage: sum(c * x^i * y^(j+offset)
2329
+ ....: for j, L in enumerate(raw) for i, c in enumerate(L)) == a
2330
+ True
2331
+
2332
+ Can also be used to construct elements::
2333
+
2334
+ sage: a.parent()(raw, offset) == a
2335
+ True
2336
+ """
2337
+ zero = self.base_ring()(0) if R is None else R(0)
2338
+ y_offset = min(self.min_pow_y(), 0)
2339
+ y_degree = max(self.max_pow_y(), 0)
2340
+ coeffs = []
2341
+ n = y_degree - y_offset + 1
2342
+ for a in self._f.list():
2343
+ k = a.valuation()
2344
+ if k is Infinity:
2345
+ k = 0
2346
+ k -= y_offset
2347
+ z = a.list()
2348
+ coeffs.append([zero] * k + z + [zero]*(n - len(z) - k))
2349
+ while len(coeffs) < self.parent().degree():
2350
+ coeffs.append([zero] * n)
2351
+ V = FreeModule(self.base_ring() if R is None else R, self.parent().degree())
2352
+ coeffs = transpose_list(coeffs)
2353
+ return [V(a) for a in coeffs], y_offset
2354
+
2355
+
2356
+ class SpecialHyperellipticQuotientRing(UniqueRepresentation, Parent):
2357
+ """
2358
+ The special hyperelliptic quotient ring.
2359
+ """
2360
+ _p = None
2361
+
2362
+ def __init__(self, Q, R=None, invert_y=True):
2363
+ r"""
2364
+ Initialize ``self``.
2365
+
2366
+ TESTS::
2367
+
2368
+ sage: R.<x> = QQ['x']
2369
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2370
+ sage: from sage.schemes.hyperelliptic_curves.monsky_washnitzer import SpecialHyperellipticQuotientRing
2371
+ sage: HQR = SpecialHyperellipticQuotientRing(E)
2372
+ sage: TestSuite(HQR).run() # needs sage.rings.real_interval_field
2373
+
2374
+ Check that caching works::
2375
+
2376
+ sage: HQR is SpecialHyperellipticQuotientRing(E)
2377
+ True
2378
+ """
2379
+ if R is None:
2380
+ R = Q.base_ring()
2381
+
2382
+ x = PolynomialRing(R, 'xx').gen()
2383
+ if isinstance(Q, EllipticCurve_generic):
2384
+ E = Q
2385
+ if E.a1() != 0 or E.a2() != 0:
2386
+ raise NotImplementedError("curve must be in Weierstrass normal form")
2387
+ Q = -E.change_ring(R).defining_polynomial()(x, 0, 1)
2388
+ self._curve = E
2389
+
2390
+ elif isinstance(Q, HyperellipticCurve_generic):
2391
+ C = Q
2392
+ if C.hyperelliptic_polynomials()[1] != 0:
2393
+ raise NotImplementedError("curve must be of form y^2 = Q(x)")
2394
+ Q = C.hyperelliptic_polynomials()[0].change_ring(R)
2395
+ self._curve = C
2396
+
2397
+ if isinstance(Q, Polynomial):
2398
+ self._Q = Q.change_ring(R)
2399
+ self._coeffs = self._Q.coefficients(sparse=False)
2400
+ if self._coeffs.pop() != 1:
2401
+ raise NotImplementedError("polynomial must be monic")
2402
+ if not hasattr(self, '_curve'):
2403
+ if self._Q.degree() == 3:
2404
+ ainvs = [0, self._Q[2], 0, self._Q[1], self._Q[0]]
2405
+ self._curve = EllipticCurve(ainvs)
2406
+ else:
2407
+ self._curve = HyperellipticCurve(self._Q, check_squarefree=R.is_field())
2408
+
2409
+ else:
2410
+ raise NotImplementedError("must be an elliptic curve or polynomial "
2411
+ "Q for y^2 = Q(x)\n(Got element of %s)" % Q.parent())
2412
+
2413
+ self._n = int(Q.degree())
2414
+ self._series_ring = (LaurentSeriesRing if invert_y else PolynomialRing)(R, 'y')
2415
+ self._series_ring_y = self._series_ring.gen(0)
2416
+ self._series_ring_0 = self._series_ring.zero()
2417
+
2418
+ Parent.__init__(self, base=R, category=Algebras(R).Commutative())
2419
+
2420
+ self._poly_ring = PolynomialRing(self._series_ring, 'x')
2421
+
2422
+ self._x = self.element_class(self, self._poly_ring.gen(0))
2423
+ self._y = self.element_class(self, self._series_ring.gen(0))
2424
+
2425
+ self._Q_coeffs = Q.change_ring(self._series_ring).list()
2426
+ self._dQ = Q.derivative().change_ring(self)(self._x)
2427
+ self._monsky_washnitzer = MonskyWashnitzerDifferentialRing(self)
2428
+
2429
+ self._monomial_diffs = {}
2430
+ self._monomial_diff_coeffs = {}
2431
+
2432
+ def _repr_(self) -> str:
2433
+ r"""
2434
+ String representation.
2435
+
2436
+ EXAMPLES::
2437
+
2438
+ sage: R.<x> = QQ['x']
2439
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2440
+ sage: x,y = E.monsky_washnitzer_gens()
2441
+ sage: x.parent() # indirect doctest
2442
+ SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = x^5 - 3*x + 1) over Rational Field
2443
+ """
2444
+ y_inverse = ",y^-1" if isinstance(self._series_ring, (LaurentSeriesRing, LazyLaurentSeriesRing)) else ""
2445
+ return "SpecialHyperellipticQuotientRing K[x,y%s] / (y^2 = %s) over %s" % (y_inverse, self._Q, self.base_ring())
2446
+
2447
+ def base_extend(self, R):
2448
+ r"""
2449
+ Return the base extension of ``self`` to the ring ``R`` if possible.
2450
+
2451
+ EXAMPLES::
2452
+
2453
+ sage: R.<x> = QQ['x']
2454
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2455
+ sage: x,y = E.monsky_washnitzer_gens()
2456
+ sage: x.parent().base_extend(UniversalCyclotomicField()) # needs sage.libs.gap
2457
+ SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = x^5 - 3*x + 1)
2458
+ over Universal Cyclotomic Field
2459
+ sage: x.parent().base_extend(ZZ)
2460
+ Traceback (most recent call last):
2461
+ ...
2462
+ TypeError: no such base extension
2463
+ """
2464
+ if R.has_coerce_map_from(self.base_ring()):
2465
+ return self.change_ring(R)
2466
+ raise TypeError("no such base extension")
2467
+
2468
+ def change_ring(self, R):
2469
+ r"""
2470
+ Return the analog of ``self`` over the ring ``R``.
2471
+
2472
+ EXAMPLES::
2473
+
2474
+ sage: R.<x> = QQ['x']
2475
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2476
+ sage: x,y = E.monsky_washnitzer_gens()
2477
+ sage: x.parent().change_ring(ZZ)
2478
+ SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = x^5 - 3*x + 1)
2479
+ over Integer Ring
2480
+ """
2481
+ return SpecialHyperellipticQuotientRing(self._Q.change_ring(R), R,
2482
+ isinstance(self._series_ring, (LaurentSeriesRing, LazyLaurentSeriesRing)))
2483
+
2484
+ def _element_constructor_(self, val, offset=0, check=True):
2485
+ r"""
2486
+ Construct an element of ``self``.
2487
+
2488
+ EXAMPLES::
2489
+
2490
+ sage: R.<x> = QQ['x']
2491
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2492
+ sage: x,y = E.monsky_washnitzer_gens()
2493
+ sage: x.parent()(x^6)
2494
+ -(1-y^2)*x + 3*x^2
2495
+ """
2496
+ if isinstance(val, SpecialHyperellipticQuotientElement) and val.parent() is self:
2497
+ if offset == 0:
2498
+ return val
2499
+ else:
2500
+ return val << offset
2501
+ elif isinstance(val, MonskyWashnitzerDifferential):
2502
+ return self._monsky_washnitzer(val)
2503
+ return self.element_class(self, val, offset, check)
2504
+
2505
+ @cached_method
2506
+ def one(self):
2507
+ """
2508
+ Return the unit of ``self``.
2509
+
2510
+ EXAMPLES::
2511
+
2512
+ sage: R.<x> = QQ['x']
2513
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2514
+ sage: x,y = E.monsky_washnitzer_gens()
2515
+ sage: x.parent().one()
2516
+ 1
2517
+ """
2518
+ return self.element_class(self, self._poly_ring.one(), check=False)
2519
+
2520
+ @cached_method
2521
+ def zero(self):
2522
+ """
2523
+ Return the zero of ``self``.
2524
+
2525
+ EXAMPLES::
2526
+
2527
+ sage: R.<x> = QQ['x']
2528
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2529
+ sage: x,y = E.monsky_washnitzer_gens()
2530
+ sage: x.parent().zero()
2531
+ 0
2532
+ """
2533
+ return self.element_class(self, self._poly_ring.zero(), check=False)
2534
+
2535
+ def gens(self) -> tuple:
2536
+ """
2537
+ Return the generators of ``self``.
2538
+
2539
+ EXAMPLES::
2540
+
2541
+ sage: R.<x> = QQ['x']
2542
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2543
+ sage: x,y = E.monsky_washnitzer_gens()
2544
+ sage: x.parent().gens()
2545
+ (x, y*1)
2546
+ """
2547
+ return (self._x, self._y)
2548
+
2549
+ def x(self):
2550
+ r"""
2551
+ Return the generator `x` of ``self``.
2552
+
2553
+ EXAMPLES::
2554
+
2555
+ sage: R.<x> = QQ['x']
2556
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2557
+ sage: x,y = E.monsky_washnitzer_gens()
2558
+ sage: x.parent().x()
2559
+ x
2560
+ """
2561
+ return self._x
2562
+
2563
+ def y(self):
2564
+ r"""
2565
+ Return the generator `y` of ``self``.
2566
+
2567
+ EXAMPLES::
2568
+
2569
+ sage: R.<x> = QQ['x']
2570
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2571
+ sage: x,y = E.monsky_washnitzer_gens()
2572
+ sage: x.parent().y()
2573
+ y*1
2574
+ """
2575
+ return self._y
2576
+
2577
+ def monomial(self, i, j, b=None):
2578
+ """
2579
+ Return `b y^j x^i`, computed quickly.
2580
+
2581
+ EXAMPLES::
2582
+
2583
+ sage: R.<x> = QQ['x']
2584
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2585
+ sage: x,y = E.monsky_washnitzer_gens()
2586
+ sage: x.parent().monomial(4,5)
2587
+ y^5*x^4
2588
+ """
2589
+ i = int(i)
2590
+ j = int(j)
2591
+
2592
+ if 0 < i < self._n:
2593
+ if b is None:
2594
+ by_to_j = self._series_ring_y << (j - 1)
2595
+ else:
2596
+ by_to_j = self._series_ring(b) << j
2597
+ v = [self._series_ring_0] * self._n
2598
+ v[i] = by_to_j
2599
+ return self.element_class(self, v)
2600
+
2601
+ if b is not None:
2602
+ b = self.base_ring()(b)
2603
+ return (self._x**i) << j if b is None else b * (self._x**i) << j
2604
+
2605
+ def monomial_diff_coeffs(self, i, j):
2606
+ r"""
2607
+ Compute coefficients of the basis representation of `d(x^iy^j)`.
2608
+
2609
+ The key here is that the formula for `d(x^iy^j)` is messy
2610
+ in terms of `i`, but varies nicely with `j`.
2611
+
2612
+ .. MATH::
2613
+
2614
+ d(x^iy^j) = y^{j-1} (2ix^{i-1}y^2 + j (A_i(x) + B_i(x)y^2)) \frac{dx}{2y},
2615
+
2616
+ where `A,B` have degree at most `n-1` for each
2617
+ `i`. Pre-compute `A_i, B_i` for each `i`
2618
+ the "hard" way, and the rest are easy.
2619
+
2620
+ EXAMPLES::
2621
+
2622
+ sage: R.<x> = QQ['x']
2623
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2624
+ sage: x,y = E.monsky_washnitzer_gens()
2625
+ sage: x.parent().monomial_diff_coeffs(2,3)
2626
+ ((0, -15, 36, 0, 0), (0, 19, 0, 0, 0))
2627
+ """
2628
+ try:
2629
+ return self._monomial_diff_coeffs[i, j]
2630
+ except KeyError:
2631
+ pass
2632
+ if i < self._n:
2633
+ try:
2634
+ A, B, two_i_x_to_i = self._precomputed_diff_coeffs[i]
2635
+ except AttributeError:
2636
+ self._precomputed_diff_coeffs = self._precompute_monomial_diffs()
2637
+ A, B, two_i_x_to_i = self._precomputed_diff_coeffs[i]
2638
+ if i == 0:
2639
+ return j*A, j*B
2640
+ else:
2641
+ return j*A, j*B + two_i_x_to_i
2642
+ else:
2643
+ dg = self.monomial(i, j).diff()
2644
+ coeffs = [dg.extract_pow_y(j-1), dg.extract_pow_y(j+1)]
2645
+ self._monomial_diff_coeffs[i, j] = coeffs
2646
+ return coeffs
2647
+
2648
+ def monomial_diff_coeffs_matrices(self):
2649
+ r"""
2650
+ Compute tables of coefficients of the basis representation
2651
+ of `d(x^iy^j)` for small `i`, `j`.
2652
+
2653
+ EXAMPLES::
2654
+
2655
+ sage: R.<x> = QQ['x']
2656
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2657
+ sage: x,y = E.monsky_washnitzer_gens()
2658
+ sage: x.parent().monomial_diff_coeffs_matrices()
2659
+ (
2660
+ [0 5 0 0 0] [0 2 0 0 0]
2661
+ [0 0 5 0 0] [0 0 4 0 0]
2662
+ [0 0 0 5 0] [0 0 0 6 0]
2663
+ [0 0 0 0 5] [0 0 0 0 8]
2664
+ [0 0 0 0 0], [0 0 0 0 0]
2665
+ )
2666
+ """
2667
+ self.monomial_diff_coeffs(0, 0) # precompute stuff
2668
+ R = self.base_ring()
2669
+ mat_1 = matrix(R, self._n, self._n)
2670
+ mat_2 = matrix(R, self._n, self._n)
2671
+ for i in range(self._n):
2672
+ mat_1[i] = self._precomputed_diff_coeffs[i][1]
2673
+ mat_2[i] = self._precomputed_diff_coeffs[i][2]
2674
+ return mat_1.transpose(), mat_2.transpose()
2675
+
2676
+ def _precompute_monomial_diffs(self) -> list:
2677
+ r"""
2678
+ Precompute coefficients of the basis representation of `d(x^iy^j)`
2679
+ for small `i`, `j`.
2680
+
2681
+ EXAMPLES::
2682
+
2683
+ sage: R.<x> = QQ['x']
2684
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2685
+ sage: x,y = E.monsky_washnitzer_gens()
2686
+ sage: x.parent()._precompute_monomial_diffs()
2687
+ [((-3, 0, 0, 0, 5), (0, 0, 0, 0, 0), (0, 0, 0, 0, 0)),
2688
+ ((-5, 12, 0, 0, 0), (5, 0, 0, 0, 0), (2, 0, 0, 0, 0)),
2689
+ ((0, -5, 12, 0, 0), (0, 5, 0, 0, 0), (0, 4, 0, 0, 0)),
2690
+ ((0, 0, -5, 12, 0), (0, 0, 5, 0, 0), (0, 0, 6, 0, 0)),
2691
+ ((0, 0, 0, -5, 12), (0, 0, 0, 5, 0), (0, 0, 0, 8, 0))]
2692
+ """
2693
+ x, y = self.gens()
2694
+ R = self.base_ring()
2695
+ V = FreeModule(R, self.degree())
2696
+ As = []
2697
+ for i in range(self.degree()):
2698
+ dg = self.monomial(i, 1).diff()
2699
+ two_i_x_to_i = R(2*i) * x**(i-1) * y*y if i > 0 else self(0)
2700
+ A = dg - self._monsky_washnitzer(two_i_x_to_i)
2701
+ As.append((V(A.extract_pow_y(0)), V(A.extract_pow_y(2)), V(two_i_x_to_i.extract_pow_y(2))))
2702
+ return As
2703
+
2704
+ def Q(self):
2705
+ """
2706
+ Return the defining polynomial of the underlying hyperelliptic curve.
2707
+
2708
+ EXAMPLES::
2709
+
2710
+ sage: R.<x> = QQ['x']
2711
+ sage: E = HyperellipticCurve(x^5-2*x+1)
2712
+ sage: x,y = E.monsky_washnitzer_gens()
2713
+ sage: x.parent().Q()
2714
+ x^5 - 2*x + 1
2715
+ """
2716
+ return self._Q
2717
+
2718
+ def curve(self):
2719
+ """
2720
+ Return the underlying hyperelliptic curve.
2721
+
2722
+ EXAMPLES::
2723
+
2724
+ sage: R.<x> = QQ['x']
2725
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2726
+ sage: x,y = E.monsky_washnitzer_gens()
2727
+ sage: x.parent().curve()
2728
+ Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 3*x + 1
2729
+ """
2730
+ return self._curve
2731
+
2732
+ def degree(self):
2733
+ """
2734
+ Return the degree of the underlying hyperelliptic curve.
2735
+
2736
+ EXAMPLES::
2737
+
2738
+ sage: R.<x> = QQ['x']
2739
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2740
+ sage: x,y = E.monsky_washnitzer_gens()
2741
+ sage: x.parent().degree()
2742
+ 5
2743
+ """
2744
+ return Integer(self._n)
2745
+
2746
+ def prime(self):
2747
+ """
2748
+ Return the stored prime number `p`.
2749
+
2750
+ EXAMPLES::
2751
+
2752
+ sage: R.<x> = QQ['x']
2753
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2754
+ sage: x,y = E.monsky_washnitzer_gens()
2755
+ sage: x.parent().prime() is None
2756
+ True
2757
+ """
2758
+ return self._p
2759
+
2760
+ def monsky_washnitzer(self):
2761
+ """
2762
+ Return the stored Monsky-Washnitzer differential ring.
2763
+
2764
+ EXAMPLES::
2765
+
2766
+ sage: R.<x> = QQ['x']
2767
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2768
+ sage: x,y = E.monsky_washnitzer_gens()
2769
+ sage: type(x.parent().monsky_washnitzer())
2770
+ <class 'sage.schemes.hyperelliptic_curves.monsky_washnitzer.MonskyWashnitzerDifferentialRing_with_category'>
2771
+ """
2772
+ return self._monsky_washnitzer
2773
+
2774
+ def is_field(self, proof=True) -> bool:
2775
+ """
2776
+ Return ``False`` as ``self`` is not a field.
2777
+
2778
+ EXAMPLES::
2779
+
2780
+ sage: R.<x> = QQ['x']
2781
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
2782
+ sage: x,y = E.monsky_washnitzer_gens()
2783
+ sage: x.parent().is_field()
2784
+ False
2785
+ """
2786
+ return False
2787
+
2788
+ Element = SpecialHyperellipticQuotientElement
2789
+
2790
+
2791
+ SpecialHyperellipticQuotientRing_class = SpecialHyperellipticQuotientRing
2792
+
2793
+
2794
+ class MonskyWashnitzerDifferential(ModuleElement):
2795
+ r"""
2796
+ An element of the Monsky-Washnitzer ring of differentials, of
2797
+ the form `F dx/2y`.
2798
+
2799
+ EXAMPLES::
2800
+
2801
+ sage: R.<x> = QQ['x']
2802
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
2803
+ sage: x,y = C.monsky_washnitzer_gens()
2804
+ sage: MW = C.invariant_differential().parent()
2805
+ sage: MW(x)
2806
+ x dx/2y
2807
+ sage: MW(y)
2808
+ y*1 dx/2y
2809
+ sage: MW(x, 10)
2810
+ y^10*x dx/2y
2811
+ """
2812
+ def __init__(self, parent, val, offset=0):
2813
+ r"""
2814
+ Initialize ``self``.
2815
+
2816
+ INPUT:
2817
+
2818
+ - ``parent`` -- Monsky-Washnitzer differential ring (instance of class
2819
+ :class:`~MonskyWashnitzerDifferentialRing`
2820
+
2821
+ - ``val`` -- element of the base ring, or list of coefficients
2822
+
2823
+ - ``offset`` -- (default: 0) if nonzero, shift val by `y^\text{offset}`
2824
+
2825
+ EXAMPLES::
2826
+
2827
+ sage: R.<x> = QQ['x']
2828
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
2829
+ sage: x,y = C.monsky_washnitzer_gens()
2830
+ sage: MW = C.invariant_differential().parent()
2831
+ sage: elt = MW(x)
2832
+ sage: TestSuite(elt).run()
2833
+ """
2834
+ ModuleElement.__init__(self, parent)
2835
+ R = parent.base_ring()
2836
+ self._coeff = R._element_constructor_(val, offset)
2837
+
2838
+ def _add_(self, other):
2839
+ r"""
2840
+ Return the sum of ``self`` and ``other``, both elements of the
2841
+ Monsky-Washnitzer ring of differentials.
2842
+
2843
+ EXAMPLES::
2844
+
2845
+ sage: R.<x> = QQ['x']
2846
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
2847
+ sage: x,y = C.monsky_washnitzer_gens()
2848
+ sage: w = C.invariant_differential()
2849
+ sage: w + w
2850
+ 2*1 dx/2y
2851
+ sage: x*w + w
2852
+ (1 + x) dx/2y
2853
+ sage: x*w + y*w
2854
+ (y*1 + x) dx/2y
2855
+ """
2856
+ P = self.parent()
2857
+ return P.element_class(P, self._coeff + other._coeff)
2858
+
2859
+ def _sub_(self, other):
2860
+ r"""
2861
+ Return the difference of ``self`` and ``other``, both elements of the
2862
+ Monsky-Washnitzer ring of differentials.
2863
+
2864
+ EXAMPLES::
2865
+
2866
+ sage: R.<x> = QQ['x']
2867
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
2868
+ sage: x,y = C.monsky_washnitzer_gens()
2869
+ sage: w = C.invariant_differential()
2870
+ sage: w-w
2871
+ 0 dx/2y
2872
+ sage: x*w-w
2873
+ (-1 + x) dx/2y
2874
+ sage: w - x*w - y*w
2875
+ ((1-y)*1 - x) dx/2y
2876
+ """
2877
+ P = self.parent()
2878
+ return P.element_class(P, self._coeff - other._coeff)
2879
+
2880
+ def __neg__(self):
2881
+ r"""
2882
+ Return the additive inverse of ``self``.
2883
+
2884
+ EXAMPLES::
2885
+
2886
+ sage: R.<x> = QQ['x']
2887
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
2888
+ sage: x,y = C.monsky_washnitzer_gens()
2889
+ sage: w = C.invariant_differential()
2890
+ sage: -w
2891
+ -1 dx/2y
2892
+ sage: -((y-x)*w)
2893
+ (-y*1 + x) dx/2y
2894
+ """
2895
+ P = self.parent()
2896
+ return P.element_class(P, -self._coeff)
2897
+
2898
+ def _lmul_(self, a):
2899
+ r"""
2900
+ Return `self * a`.
2901
+
2902
+ EXAMPLES::
2903
+
2904
+ sage: R.<x> = QQ['x']
2905
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
2906
+ sage: x,y = C.monsky_washnitzer_gens()
2907
+ sage: w = C.invariant_differential()
2908
+ sage: w*x
2909
+ x dx/2y
2910
+ sage: (w*x)*2
2911
+ 2*x dx/2y
2912
+ sage: w*y
2913
+ y*1 dx/2y
2914
+ sage: w*(x+y)
2915
+ (y*1 + x) dx/2y
2916
+ """
2917
+ P = self.parent()
2918
+ return P.element_class(P, self._coeff * a)
2919
+
2920
+ def _rmul_(self, a):
2921
+ r"""
2922
+ Return `a * self`.
2923
+
2924
+ EXAMPLES::
2925
+
2926
+ sage: R.<x> = QQ['x']
2927
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
2928
+ sage: x,y = C.monsky_washnitzer_gens()
2929
+ sage: w = C.invariant_differential()
2930
+ sage: x*w
2931
+ x dx/2y
2932
+ sage: 2*(x*w)
2933
+ 2*x dx/2y
2934
+ sage: y*w
2935
+ y*1 dx/2y
2936
+ sage: (x+y)*w
2937
+ (y*1 + x) dx/2y
2938
+ """
2939
+ P = self.parent()
2940
+ return P.element_class(P, a * self._coeff)
2941
+
2942
+ def coeff(self):
2943
+ r"""
2944
+ Return `A`, where this element is `A dx/2y`.
2945
+
2946
+ EXAMPLES::
2947
+
2948
+ sage: R.<x> = QQ['x']
2949
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
2950
+ sage: x,y = C.monsky_washnitzer_gens()
2951
+ sage: w = C.invariant_differential()
2952
+ sage: w
2953
+ 1 dx/2y
2954
+ sage: w.coeff()
2955
+ 1
2956
+ sage: (x*y*w).coeff()
2957
+ y*x
2958
+ """
2959
+ return self._coeff
2960
+
2961
+ def __bool__(self):
2962
+ r"""
2963
+ EXAMPLES::
2964
+
2965
+ sage: R.<x> = QQ['x']
2966
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
2967
+ sage: x,y = C.monsky_washnitzer_gens()
2968
+ sage: w = C.invariant_differential()
2969
+ sage: not w
2970
+ False
2971
+ sage: not 0*w
2972
+ True
2973
+ sage: not x*y*w
2974
+ False
2975
+ """
2976
+ return bool(self._coeff)
2977
+
2978
+ def _repr_(self):
2979
+ r"""
2980
+ EXAMPLES::
2981
+
2982
+ sage: R.<x> = QQ['x']
2983
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
2984
+ sage: x,y = C.monsky_washnitzer_gens()
2985
+ sage: w = C.invariant_differential()
2986
+ sage: w
2987
+ 1 dx/2y
2988
+ sage: (2*x+y)*w
2989
+ (y*1 + 2*x) dx/2y
2990
+ """
2991
+ s = self._coeff._repr_()
2992
+ if s.find("+") != -1 or s.find("-") > 0:
2993
+ s = "(%s)" % s
2994
+ return s + " dx/2y"
2995
+
2996
+ def _latex_(self):
2997
+ r"""
2998
+ Return the latex representation of ``self``.
2999
+
3000
+ EXAMPLES::
3001
+
3002
+ sage: R.<x> = QQ['x']
3003
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3004
+ sage: x,y = C.monsky_washnitzer_gens()
3005
+ sage: w = C.invariant_differential()
3006
+ sage: latex(w)
3007
+ 1 \frac{dx}{2y}
3008
+ sage: latex(x*w)
3009
+ x \frac{dx}{2y}
3010
+ """
3011
+ s = self._coeff._latex_()
3012
+ if s.find("+") != -1 or s.find("-") > 0:
3013
+ s = "\\left(%s\\right)" % s
3014
+ return s + " \\frac{dx}{2y}"
3015
+
3016
+ def _richcmp_(self, other, op):
3017
+ """
3018
+ Rich comparison of ``self`` to ``other``.
3019
+
3020
+ .. TODO::
3021
+
3022
+ This does not compare elements by any reduction;
3023
+ it only compares the coefficients. The comparison
3024
+ should be done against a normal form or possibly
3025
+ after some reduction steps.
3026
+
3027
+ EXAMPLES::
3028
+
3029
+ sage: R.<x> = QQ['x']
3030
+ sage: C = HyperellipticCurve(x^5 - 3*x + 1)
3031
+ sage: x,y = C.monsky_washnitzer_gens()
3032
+ sage: (y^-1).diff() == (y^-1).diff()
3033
+ True
3034
+
3035
+ This element is the zero differential in the ring, but it does
3036
+ not compare as equal because the representative is different::
3037
+
3038
+ sage: MW = C.invariant_differential().parent()
3039
+ sage: (y^-1).diff().reduce_neg_y()
3040
+ ((y^-1)*1, 0 dx/2y)
3041
+ sage: (y^-1).diff() == MW.zero()
3042
+ False
3043
+ """
3044
+ return richcmp(self._coeff, other._coeff, op)
3045
+
3046
+ def extract_pow_y(self, k):
3047
+ r"""
3048
+ Return the power of `y` in `A` where ``self`` is `A dx/2y`.
3049
+
3050
+ EXAMPLES::
3051
+
3052
+ sage: R.<x> = QQ['x']
3053
+ sage: C = HyperellipticCurve(x^5 - 3*x + 1)
3054
+ sage: x,y = C.monsky_washnitzer_gens()
3055
+ sage: A = y^5 - x*y^3
3056
+ sage: A.extract_pow_y(5)
3057
+ [1, 0, 0, 0, 0]
3058
+ sage: (A * C.invariant_differential()).extract_pow_y(5)
3059
+ [1, 0, 0, 0, 0]
3060
+ """
3061
+ return self._coeff.extract_pow_y(k)
3062
+
3063
+ def min_pow_y(self):
3064
+ r"""
3065
+ Return the minimum power of `y` in `A` where ``self`` is `A dx/2y`.
3066
+
3067
+ EXAMPLES::
3068
+
3069
+ sage: R.<x> = QQ['x']
3070
+ sage: C = HyperellipticCurve(x^5 - 3*x + 1)
3071
+ sage: x,y = C.monsky_washnitzer_gens()
3072
+ sage: w = y^5 * C.invariant_differential()
3073
+ sage: w.min_pow_y()
3074
+ 5
3075
+ sage: w = (x^2*y^4 + y^5) * C.invariant_differential()
3076
+ sage: w.min_pow_y()
3077
+ 4
3078
+ """
3079
+ return self._coeff.min_pow_y()
3080
+
3081
+ def max_pow_y(self):
3082
+ r"""
3083
+ Return the maximum power of `y` in `A` where ``self`` is `A dx/2y`.
3084
+
3085
+ EXAMPLES::
3086
+
3087
+ sage: R.<x> = QQ['x']
3088
+ sage: C = HyperellipticCurve(x^5 - 3*x + 1)
3089
+ sage: x,y = C.monsky_washnitzer_gens()
3090
+ sage: w = y^5 * C.invariant_differential()
3091
+ sage: w.max_pow_y()
3092
+ 5
3093
+ sage: w = (x^2*y^4 + y^5) * C.invariant_differential()
3094
+ sage: w.max_pow_y()
3095
+ 5
3096
+ """
3097
+ return self._coeff.max_pow_y()
3098
+
3099
+ def reduce_neg_y(self):
3100
+ r"""
3101
+ Use homology relations to eliminate negative powers of `y`.
3102
+
3103
+ EXAMPLES::
3104
+
3105
+ sage: R.<x> = QQ['x']
3106
+ sage: C = HyperellipticCurve(x^5 - 3*x + 1)
3107
+ sage: x,y = C.monsky_washnitzer_gens()
3108
+ sage: (y^-1).diff().reduce_neg_y()
3109
+ ((y^-1)*1, 0 dx/2y)
3110
+ sage: (y^-5*x^2+y^-1*x).diff().reduce_neg_y()
3111
+ ((y^-1)*x + (y^-5)*x^2, 0 dx/2y)
3112
+ """
3113
+ S = self.parent().base_ring()
3114
+ R = S.base_ring()
3115
+ M = self.parent().helper_matrix()
3116
+ p = S._p
3117
+ f = S.zero()
3118
+ reduced = self
3119
+ for j in range(self.min_pow_y()+1, 0):
3120
+ if p is not None and p.divides(j):
3121
+ cs = [a/j for a in reduced.extract_pow_y(j-1)]
3122
+ else:
3123
+ j_inverse = ~R(j)
3124
+ cs = [a*j_inverse for a in reduced.extract_pow_y(j-1)]
3125
+ lin_comb = M * vector(M.base_ring(), cs)
3126
+ if lin_comb.is_zero():
3127
+ continue
3128
+ g = S.sum(S.monomial(i, j, val) for i, val in enumerate(lin_comb) if val)
3129
+ if not g.is_zero():
3130
+ f += g
3131
+ reduced -= g.diff()
3132
+
3133
+ return f, reduced
3134
+
3135
+ def reduce_neg_y_fast(self, even_degree_only=False):
3136
+ r"""
3137
+ Use homology relations to eliminate negative powers of `y`.
3138
+
3139
+ EXAMPLES::
3140
+
3141
+ sage: R.<x> = QQ['x']
3142
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
3143
+ sage: x, y = E.monsky_washnitzer_gens()
3144
+ sage: (y^-1).diff().reduce_neg_y_fast()
3145
+ ((y^-1)*1, 0 dx/2y)
3146
+ sage: (y^-5*x^2+y^-1*x).diff().reduce_neg_y_fast()
3147
+ ((y^-1)*x + (y^-5)*x^2, 0 dx/2y)
3148
+
3149
+ It leaves nonnegative powers of `y` alone::
3150
+
3151
+ sage: y.diff()
3152
+ (-3*1 + 5*x^4) dx/2y
3153
+ sage: y.diff().reduce_neg_y_fast()
3154
+ (0, (-3*1 + 5*x^4) dx/2y)
3155
+ """
3156
+ # prof = Profiler()
3157
+ # prof("reduce setup")
3158
+ S = self.parent().base_ring()
3159
+ R = S.base_ring()
3160
+ M = self.parent().helper_matrix()
3161
+
3162
+ # prof("extract coeffs")
3163
+ coeffs, offset = self.coeffs(R)
3164
+ V = coeffs[0].parent()
3165
+
3166
+ if offset == 0:
3167
+ return S(0), self
3168
+
3169
+ # prof("loop %s"%self.min_pow_y())
3170
+ forms = []
3171
+ p = S._p
3172
+ for j in range(self.min_pow_y()+1, 0):
3173
+ if (even_degree_only and j % 2 == 0) or coeffs[j-offset-1].is_zero():
3174
+ forms.append(V(0))
3175
+ else:
3176
+ # this is a total hack to deal with the fact that we're using
3177
+ # rational numbers to approximate fixed precision p-adics
3178
+ if p is not None and j % 3 == 1:
3179
+ try:
3180
+ v = coeffs[j-offset-1]
3181
+ for kk in range(len(v)):
3182
+ a = v[kk]
3183
+ ppow = p**max(-a.valuation(S._p), 0)
3184
+ v[kk] = ((a * ppow) % S._prec_cap) / ppow
3185
+ except AttributeError:
3186
+ pass
3187
+ lin_comb = ~R(j) * (M * coeffs[j-offset-1])
3188
+ forms.append(lin_comb)
3189
+ for i in lin_comb.nonzero_positions():
3190
+ # g = lin_comb[i] x^i y^j
3191
+ # self -= dg
3192
+ coeffs[j-offset+1] -= lin_comb[i] * S.monomial_diff_coeffs(i, j)[1]
3193
+
3194
+ # prof("recreate forms")
3195
+ f = S(forms, offset+1)
3196
+ reduced = S._monsky_washnitzer(coeffs[-1-offset:], -1)
3197
+ return f, reduced
3198
+
3199
+ def reduce_neg_y_faster(self, even_degree_only=False):
3200
+ r"""
3201
+ Use homology relations to eliminate negative powers of `y`.
3202
+
3203
+ EXAMPLES::
3204
+
3205
+ sage: R.<x> = QQ['x']
3206
+ sage: C = HyperellipticCurve(x^5 - 3*x + 1)
3207
+ sage: x,y = C.monsky_washnitzer_gens()
3208
+ sage: (y^-1).diff().reduce_neg_y()
3209
+ ((y^-1)*1, 0 dx/2y)
3210
+ sage: (y^-5*x^2+y^-1*x).diff().reduce_neg_y_faster()
3211
+ ((y^-1)*x + (y^-5)*x^2, 0 dx/2y)
3212
+ """
3213
+ # Timings indicate that this is not any faster after all...
3214
+
3215
+ S = self.parent().base_ring()
3216
+ R = S.base_ring()
3217
+ M = self.parent().helper_matrix()
3218
+
3219
+ coeffs, offset = self.coeffs(R)
3220
+ V = coeffs[0].parent()
3221
+ zeroV = V(0)
3222
+
3223
+ if offset == 0:
3224
+ return S.zero(), self
3225
+
3226
+ # See monomial_diff_coeffs
3227
+ # this is the B_i and x_to_i contributions respectively for all i
3228
+ d_mat_1, d_mat_2 = S.monomial_diff_coeffs_matrices()
3229
+
3230
+ forms = []
3231
+ for j in range(self.min_pow_y()+1, 0):
3232
+ if coeffs[j-offset-1].is_zero():
3233
+ forms.append(zeroV)
3234
+ else:
3235
+ # this is a total hack to deal with the fact that we're using
3236
+ # rational numbers to approximate fixed precision p-adics
3237
+ if j % 3 == 0:
3238
+ try:
3239
+ v = coeffs[j-offset-1]
3240
+ for kk in range(len(v)):
3241
+ a = v[kk]
3242
+ ppow = S._p**max(-a.valuation(S._p), 0)
3243
+ v[kk] = ((a * ppow) % S._prec_cap) / ppow
3244
+ except AttributeError:
3245
+ pass
3246
+ j_inverse = ~R(j)
3247
+ lin_comb = (M * coeffs[j-offset-1])
3248
+ forms.append(j_inverse * lin_comb)
3249
+ coeffs[j-offset+1] -= (d_mat_1 + j_inverse * d_mat_2) * lin_comb
3250
+
3251
+ f = S(forms, offset + 1)
3252
+ reduced = S._monsky_washnitzer(coeffs[-1-offset:], -1)
3253
+ # reduced = self - f.diff()
3254
+ return f, reduced
3255
+
3256
+ def reduce_pos_y(self):
3257
+ r"""
3258
+ Use homology relations to eliminate positive powers of `y`.
3259
+
3260
+ EXAMPLES::
3261
+
3262
+ sage: R.<x> = QQ['x']
3263
+ sage: C = HyperellipticCurve(x^3-4*x+4)
3264
+ sage: x,y = C.monsky_washnitzer_gens()
3265
+ sage: (y^2).diff().reduce_pos_y()
3266
+ (y^2*1, 0 dx/2y)
3267
+ sage: (y^2*x).diff().reduce_pos_y()
3268
+ (y^2*x, 0 dx/2y)
3269
+ sage: (y^92*x).diff().reduce_pos_y()
3270
+ (y^92*x, 0 dx/2y)
3271
+ sage: w = (y^3 + x).diff()
3272
+ sage: w += w.parent()(x)
3273
+ sage: w.reduce_pos_y_fast()
3274
+ (y^3*1 + x, x dx/2y)
3275
+ """
3276
+ S = self.parent().base_ring()
3277
+ n = S.Q().degree()
3278
+ f = S.zero()
3279
+ reduced = self
3280
+ for j in range(self.max_pow_y(), 0, -1):
3281
+ for i in range(n - 1, -1, -1):
3282
+ c = reduced.extract_pow_y(j)[i]
3283
+ if c:
3284
+ g = S.monomial(0, j+1) if i == n-1 else S.monomial(i+1, j-1)
3285
+ dg = g.diff()
3286
+ denom = dg.extract_pow_y(j)[i]
3287
+ c /= denom
3288
+ c = g.parent()(c)
3289
+ f += c * g
3290
+ reduced -= c * dg
3291
+
3292
+ return f, reduced
3293
+
3294
+ def reduce_pos_y_fast(self, even_degree_only=False):
3295
+ r"""
3296
+ Use homology relations to eliminate positive powers of `y`.
3297
+
3298
+ EXAMPLES::
3299
+
3300
+ sage: R.<x> = QQ['x']
3301
+ sage: E = HyperellipticCurve(x^3 - 4*x + 4)
3302
+ sage: x, y = E.monsky_washnitzer_gens()
3303
+ sage: y.diff().reduce_pos_y_fast()
3304
+ (y*1, 0 dx/2y)
3305
+ sage: (y^2).diff().reduce_pos_y_fast()
3306
+ (y^2*1, 0 dx/2y)
3307
+ sage: (y^2*x).diff().reduce_pos_y_fast()
3308
+ (y^2*x, 0 dx/2y)
3309
+ sage: (y^92*x).diff().reduce_pos_y_fast()
3310
+ (y^92*x, 0 dx/2y)
3311
+ sage: w = (y^3 + x).diff()
3312
+ sage: w += w.parent()(x)
3313
+ sage: w.reduce_pos_y_fast()
3314
+ (y^3*1 + x, x dx/2y)
3315
+ """
3316
+ S = self.parent().base_ring()
3317
+ R = S.base_ring()
3318
+ n = S.Q().degree()
3319
+
3320
+ coeffs, offset = self.coeffs(R)
3321
+ V = coeffs[0].parent()
3322
+ zeroV = V(0)
3323
+ forms = [V(0), V(0)]
3324
+
3325
+ for j in range(self.max_pow_y(), -1, -1):
3326
+
3327
+ if (even_degree_only and j % 2) or (j > 0 and coeffs[j-offset].is_zero()):
3328
+ forms.append(zeroV)
3329
+ continue
3330
+
3331
+ form = V(0)
3332
+ i = n - 1
3333
+ c = coeffs[j-offset][i]
3334
+ if c:
3335
+ dg_coeffs = S.monomial_diff_coeffs(0, j+1)[0]
3336
+ c /= dg_coeffs[i]
3337
+ forms[len(forms)-2][0] = c
3338
+ # self -= c d(y^{j+1})
3339
+ coeffs[j-offset] -= c*dg_coeffs
3340
+
3341
+ if j == 0:
3342
+ # the others are basis elements
3343
+ break
3344
+
3345
+ for i in range(n-2, -1, -1):
3346
+ c = coeffs[j-offset][i]
3347
+ if c:
3348
+ dg_coeffs = S.monomial_diff_coeffs(i+1, j-1)
3349
+ denom = dg_coeffs[1][i]
3350
+ c /= denom
3351
+ form[i+1] = c
3352
+ # self -= c d(x^{i+1} y^{j-1})
3353
+ coeffs[j-offset] -= c*dg_coeffs[1]
3354
+ coeffs[j-offset-2] -= c*dg_coeffs[0]
3355
+ forms.append(form)
3356
+
3357
+ forms.reverse()
3358
+ f = S(forms)
3359
+ reduced = self.parent()(coeffs[:1-offset], offset)
3360
+ return f, reduced
3361
+
3362
+ def reduce(self):
3363
+ r"""
3364
+ Use homology relations to find `a` and `f` such that this element is
3365
+ equal to `a + df`, where `a` is given in terms of the `x^i dx/2y`.
3366
+
3367
+ EXAMPLES::
3368
+
3369
+ sage: R.<x> = QQ['x']
3370
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3371
+ sage: x,y = C.monsky_washnitzer_gens()
3372
+ sage: w = (y*x).diff()
3373
+ sage: w.reduce()
3374
+ (y*x, 0 dx/2y)
3375
+
3376
+ sage: w = x^4 * C.invariant_differential()
3377
+ sage: w.reduce()
3378
+ (1/5*y*1, 4/5*1 dx/2y)
3379
+
3380
+ sage: w = sum(QQ.random_element() * x^i * y^j
3381
+ ....: for i in [0..4] for j in [-3..3]) * C.invariant_differential()
3382
+ sage: f, a = w.reduce()
3383
+ sage: f.diff() + a - w
3384
+ 0 dx/2y
3385
+ """
3386
+ n = self.parent().base_ring().Q().degree()
3387
+ f1, a = self.reduce_neg_y()
3388
+ f2, a = a.reduce_pos_y()
3389
+ f = f1 + f2
3390
+
3391
+ c = a.extract_pow_y(0)[n - 1]
3392
+ if c:
3393
+ x, y = self.parent().base_ring().gens()
3394
+ g = y
3395
+ dg = g.diff()
3396
+ c = g.parent()(c / dg.extract_pow_y(0)[n - 1])
3397
+ f += c * g
3398
+ a -= c * dg
3399
+
3400
+ return f, a
3401
+
3402
+ def reduce_fast(self, even_degree_only=False):
3403
+ r"""
3404
+ Use homology relations to find `a` and `f` such that this element is
3405
+ equal to `a + df`, where `a` is given in terms of the `x^i dx/2y`.
3406
+
3407
+ EXAMPLES::
3408
+
3409
+ sage: R.<x> = QQ['x']
3410
+ sage: E = HyperellipticCurve(x^3 - 4*x + 4)
3411
+ sage: x, y = E.monsky_washnitzer_gens()
3412
+ sage: x.diff().reduce_fast()
3413
+ (x, (0, 0))
3414
+ sage: y.diff().reduce_fast()
3415
+ (y*1, (0, 0))
3416
+ sage: (y^-1).diff().reduce_fast()
3417
+ ((y^-1)*1, (0, 0))
3418
+ sage: (y^-11).diff().reduce_fast()
3419
+ ((y^-11)*1, (0, 0))
3420
+ sage: (x*y^2).diff().reduce_fast()
3421
+ (y^2*x, (0, 0))
3422
+ """
3423
+ f1, reduced = self.reduce_neg_y_fast(even_degree_only)
3424
+ f2, reduced = reduced.reduce_pos_y_fast(even_degree_only)
3425
+ # f1, reduced = self.reduce_neg_y()
3426
+ # f2, reduced = reduced.reduce_pos_y()
3427
+ v = reduced.extract_pow_y(0)
3428
+ v.pop()
3429
+ V = FreeModule(self.base_ring().base_ring(), len(v))
3430
+ return f1 + f2, V(v)
3431
+
3432
+ def coeffs(self, R=None):
3433
+ """
3434
+ Used to obtain the raw coefficients of a differential, see
3435
+ :meth:`SpecialHyperellipticQuotientElement.coeffs`
3436
+
3437
+ INPUT:
3438
+
3439
+ - ``R`` -- an (optional) base ring in which to cast the coefficients
3440
+
3441
+ OUTPUT: the raw coefficients of `A` where ``self`` is `A dx/2y`
3442
+
3443
+ EXAMPLES::
3444
+
3445
+ sage: R.<x> = QQ['x']
3446
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3447
+ sage: x,y = C.monsky_washnitzer_gens()
3448
+ sage: w = C.invariant_differential()
3449
+ sage: w.coeffs()
3450
+ ([(1, 0, 0, 0, 0)], 0)
3451
+ sage: (x*w).coeffs()
3452
+ ([(0, 1, 0, 0, 0)], 0)
3453
+ sage: (y*w).coeffs()
3454
+ ([(0, 0, 0, 0, 0), (1, 0, 0, 0, 0)], 0)
3455
+ sage: (y^-2*w).coeffs()
3456
+ ([(1, 0, 0, 0, 0), (0, 0, 0, 0, 0), (0, 0, 0, 0, 0)], -2)
3457
+ """
3458
+ return self._coeff.coeffs(R)
3459
+
3460
+ def coleman_integral(self, P, Q):
3461
+ r"""
3462
+ Compute the definite integral of ``self`` from `P` to `Q`.
3463
+
3464
+ INPUT:
3465
+
3466
+ - `P`, `Q` -- two points on the underlying curve
3467
+
3468
+ OUTPUT: `\int_P^Q \text{self}`
3469
+
3470
+ EXAMPLES::
3471
+
3472
+ sage: K = pAdicField(5,7)
3473
+ sage: E = EllipticCurve(K,[-31/3,-2501/108]) #11a
3474
+ sage: P = E(K(14/3), K(11/2))
3475
+ sage: w = E.invariant_differential()
3476
+ sage: w.coleman_integral(P, 2*P)
3477
+ O(5^6)
3478
+
3479
+ sage: Q = E([3,58332])
3480
+ sage: w.coleman_integral(P,Q)
3481
+ 2*5 + 4*5^2 + 3*5^3 + 4*5^4 + 3*5^5 + O(5^6)
3482
+ sage: w.coleman_integral(2*P,Q)
3483
+ 2*5 + 4*5^2 + 3*5^3 + 4*5^4 + 3*5^5 + O(5^6)
3484
+ sage: (2*w).coleman_integral(P, Q) == 2*(w.coleman_integral(P, Q))
3485
+ True
3486
+ """
3487
+ return self.parent().base_ring().curve().coleman_integral(self, P, Q)
3488
+
3489
+ integrate = coleman_integral
3490
+
3491
+
3492
+ class MonskyWashnitzerDifferentialRing(UniqueRepresentation, Module):
3493
+ r"""
3494
+ A ring of Monsky--Washnitzer differentials over ``base_ring``.
3495
+ """
3496
+ def __init__(self, base_ring):
3497
+ r"""
3498
+ Initialize ``self``.
3499
+
3500
+ TESTS::
3501
+
3502
+ sage: R.<x> = QQ['x']
3503
+ sage: E = HyperellipticCurve(x^5 - 3*x + 1)
3504
+ sage: from sage.schemes.hyperelliptic_curves.monsky_washnitzer import SpecialHyperellipticQuotientRing, MonskyWashnitzerDifferentialRing
3505
+ sage: S = SpecialHyperellipticQuotientRing(E)
3506
+ sage: DR = MonskyWashnitzerDifferentialRing(S)
3507
+ sage: TestSuite(DR).run() # needs sage.rings.real_interval_field
3508
+
3509
+ Check that caching works::
3510
+
3511
+ sage: DR is MonskyWashnitzerDifferentialRing(S)
3512
+ True
3513
+ """
3514
+ Module.__init__(self, base_ring)
3515
+
3516
+ def invariant_differential(self):
3517
+ r"""
3518
+ Return `dx/2y` as an element of ``self``.
3519
+
3520
+ EXAMPLES::
3521
+
3522
+ sage: R.<x> = QQ['x']
3523
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3524
+ sage: MW = C.invariant_differential().parent()
3525
+ sage: MW.invariant_differential()
3526
+ 1 dx/2y
3527
+ """
3528
+ return self.element_class(self, 1)
3529
+
3530
+ def base_extend(self, R):
3531
+ """
3532
+ Return a new differential ring which is ``self`` base-extended to `R`.
3533
+
3534
+ INPUT:
3535
+
3536
+ - ``R`` -- ring
3537
+
3538
+ OUTPUT:
3539
+
3540
+ Self, base-extended to `R`.
3541
+
3542
+ EXAMPLES::
3543
+
3544
+ sage: R.<x> = QQ['x']
3545
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3546
+ sage: MW = C.invariant_differential().parent()
3547
+ sage: MW.base_ring()
3548
+ SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = x^5 - 4*x + 4)
3549
+ over Rational Field
3550
+ sage: MW.base_extend(Qp(5,5)).base_ring() # needs sage.rings.padics
3551
+ SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = (1 + O(5^5))*x^5
3552
+ + (1 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5))*x + 4 + O(5^5))
3553
+ over 5-adic Field with capped relative precision 5
3554
+ """
3555
+ return MonskyWashnitzerDifferentialRing(self.base_ring().base_extend(R))
3556
+
3557
+ def change_ring(self, R):
3558
+ """
3559
+ Return a new differential ring which is ``self`` with the coefficient
3560
+ ring changed to `R`.
3561
+
3562
+ INPUT:
3563
+
3564
+ - ``R`` -- ring of coefficients
3565
+
3566
+ OUTPUT: ``self`` with the coefficient ring changed to `R`
3567
+
3568
+ EXAMPLES::
3569
+
3570
+ sage: R.<x> = QQ['x']
3571
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3572
+ sage: MW = C.invariant_differential().parent()
3573
+ sage: MW.base_ring()
3574
+ SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = x^5 - 4*x + 4)
3575
+ over Rational Field
3576
+ sage: MW.change_ring(Qp(5,5)).base_ring() # needs sage.rings.padics
3577
+ SpecialHyperellipticQuotientRing K[x,y,y^-1] / (y^2 = (1 + O(5^5))*x^5
3578
+ + (1 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5))*x + 4 + O(5^5))
3579
+ over 5-adic Field with capped relative precision 5
3580
+ """
3581
+ return MonskyWashnitzerDifferentialRing(self.base_ring().change_ring(R))
3582
+
3583
+ def degree(self):
3584
+ """
3585
+ Return the degree of `Q(x)`, where the model of the underlying
3586
+ hyperelliptic curve of ``self`` is given by `y^2 = Q(x)`.
3587
+
3588
+ EXAMPLES::
3589
+
3590
+ sage: R.<x> = QQ['x']
3591
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3592
+ sage: MW = C.invariant_differential().parent()
3593
+ sage: MW.Q()
3594
+ x^5 - 4*x + 4
3595
+ sage: MW.degree()
3596
+ 5
3597
+ """
3598
+ return self.base_ring().degree()
3599
+
3600
+ def dimension(self):
3601
+ """
3602
+ Return the dimension of ``self``.
3603
+
3604
+ EXAMPLES::
3605
+
3606
+ sage: # needs sage.rings.padics
3607
+ sage: R.<x> = QQ['x']
3608
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3609
+ sage: K = Qp(7,5)
3610
+ sage: CK = C.change_ring(K)
3611
+ sage: MW = CK.invariant_differential().parent()
3612
+ sage: MW.dimension()
3613
+ 4
3614
+ """
3615
+ return self.base_ring().degree() - 1
3616
+
3617
+ def Q(self):
3618
+ """
3619
+ Return `Q(x)` where the model of the underlying hyperelliptic curve
3620
+ of ``self`` is given by `y^2 = Q(x)`.
3621
+
3622
+ EXAMPLES::
3623
+
3624
+ sage: R.<x> = QQ['x']
3625
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3626
+ sage: MW = C.invariant_differential().parent()
3627
+ sage: MW.Q()
3628
+ x^5 - 4*x + 4
3629
+ """
3630
+ return self.base_ring().Q()
3631
+
3632
+ @cached_method
3633
+ def x_to_p(self, p):
3634
+ """
3635
+ Return and cache `x^p`, reduced via the relations coming from the
3636
+ defining polynomial of the hyperelliptic curve.
3637
+
3638
+ EXAMPLES::
3639
+
3640
+ sage: R.<x> = QQ['x']
3641
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3642
+ sage: MW = C.invariant_differential().parent()
3643
+ sage: MW.x_to_p(3)
3644
+ x^3
3645
+ sage: MW.x_to_p(5)
3646
+ -(4-y^2)*1 + 4*x
3647
+ sage: MW.x_to_p(101) is MW.x_to_p(101)
3648
+ True
3649
+ """
3650
+ return self.base_ring().x()**p
3651
+
3652
+ @cached_method
3653
+ def frob_Q(self, p):
3654
+ r"""
3655
+ Return and cache `Q(x^p)`, which is used in computing the image of
3656
+ `y` under a `p`-power lift of Frobenius to `A^{\dagger}`.
3657
+
3658
+ EXAMPLES::
3659
+
3660
+ sage: R.<x> = QQ['x']
3661
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3662
+ sage: MW = C.invariant_differential().parent()
3663
+ sage: MW.frob_Q(3)
3664
+ -(60-48*y^2+12*y^4-y^6)*1 + (192-96*y^2+12*y^4)*x - (192-48*y^2)*x^2 + 60*x^3
3665
+ sage: MW.Q()(MW.x_to_p(3)) # needs sage.rings.real_interval_field
3666
+ -(60-48*y^2+12*y^4-y^6)*1 + (192-96*y^2+12*y^4)*x - (192-48*y^2)*x^2 + 60*x^3
3667
+ sage: MW.frob_Q(11) is MW.frob_Q(11)
3668
+ True
3669
+ """
3670
+ return self.base_ring()._Q.change_ring(self.base_ring())(self.x_to_p(p))
3671
+
3672
+ def frob_invariant_differential(self, prec, p):
3673
+ r"""
3674
+ Kedlaya's algorithm allows us to calculate the action of Frobenius on
3675
+ the Monsky-Washnitzer cohomology. First we lift `\phi` to `A^{\dagger}`
3676
+ by setting
3677
+
3678
+ .. MATH::
3679
+
3680
+ \phi(x) = x^p,
3681
+ \qquad\qquad
3682
+ \phi(y) = y^p \sqrt{1 + \frac{Q(x^p) - Q(x)^p}{Q(x)^p}}.
3683
+
3684
+ Pulling back the differential `dx/2y`, we get
3685
+
3686
+ .. MATH::
3687
+
3688
+ \phi^*(dx/2y) = px^{p-1} y(\phi(y))^{-1} dx/2y
3689
+ = px^{p-1} y^{1-p} \sqrt{1+ \frac{Q(x^p) - Q(x)^p}{Q(x)^p}} dx/2y.
3690
+
3691
+ Use Newton's method to calculate the square root.
3692
+
3693
+ EXAMPLES::
3694
+
3695
+ sage: R.<x> = QQ['x']
3696
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3697
+ sage: prec = 2
3698
+ sage: p = 7
3699
+ sage: MW = C.invariant_differential().parent()
3700
+ sage: MW.frob_invariant_differential(prec, p)
3701
+ ((67894400*y^-20-81198880*y^-18+40140800*y^-16-10035200*y^-14+1254400*y^-12-62720*y^-10)*1
3702
+ - (119503944*y^-20-116064242*y^-18+43753472*y^-16-7426048*y^-14+514304*y^-12-12544*y^-10+1568*y^-8-70*y^-6-7*y^-4)*x
3703
+ + (78905288*y^-20-61014016*y^-18+16859136*y^-16-2207744*y^-14+250880*y^-12-37632*y^-10+3136*y^-8-70*y^-6)*x^2
3704
+ - (39452448*y^-20-26148752*y^-18+8085490*y^-16-2007040*y^-14+376320*y^-12-37632*y^-10+1568*y^-8)*x^3
3705
+ + (21102144*y^-20-18120592*y^-18+8028160*y^-16-2007040*y^-14+250880*y^-12-12544*y^-10)*x^4) dx/2y
3706
+ """
3707
+ try:
3708
+ from sage.misc.profiler import Profiler
3709
+ except ImportError:
3710
+ def prof():
3711
+ pass
3712
+ else:
3713
+ prof = Profiler()
3714
+ prof("setup")
3715
+ # TODO, would it be useful to be able to take Frobenius of any element? Less efficient?
3716
+ x, y = self.base_ring().gens()
3717
+ prof("x_to_p")
3718
+ x_to_p_less_1 = x**(p-1)
3719
+ x_to_p = x*x_to_p_less_1
3720
+
3721
+ # cache for future use
3722
+ self.x_to_p.set_cache(p, x_to_p)
3723
+
3724
+ prof("frob_Q")
3725
+ a = self.frob_Q(p) >> 2*p # frobQ * y^{-2p}
3726
+
3727
+ prof("sqrt")
3728
+
3729
+ # Q = self.base_ring()._Q
3730
+ # three_halves = Q.parent().base_ring()(Rational((3,2)))
3731
+ # one_half = Q.parent().base_ring()(Rational((1,2)))
3732
+ three_halves = self.base_ring()._series_ring.base_ring()(Rational((3, 2)))
3733
+ one_half = self.base_ring()._series_ring.base_ring()(Rational((1, 2)))
3734
+ half_a = a._rmul_(one_half)
3735
+
3736
+ # We are solving for t = a^{-1/2} = (F_pQ y^{-p})^{-1/2}
3737
+ # Newton's method converges because we know the root is in the same residue class as 1.
3738
+
3739
+ # t = self.base_ring()(1)
3740
+ t = self.base_ring()(three_halves) - half_a
3741
+ # first iteration trivial, start with prec 2
3742
+
3743
+ from sage.misc.misc import newton_method_sizes
3744
+
3745
+ for cur_prec in newton_method_sizes(prec)[2:]:
3746
+ # newton_method_sizes = [1, 2, ...]
3747
+ y_prec = -(2*cur_prec-1)*p+1
3748
+ # binomial expansion is $\sum p^{k+1} y^{-(2k+1)p+1} f(x)$
3749
+ # so if we are only correct mod p^prec,
3750
+ # can ignore y powers less than y_prec
3751
+ t_cube = (t*t*t).truncate_neg(y_prec)
3752
+ t = t._rmul_(three_halves) - (half_a * t_cube).truncate_neg(y_prec)
3753
+ # t = (3/2) t - (1/2) a t^3
3754
+
3755
+ prof("compose")
3756
+ F_dx_y = (p * x_to_p_less_1 * t) >> (p-1) # px^{p-1} sqrt(a) * y^{-p+1}
3757
+
3758
+ prof("done")
3759
+ return MonskyWashnitzerDifferential(self, F_dx_y)
3760
+
3761
+ def frob_basis_elements(self, prec, p):
3762
+ r"""
3763
+ Return the action of a `p`-power lift of Frobenius on the basis.
3764
+
3765
+ .. MATH::
3766
+
3767
+ \{ dx/2y, x dx/2y, ..., x^{d-2} dx/2y \},
3768
+
3769
+ where `d` is the degree of the underlying hyperelliptic curve.
3770
+
3771
+ EXAMPLES::
3772
+
3773
+ sage: R.<x> = QQ['x']
3774
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3775
+ sage: prec = 1
3776
+ sage: p = 5
3777
+ sage: MW = C.invariant_differential().parent()
3778
+ sage: MW.frob_basis_elements(prec, p)
3779
+ [((92000*y^-14-74200*y^-12+32000*y^-10-8000*y^-8+1000*y^-6-50*y^-4)*1
3780
+ - (194400*y^-14-153600*y^-12+57600*y^-10-9600*y^-8+600*y^-6)*x
3781
+ + (204800*y^-14-153600*y^-12+38400*y^-10-3200*y^-8)*x^2
3782
+ - (153600*y^-14-76800*y^-12+9600*y^-10)*x^3
3783
+ + (63950*y^-14-18550*y^-12+1600*y^-10-400*y^-8+50*y^-6+5*y^-4)*x^4) dx/2y,
3784
+ (-(1391200*y^-14-941400*y^-12+302000*y^-10-76800*y^-8+14400*y^-6-1320*y^-4+30*y^-2)*1
3785
+ + (2168800*y^-14-1402400*y^-12+537600*y^-10-134400*y^-8+16800*y^-6-720*y^-4)*x
3786
+ - (1596800*y^-14-1433600*y^-12+537600*y^-10-89600*y^-8+5600*y^-6)*x^2
3787
+ + (1433600*y^-14-1075200*y^-12+268800*y^-10-22400*y^-8)*x^3
3788
+ - (870200*y^-14-445350*y^-12+63350*y^-10-3200*y^-8+600*y^-6-30*y^-4-5*y^-2)*x^4) dx/2y,
3789
+ ((19488000*y^-14-15763200*y^-12+4944400*y^-10-913800*y^-8+156800*y^-6-22560*y^-4+1480*y^-2-10)*1
3790
+ - (28163200*y^-14-18669600*y^-12+5774400*y^-10-1433600*y^-8+268800*y^-6-25440*y^-4+760*y^-2)*x
3791
+ + (15062400*y^-14-12940800*y^-12+5734400*y^-10-1433600*y^-8+179200*y^-6-8480*y^-4)*x^2
3792
+ - (12121600*y^-14-11468800*y^-12+4300800*y^-10-716800*y^-8+44800*y^-6)*x^3
3793
+ + (9215200*y^-14-6952400*y^-12+1773950*y^-10-165750*y^-8+5600*y^-6-720*y^-4+10*y^-2+5)*x^4) dx/2y,
3794
+ (-(225395200*y^-14-230640000*y^-12+91733600*y^-10-18347400*y^-8+2293600*y^-6-280960*y^-4+31520*y^-2-1480-10*y^2)*1
3795
+ + (338048000*y^-14-277132800*y^-12+89928000*y^-10-17816000*y^-8+3225600*y^-6-472320*y^-4+34560*y^-2-720)*x
3796
+ - (172902400*y^-14-141504000*y^-12+58976000*y^-10-17203200*y^-8+3225600*y^-6-314880*y^-4+11520*y^-2)*x^2
3797
+ + (108736000*y^-14-109760000*y^-12+51609600*y^-10-12902400*y^-8+1612800*y^-6-78720*y^-4)*x^3
3798
+ - (85347200*y^-14-82900000*y^-12+31251400*y^-10-5304150*y^-8+367350*y^-6-8480*y^-4+760*y^-2+10-5*y^2)*x^4) dx/2y]
3799
+ """
3800
+ F_i = self.frob_invariant_differential(prec, p)
3801
+ x_to_p = self.x_to_p(p)
3802
+ F = [F_i]
3803
+ for i in range(1, self.degree()-1):
3804
+ F_i *= x_to_p
3805
+ F.append(F_i)
3806
+ return F
3807
+
3808
+ @cached_method
3809
+ def helper_matrix(self):
3810
+ r"""
3811
+ We use this to solve for the linear combination of
3812
+ `x^i y^j` needed to clear all terms with `y^{j-1}`.
3813
+
3814
+ EXAMPLES::
3815
+
3816
+ sage: R.<x> = QQ['x']
3817
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3818
+ sage: MW = C.invariant_differential().parent()
3819
+ sage: MW.helper_matrix()
3820
+ [ 256/2101 320/2101 400/2101 500/2101 625/2101]
3821
+ [-625/8404 -64/2101 -80/2101 -100/2101 -125/2101]
3822
+ [-125/2101 -625/8404 -64/2101 -80/2101 -100/2101]
3823
+ [-100/2101 -125/2101 -625/8404 -64/2101 -80/2101]
3824
+ [ -80/2101 -100/2101 -125/2101 -625/8404 -64/2101]
3825
+ """
3826
+ # The smallest y term of (1/j) d(x^i y^j) is constant for all j.
3827
+ x, y = self.base_ring().gens()
3828
+ n = self.degree()
3829
+ L = [(y * x**i).diff().extract_pow_y(0) for i in range(n)]
3830
+ A = matrix(L).transpose()
3831
+ if A.base_ring() not in IntegralDomains():
3832
+ # must be using integer_mod or something to approximate ?
3833
+ return (~A.change_ring(QQ)).change_ring(A.base_ring())
3834
+
3835
+ return ~A
3836
+
3837
+ def _element_constructor_(self, val=0, offset=0):
3838
+ r"""
3839
+ Construct an element of ``self``.
3840
+
3841
+ INPUT:
3842
+
3843
+ - ``parent`` -- Monsky-Washnitzer differential ring (instance of class
3844
+ :class:`~MonskyWashnitzerDifferentialRing`
3845
+ - ``val`` -- element of the base ring, or list of coefficients
3846
+ - ``offset`` -- (default: 0) if nonzero, shift val by `y^\text{offset}`
3847
+
3848
+ EXAMPLES::
3849
+
3850
+ sage: R.<x> = QQ['x']
3851
+ sage: C = HyperellipticCurve(x^5 - 4*x + 4)
3852
+ sage: MW = C.invariant_differential().parent()
3853
+ sage: MW(3)
3854
+ 3*1 dx/2y
3855
+ """
3856
+ if isinstance(val, MonskyWashnitzerDifferential):
3857
+ val = val._coeff
3858
+ return self.element_class(self, val, offset)
3859
+
3860
+ Element = MonskyWashnitzerDifferential
3861
+
3862
+
3863
+ MonskyWashnitzerDifferentialRing_class = MonskyWashnitzerDifferentialRing