passagemath-schemes 10.6.47__cp312-cp312-macosx_13_0_arm64.whl

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