passagemath-pari 10.6.32__cp314-cp314-musllinux_1_2_x86_64.whl

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

Potentially problematic release.


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

Files changed (331) hide show
  1. PARIKernel/__init__.py +2 -0
  2. PARIKernel/__main__.py +5 -0
  3. PARIKernel/io.cpython-314-x86_64-linux-musl.so +0 -0
  4. PARIKernel/io.pxd +7 -0
  5. PARIKernel/io.pyx +84 -0
  6. PARIKernel/kernel.cpython-314-x86_64-linux-musl.so +0 -0
  7. PARIKernel/kernel.pyx +260 -0
  8. PARIKernel/paridecl.pxd +95 -0
  9. PARIKernel/svg.cpython-314-x86_64-linux-musl.so +0 -0
  10. PARIKernel/svg.pyx +52 -0
  11. cypari2/__init__.py +8 -0
  12. cypari2/auto_paridecl.pxd +1070 -0
  13. cypari2/closure.cpython-314-x86_64-linux-musl.so +0 -0
  14. cypari2/closure.pxd +5 -0
  15. cypari2/closure.pyx +246 -0
  16. cypari2/convert.cpython-314-x86_64-linux-musl.so +0 -0
  17. cypari2/convert.pxd +80 -0
  18. cypari2/convert.pyx +613 -0
  19. cypari2/custom_block.cpython-314-x86_64-linux-musl.so +0 -0
  20. cypari2/custom_block.pyx +30 -0
  21. cypari2/cypari.h +13 -0
  22. cypari2/gen.cpython-314-x86_64-linux-musl.so +0 -0
  23. cypari2/gen.pxd +69 -0
  24. cypari2/gen.pyx +4819 -0
  25. cypari2/handle_error.cpython-314-x86_64-linux-musl.so +0 -0
  26. cypari2/handle_error.pxd +7 -0
  27. cypari2/handle_error.pyx +232 -0
  28. cypari2/pari_instance.cpython-314-x86_64-linux-musl.so +0 -0
  29. cypari2/pari_instance.pxd +27 -0
  30. cypari2/pari_instance.pyx +1438 -0
  31. cypari2/paridecl.pxd +5353 -0
  32. cypari2/paripriv.pxd +34 -0
  33. cypari2/pycore_long.h +98 -0
  34. cypari2/pycore_long.pxd +9 -0
  35. cypari2/stack.cpython-314-x86_64-linux-musl.so +0 -0
  36. cypari2/stack.pxd +27 -0
  37. cypari2/stack.pyx +278 -0
  38. cypari2/string_utils.cpython-314-x86_64-linux-musl.so +0 -0
  39. cypari2/string_utils.pxd +29 -0
  40. cypari2/string_utils.pyx +65 -0
  41. cypari2/types.pxd +147 -0
  42. passagemath_pari-10.6.32.data/data/etc/jupyter/nbconfig/notebook.d/gp-mode.json +5 -0
  43. passagemath_pari-10.6.32.data/data/share/jupyter/kernels/pari_jupyter/kernel.js +28 -0
  44. passagemath_pari-10.6.32.data/data/share/jupyter/kernels/pari_jupyter/kernel.json +6 -0
  45. passagemath_pari-10.6.32.data/data/share/jupyter/kernels/pari_jupyter/logo-64x64.png +0 -0
  46. passagemath_pari-10.6.32.data/data/share/jupyter/kernels/xeus-gp/kernel.json +13 -0
  47. passagemath_pari-10.6.32.data/data/share/jupyter/kernels/xeus-gp/logo-32x32.png +0 -0
  48. passagemath_pari-10.6.32.data/data/share/jupyter/kernels/xeus-gp/logo-64x64.png +0 -0
  49. passagemath_pari-10.6.32.data/data/share/jupyter/kernels/xeus-gp/logo-svg.svg +75 -0
  50. passagemath_pari-10.6.32.data/data/share/jupyter/nbextensions/gp-mode/gp.js +284 -0
  51. passagemath_pari-10.6.32.data/data/share/jupyter/nbextensions/gp-mode/main.js +15 -0
  52. passagemath_pari-10.6.32.dist-info/METADATA +209 -0
  53. passagemath_pari-10.6.32.dist-info/RECORD +331 -0
  54. passagemath_pari-10.6.32.dist-info/WHEEL +5 -0
  55. passagemath_pari-10.6.32.dist-info/top_level.txt +4 -0
  56. passagemath_pari.libs/libcrypto-f04afe95.so.3 +0 -0
  57. passagemath_pari.libs/libflint-fd6f12fc.so.21.0.0 +0 -0
  58. passagemath_pari.libs/libgcc_s-0cd532bd.so.1 +0 -0
  59. passagemath_pari.libs/libgf2x-9e30c3e3.so.3.0.0 +0 -0
  60. passagemath_pari.libs/libgfortran-2c33b284.so.5.0.0 +0 -0
  61. passagemath_pari.libs/libgivaro-9a94c711.so.9.2.1 +0 -0
  62. passagemath_pari.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
  63. passagemath_pari.libs/libgmpxx-9e08595c.so.4.7.0 +0 -0
  64. passagemath_pari.libs/libgsl-42cda06f.so.28.0.0 +0 -0
  65. passagemath_pari.libs/libmpfr-aaecbfc0.so.6.2.1 +0 -0
  66. passagemath_pari.libs/libncursesw-9c9e32c3.so.6.5 +0 -0
  67. passagemath_pari.libs/libntl-26885ca2.so.44.0.1 +0 -0
  68. passagemath_pari.libs/libopenblasp-r0-905cb27d.3.29.so +0 -0
  69. passagemath_pari.libs/libpari-gmp-tls-f31f908f.so.2.17.2 +0 -0
  70. passagemath_pari.libs/libquadmath-bb76a5fc.so.0.0.0 +0 -0
  71. passagemath_pari.libs/libreadline-06542304.so.8.2 +0 -0
  72. passagemath_pari.libs/libstdc++-5d72f927.so.6.0.33 +0 -0
  73. passagemath_pari.libs/libuuid-f3770415.so.1.3.0 +0 -0
  74. passagemath_pari.libs/libxeus-735780ff.so.13.1.0 +0 -0
  75. passagemath_pari.libs/libxeus-zmq-c68577b4.so.6.0.1 +0 -0
  76. passagemath_pari.libs/libzmq-1ba9a3da.so.5.2.5 +0 -0
  77. sage/all__sagemath_pari.py +26 -0
  78. sage/databases/all__sagemath_pari.py +7 -0
  79. sage/databases/conway.py +274 -0
  80. sage/ext/all__sagemath_pari.py +1 -0
  81. sage/ext/memory.cpython-314-x86_64-linux-musl.so +0 -0
  82. sage/ext/memory.pyx +98 -0
  83. sage/ext_data/pari/buzzard/DimensionSk.g +286 -0
  84. sage/ext_data/pari/buzzard/Tpprog.g +179 -0
  85. sage/ext_data/pari/buzzard/genusn.g +129 -0
  86. sage/ext_data/pari/dokchitser/computel.gp +740 -0
  87. sage/ext_data/pari/dokchitser/computel.gp.template +740 -0
  88. sage/ext_data/pari/dokchitser/ex-bsw +43 -0
  89. sage/ext_data/pari/dokchitser/ex-chgen +48 -0
  90. sage/ext_data/pari/dokchitser/ex-chqua +37 -0
  91. sage/ext_data/pari/dokchitser/ex-delta +35 -0
  92. sage/ext_data/pari/dokchitser/ex-eisen +30 -0
  93. sage/ext_data/pari/dokchitser/ex-gen2 +38 -0
  94. sage/ext_data/pari/dokchitser/ex-gen3 +49 -0
  95. sage/ext_data/pari/dokchitser/ex-gen4 +54 -0
  96. sage/ext_data/pari/dokchitser/ex-nf +48 -0
  97. sage/ext_data/pari/dokchitser/ex-shin +50 -0
  98. sage/ext_data/pari/dokchitser/ex-tau2 +30 -0
  99. sage/ext_data/pari/dokchitser/ex-zeta +27 -0
  100. sage/ext_data/pari/dokchitser/ex-zeta2 +47 -0
  101. sage/ext_data/pari/dokchitser/testall +13 -0
  102. sage/ext_data/pari/simon/ell.gp +2129 -0
  103. sage/ext_data/pari/simon/ellQ.gp +2151 -0
  104. sage/ext_data/pari/simon/ellcommon.gp +126 -0
  105. sage/ext_data/pari/simon/qfsolve.gp +722 -0
  106. sage/ext_data/pari/simon/resultant3.gp +306 -0
  107. sage/groups/all__sagemath_pari.py +3 -0
  108. sage/groups/pari_group.py +175 -0
  109. sage/interfaces/all__sagemath_pari.py +1 -0
  110. sage/interfaces/genus2reduction.py +464 -0
  111. sage/interfaces/gp.py +1114 -0
  112. sage/libs/all__sagemath_pari.py +2 -0
  113. sage/libs/linkages/__init__.py +1 -0
  114. sage/libs/linkages/padics/API.pxi +617 -0
  115. sage/libs/linkages/padics/Polynomial_ram.pxi +388 -0
  116. sage/libs/linkages/padics/Polynomial_shared.pxi +554 -0
  117. sage/libs/linkages/padics/__init__.py +1 -0
  118. sage/libs/linkages/padics/fmpz_poly_unram.pxi +869 -0
  119. sage/libs/linkages/padics/mpz.pxi +691 -0
  120. sage/libs/linkages/padics/relaxed/API.pxi +518 -0
  121. sage/libs/linkages/padics/relaxed/__init__.py +1 -0
  122. sage/libs/linkages/padics/relaxed/flint.pxi +543 -0
  123. sage/libs/linkages/padics/unram_shared.pxi +247 -0
  124. sage/libs/pari/__init__.py +210 -0
  125. sage/libs/pari/all.py +5 -0
  126. sage/libs/pari/convert_flint.cpython-314-x86_64-linux-musl.so +0 -0
  127. sage/libs/pari/convert_flint.pxd +14 -0
  128. sage/libs/pari/convert_flint.pyx +159 -0
  129. sage/libs/pari/convert_gmp.cpython-314-x86_64-linux-musl.so +0 -0
  130. sage/libs/pari/convert_gmp.pxd +14 -0
  131. sage/libs/pari/convert_gmp.pyx +210 -0
  132. sage/libs/pari/convert_sage.cpython-314-x86_64-linux-musl.so +0 -0
  133. sage/libs/pari/convert_sage.pxd +16 -0
  134. sage/libs/pari/convert_sage.pyx +588 -0
  135. sage/libs/pari/convert_sage_complex_double.cpython-314-x86_64-linux-musl.so +0 -0
  136. sage/libs/pari/convert_sage_complex_double.pxd +14 -0
  137. sage/libs/pari/convert_sage_complex_double.pyx +132 -0
  138. sage/libs/pari/convert_sage_matrix.cpython-314-x86_64-linux-musl.so +0 -0
  139. sage/libs/pari/convert_sage_matrix.pyx +106 -0
  140. sage/libs/pari/convert_sage_real_double.cpython-314-x86_64-linux-musl.so +0 -0
  141. sage/libs/pari/convert_sage_real_double.pxd +5 -0
  142. sage/libs/pari/convert_sage_real_double.pyx +14 -0
  143. sage/libs/pari/convert_sage_real_mpfr.cpython-314-x86_64-linux-musl.so +0 -0
  144. sage/libs/pari/convert_sage_real_mpfr.pxd +7 -0
  145. sage/libs/pari/convert_sage_real_mpfr.pyx +108 -0
  146. sage/libs/pari/misc.cpython-314-x86_64-linux-musl.so +0 -0
  147. sage/libs/pari/misc.pxd +4 -0
  148. sage/libs/pari/misc.pyx +26 -0
  149. sage/libs/pari/tests.py +1848 -0
  150. sage/matrix/all__sagemath_pari.py +1 -0
  151. sage/matrix/matrix_integer_pari.cpython-314-x86_64-linux-musl.so +0 -0
  152. sage/matrix/matrix_integer_pari.pyx +187 -0
  153. sage/matrix/matrix_rational_pari.cpython-314-x86_64-linux-musl.so +0 -0
  154. sage/matrix/matrix_rational_pari.pyx +160 -0
  155. sage/quadratic_forms/all__sagemath_pari.py +10 -0
  156. sage/quadratic_forms/genera/all.py +9 -0
  157. sage/quadratic_forms/genera/genus.py +3506 -0
  158. sage/quadratic_forms/genera/normal_form.py +1519 -0
  159. sage/quadratic_forms/genera/spinor_genus.py +243 -0
  160. sage/quadratic_forms/qfsolve.py +255 -0
  161. sage/quadratic_forms/quadratic_form__automorphisms.py +427 -0
  162. sage/quadratic_forms/quadratic_form__genus.py +141 -0
  163. sage/quadratic_forms/quadratic_form__local_density_interfaces.py +140 -0
  164. sage/quadratic_forms/quadratic_form__local_normal_form.py +421 -0
  165. sage/quadratic_forms/quadratic_form__local_representation_conditions.py +889 -0
  166. sage/quadratic_forms/quadratic_form__mass.py +69 -0
  167. sage/quadratic_forms/quadratic_form__mass__Conway_Sloane_masses.py +663 -0
  168. sage/quadratic_forms/quadratic_form__mass__Siegel_densities.py +373 -0
  169. sage/quadratic_forms/quadratic_form__siegel_product.py +198 -0
  170. sage/quadratic_forms/special_values.py +323 -0
  171. sage/rings/all__sagemath_pari.py +15 -0
  172. sage/rings/factorint_pari.cpython-314-x86_64-linux-musl.so +0 -0
  173. sage/rings/factorint_pari.pyx +80 -0
  174. sage/rings/finite_rings/all__sagemath_pari.py +1 -0
  175. sage/rings/finite_rings/element_givaro.cpython-314-x86_64-linux-musl.so +0 -0
  176. sage/rings/finite_rings/element_givaro.pxd +91 -0
  177. sage/rings/finite_rings/element_givaro.pyx +1769 -0
  178. sage/rings/finite_rings/element_ntl_gf2e.cpython-314-x86_64-linux-musl.so +0 -0
  179. sage/rings/finite_rings/element_ntl_gf2e.pxd +22 -0
  180. sage/rings/finite_rings/element_ntl_gf2e.pyx +1333 -0
  181. sage/rings/finite_rings/element_pari_ffelt.cpython-314-x86_64-linux-musl.so +0 -0
  182. sage/rings/finite_rings/element_pari_ffelt.pxd +13 -0
  183. sage/rings/finite_rings/element_pari_ffelt.pyx +1441 -0
  184. sage/rings/finite_rings/finite_field_givaro.py +612 -0
  185. sage/rings/finite_rings/finite_field_pari_ffelt.py +238 -0
  186. sage/rings/finite_rings/hom_finite_field_givaro.cpython-314-x86_64-linux-musl.so +0 -0
  187. sage/rings/finite_rings/hom_finite_field_givaro.pxd +28 -0
  188. sage/rings/finite_rings/hom_finite_field_givaro.pyx +280 -0
  189. sage/rings/finite_rings/residue_field_givaro.cpython-314-x86_64-linux-musl.so +0 -0
  190. sage/rings/finite_rings/residue_field_givaro.pyx +133 -0
  191. sage/rings/finite_rings/residue_field_pari_ffelt.cpython-314-x86_64-linux-musl.so +0 -0
  192. sage/rings/finite_rings/residue_field_pari_ffelt.pyx +128 -0
  193. sage/rings/function_field/all__sagemath_pari.py +1 -0
  194. sage/rings/function_field/valuation.py +1450 -0
  195. sage/rings/function_field/valuation_ring.py +212 -0
  196. sage/rings/number_field/all__sagemath_pari.py +14 -0
  197. sage/rings/number_field/totallyreal.cpython-314-x86_64-linux-musl.so +0 -0
  198. sage/rings/number_field/totallyreal.pyx +509 -0
  199. sage/rings/number_field/totallyreal_data.cpython-314-x86_64-linux-musl.so +0 -0
  200. sage/rings/number_field/totallyreal_data.pxd +26 -0
  201. sage/rings/number_field/totallyreal_data.pyx +928 -0
  202. sage/rings/number_field/totallyreal_phc.py +144 -0
  203. sage/rings/number_field/totallyreal_rel.py +1018 -0
  204. sage/rings/padics/CA_template.pxi +1847 -0
  205. sage/rings/padics/CA_template_header.pxi +50 -0
  206. sage/rings/padics/CR_template.pxi +2563 -0
  207. sage/rings/padics/CR_template_header.pxi +57 -0
  208. sage/rings/padics/FM_template.pxi +1575 -0
  209. sage/rings/padics/FM_template_header.pxi +50 -0
  210. sage/rings/padics/FP_template.pxi +2176 -0
  211. sage/rings/padics/FP_template_header.pxi +57 -0
  212. sage/rings/padics/all.py +3 -0
  213. sage/rings/padics/all__sagemath_pari.py +11 -0
  214. sage/rings/padics/common_conversion.cpython-314-x86_64-linux-musl.so +0 -0
  215. sage/rings/padics/common_conversion.pxd +15 -0
  216. sage/rings/padics/common_conversion.pyx +508 -0
  217. sage/rings/padics/eisenstein_extension_generic.py +232 -0
  218. sage/rings/padics/factory.py +3623 -0
  219. sage/rings/padics/generic_nodes.py +1615 -0
  220. sage/rings/padics/lattice_precision.py +2889 -0
  221. sage/rings/padics/morphism.cpython-314-x86_64-linux-musl.so +0 -0
  222. sage/rings/padics/morphism.pxd +11 -0
  223. sage/rings/padics/morphism.pyx +366 -0
  224. sage/rings/padics/padic_base_generic.py +467 -0
  225. sage/rings/padics/padic_base_leaves.py +1235 -0
  226. sage/rings/padics/padic_capped_absolute_element.cpython-314-x86_64-linux-musl.so +0 -0
  227. sage/rings/padics/padic_capped_absolute_element.pxd +15 -0
  228. sage/rings/padics/padic_capped_absolute_element.pyx +520 -0
  229. sage/rings/padics/padic_capped_relative_element.cpython-314-x86_64-linux-musl.so +0 -0
  230. sage/rings/padics/padic_capped_relative_element.pxd +14 -0
  231. sage/rings/padics/padic_capped_relative_element.pyx +614 -0
  232. sage/rings/padics/padic_extension_generic.py +990 -0
  233. sage/rings/padics/padic_extension_leaves.py +738 -0
  234. sage/rings/padics/padic_fixed_mod_element.cpython-314-x86_64-linux-musl.so +0 -0
  235. sage/rings/padics/padic_fixed_mod_element.pxd +15 -0
  236. sage/rings/padics/padic_fixed_mod_element.pyx +584 -0
  237. sage/rings/padics/padic_floating_point_element.cpython-314-x86_64-linux-musl.so +0 -0
  238. sage/rings/padics/padic_floating_point_element.pxd +14 -0
  239. sage/rings/padics/padic_floating_point_element.pyx +447 -0
  240. sage/rings/padics/padic_generic_element.cpython-314-x86_64-linux-musl.so +0 -0
  241. sage/rings/padics/padic_generic_element.pxd +48 -0
  242. sage/rings/padics/padic_generic_element.pyx +4642 -0
  243. sage/rings/padics/padic_lattice_element.py +1342 -0
  244. sage/rings/padics/padic_printing.cpython-314-x86_64-linux-musl.so +0 -0
  245. sage/rings/padics/padic_printing.pxd +38 -0
  246. sage/rings/padics/padic_printing.pyx +1505 -0
  247. sage/rings/padics/padic_relaxed_element.cpython-314-x86_64-linux-musl.so +0 -0
  248. sage/rings/padics/padic_relaxed_element.pxd +56 -0
  249. sage/rings/padics/padic_relaxed_element.pyx +18 -0
  250. sage/rings/padics/padic_relaxed_errors.cpython-314-x86_64-linux-musl.so +0 -0
  251. sage/rings/padics/padic_relaxed_errors.pxd +11 -0
  252. sage/rings/padics/padic_relaxed_errors.pyx +71 -0
  253. sage/rings/padics/padic_template_element.pxi +1212 -0
  254. sage/rings/padics/padic_template_element_header.pxi +50 -0
  255. sage/rings/padics/padic_valuation.py +1423 -0
  256. sage/rings/padics/pow_computer_flint.cpython-314-x86_64-linux-musl.so +0 -0
  257. sage/rings/padics/pow_computer_flint.pxd +38 -0
  258. sage/rings/padics/pow_computer_flint.pyx +641 -0
  259. sage/rings/padics/pow_computer_relative.cpython-314-x86_64-linux-musl.so +0 -0
  260. sage/rings/padics/pow_computer_relative.pxd +29 -0
  261. sage/rings/padics/pow_computer_relative.pyx +415 -0
  262. sage/rings/padics/qadic_flint_CA.cpython-314-x86_64-linux-musl.so +0 -0
  263. sage/rings/padics/qadic_flint_CA.pxd +21 -0
  264. sage/rings/padics/qadic_flint_CA.pyx +130 -0
  265. sage/rings/padics/qadic_flint_CR.cpython-314-x86_64-linux-musl.so +0 -0
  266. sage/rings/padics/qadic_flint_CR.pxd +13 -0
  267. sage/rings/padics/qadic_flint_CR.pyx +172 -0
  268. sage/rings/padics/qadic_flint_FM.cpython-314-x86_64-linux-musl.so +0 -0
  269. sage/rings/padics/qadic_flint_FM.pxd +14 -0
  270. sage/rings/padics/qadic_flint_FM.pyx +111 -0
  271. sage/rings/padics/qadic_flint_FP.cpython-314-x86_64-linux-musl.so +0 -0
  272. sage/rings/padics/qadic_flint_FP.pxd +12 -0
  273. sage/rings/padics/qadic_flint_FP.pyx +165 -0
  274. sage/rings/padics/relative_extension_leaves.py +429 -0
  275. sage/rings/padics/relative_ramified_CA.cpython-314-x86_64-linux-musl.so +0 -0
  276. sage/rings/padics/relative_ramified_CA.pxd +9 -0
  277. sage/rings/padics/relative_ramified_CA.pyx +33 -0
  278. sage/rings/padics/relative_ramified_CR.cpython-314-x86_64-linux-musl.so +0 -0
  279. sage/rings/padics/relative_ramified_CR.pxd +8 -0
  280. sage/rings/padics/relative_ramified_CR.pyx +33 -0
  281. sage/rings/padics/relative_ramified_FM.cpython-314-x86_64-linux-musl.so +0 -0
  282. sage/rings/padics/relative_ramified_FM.pxd +9 -0
  283. sage/rings/padics/relative_ramified_FM.pyx +33 -0
  284. sage/rings/padics/relative_ramified_FP.cpython-314-x86_64-linux-musl.so +0 -0
  285. sage/rings/padics/relative_ramified_FP.pxd +8 -0
  286. sage/rings/padics/relative_ramified_FP.pyx +33 -0
  287. sage/rings/padics/relaxed_template.pxi +4229 -0
  288. sage/rings/padics/relaxed_template_header.pxi +160 -0
  289. sage/rings/padics/tests.py +35 -0
  290. sage/rings/padics/tutorial.py +341 -0
  291. sage/rings/padics/unramified_extension_generic.py +335 -0
  292. sage/rings/padics/witt_vector.py +917 -0
  293. sage/rings/padics/witt_vector_ring.py +934 -0
  294. sage/rings/pari_ring.py +235 -0
  295. sage/rings/polynomial/all__sagemath_pari.py +1 -0
  296. sage/rings/polynomial/padics/all.py +1 -0
  297. sage/rings/polynomial/padics/polynomial_padic.py +360 -0
  298. sage/rings/polynomial/padics/polynomial_padic_capped_relative_dense.py +1324 -0
  299. sage/rings/polynomial/padics/polynomial_padic_flat.py +72 -0
  300. sage/rings/power_series_pari.cpython-314-x86_64-linux-musl.so +0 -0
  301. sage/rings/power_series_pari.pxd +6 -0
  302. sage/rings/power_series_pari.pyx +934 -0
  303. sage/rings/tate_algebra.py +1282 -0
  304. sage/rings/tate_algebra_element.cpython-314-x86_64-linux-musl.so +0 -0
  305. sage/rings/tate_algebra_element.pxd +49 -0
  306. sage/rings/tate_algebra_element.pyx +3464 -0
  307. sage/rings/tate_algebra_ideal.cpython-314-x86_64-linux-musl.so +0 -0
  308. sage/rings/tate_algebra_ideal.pxd +7 -0
  309. sage/rings/tate_algebra_ideal.pyx +1307 -0
  310. sage/rings/valuation/all.py +7 -0
  311. sage/rings/valuation/augmented_valuation.py +2118 -0
  312. sage/rings/valuation/developing_valuation.py +362 -0
  313. sage/rings/valuation/gauss_valuation.py +812 -0
  314. sage/rings/valuation/inductive_valuation.py +1686 -0
  315. sage/rings/valuation/limit_valuation.py +946 -0
  316. sage/rings/valuation/mapped_valuation.py +656 -0
  317. sage/rings/valuation/scaled_valuation.py +322 -0
  318. sage/rings/valuation/trivial_valuation.py +382 -0
  319. sage/rings/valuation/valuation.py +1119 -0
  320. sage/rings/valuation/valuation_space.py +1615 -0
  321. sage/rings/valuation/valuations_catalog.py +10 -0
  322. sage/rings/valuation/value_group.py +697 -0
  323. sage/schemes/all__sagemath_pari.py +1 -0
  324. sage/schemes/elliptic_curves/all__sagemath_pari.py +1 -0
  325. sage/schemes/elliptic_curves/descent_two_isogeny_pari.cpython-314-x86_64-linux-musl.so +0 -0
  326. sage/schemes/elliptic_curves/descent_two_isogeny_pari.pyx +46 -0
  327. sage_wheels/bin/gp +0 -0
  328. sage_wheels/bin/gp2c +0 -0
  329. sage_wheels/bin/gp2c-run +57 -0
  330. sage_wheels/bin/xeus-gp +0 -0
  331. sage_wheels/share/gp2c/func.dsc +18414 -0
@@ -0,0 +1,2889 @@
1
+ # sage_setup: distribution = sagemath-pari
2
+ r"""
3
+ Lattice precision for the parents ``ZpLC``/``QpLC`` and ``ZpLF``/``QpLF``
4
+
5
+ AUTHOR:
6
+
7
+ - Xavier Caruso (2018-02): initial version
8
+
9
+ TESTS::
10
+
11
+ sage: R = ZpLC(2)
12
+ doctest:...: FutureWarning: This class/method/function is marked as experimental. It, its functionality or its interface might change without a formal deprecation.
13
+ See https://github.com/sagemath/sage/issues/23505 for details.
14
+ sage: prec = R.precision()
15
+ sage: prec
16
+ Precision lattice on 0 objects
17
+
18
+ sage: S = ZpLF(2)
19
+ sage: prec = S.precision()
20
+ sage: prec
21
+ Precision module on 0 objects
22
+ """
23
+
24
+ # ****************************************************************************
25
+ # Copyright (C) 2018 Xavier Caruso <xavier.caruso@normalesup.org>
26
+ #
27
+ # This program is free software: you can redistribute it and/or modify
28
+ # it under the terms of the GNU General Public License as published by
29
+ # the Free Software Foundation, either version 2 of the License, or
30
+ # (at your option) any later version.
31
+ # https://www.gnu.org/licenses/
32
+ # ****************************************************************************
33
+
34
+ from collections import defaultdict
35
+
36
+ from sage.misc.timing import walltime
37
+
38
+ from sage.structure.sage_object import SageObject
39
+ from sage.structure.unique_representation import UniqueRepresentation
40
+ from sage.misc.abstract_method import abstract_method
41
+ from sage.misc.cachefunc import cached_method
42
+
43
+ from sage.rings.integer_ring import ZZ
44
+ from sage.rings.rational_field import QQ
45
+ from sage.rings.infinity import Infinity
46
+
47
+ from sage.rings.padics.precision_error import PrecisionError
48
+
49
+
50
+ # The default minimal size after which re-echelonization is not performed,
51
+ # i.e., when a variable is not referenced anymore and could be deleted but its
52
+ # corresponding column is further than this threshold from the right end of the
53
+ # matrix representing the precision lattice, then the column is not removed
54
+ # from the matrix because the re-echelonization would be too costly.
55
+ DEFAULT_THRESHOLD_DELETION = 50
56
+
57
+ # The number of additional digits used for internal computations
58
+ STARTING_ADDITIONAL_PREC = 5
59
+
60
+
61
+ class pRational:
62
+ r"""
63
+ This class implements rational numbers viewed as elements of ``Qp``.
64
+ In particular, it provides additional methods which are specific to
65
+ `p`-adics (as `p`-adic valuation).
66
+
67
+ Only for internal use.
68
+
69
+ INPUT:
70
+
71
+ - ``p`` -- a prime number
72
+
73
+ - ``x`` -- a rational number
74
+
75
+ - ``exponent`` -- integer (default: 0)
76
+
77
+ - ``valuation`` -- integer or ``None`` (default: ``None``);
78
+ the `p`-adic valuation of this element
79
+
80
+ If not ``None``, this method trusts the given value to the
81
+ attribute ``valuation``.
82
+
83
+ TESTS::
84
+
85
+ sage: from sage.rings.padics.lattice_precision import pRational
86
+ sage: x = pRational(2, 5); x
87
+ 5
88
+ sage: y = pRational(2, 5/3, 2); y
89
+ 2^2 * 5/3
90
+
91
+ sage: x + y
92
+ 35/3
93
+ sage: x - y
94
+ -5/3
95
+ sage: x * y
96
+ 2^2 * 25/3
97
+ sage: x / y
98
+ 2^-2 * 3
99
+
100
+ sage: x.valuation()
101
+ 0
102
+ sage: y.valuation()
103
+ 2
104
+
105
+ sage: z = pRational(2, 1024, valuation=4)
106
+ sage: z
107
+ 1024
108
+ sage: z.valuation()
109
+ 4
110
+ """
111
+ def __init__(self, p, x, exponent=0, valuation=None):
112
+ r"""
113
+ Construct the element ``x * p^exponent``.
114
+
115
+ TESTS::
116
+
117
+ sage: from sage.rings.padics.lattice_precision import pRational
118
+ sage: pRational(2, 5)
119
+ 5
120
+ sage: pRational(2, 5/3, 2)
121
+ 2^2 * 5/3
122
+ """
123
+ self.p = p
124
+ if x in ZZ:
125
+ self.x = ZZ(x)
126
+ else:
127
+ self.x = x
128
+ self.exponent = exponent
129
+ self._valuation = valuation
130
+
131
+ def __repr__(self):
132
+ r"""
133
+ Return a string representation of this element.
134
+
135
+ TESTS::
136
+
137
+ sage: from sage.rings.padics.lattice_precision import pRational
138
+ sage: pRational(2, 5, 2) # indirect doctest
139
+ 2^2 * 5
140
+ """
141
+ if self.exponent == 0:
142
+ return repr(self.x)
143
+ else:
144
+ return "%s^%s * %s" % (self.p, self.exponent, self.x)
145
+
146
+ def reduce(self, prec):
147
+ r"""
148
+ Return this element reduced modulo ``p^prec``.
149
+
150
+ INPUT:
151
+
152
+ - ``prec`` -- integer
153
+
154
+ TESTS::
155
+
156
+ sage: from sage.rings.padics.lattice_precision import pRational
157
+ sage: x = pRational(2, 1234567); x
158
+ 1234567
159
+ sage: x.reduce(12)
160
+ 1671
161
+
162
+ sage: x = pRational(2, 1234/567); x
163
+ 1234/567
164
+ sage: x.reduce(12)
165
+ 190
166
+ """
167
+ if prec is Infinity:
168
+ return self
169
+ x = self.x
170
+ exp = self.exponent
171
+ if x.parent() is ZZ:
172
+ if prec > exp:
173
+ x = x % (self.p ** (prec-exp))
174
+ else:
175
+ x = 0
176
+ elif x.parent() is QQ:
177
+ num = x.numerator()
178
+ denom = x.denominator()
179
+ valdenom = denom.valuation(self.p)
180
+ denom //= self.p ** valdenom
181
+ exp -= valdenom
182
+ if prec > exp:
183
+ modulo = self.p ** (prec - exp)
184
+ # probably we should use Newton iteration instead
185
+ # (but it is actually slower for now - Python implementation)
186
+ _, inv, _ = denom.xgcd(modulo)
187
+ x = (num*inv) % modulo
188
+ else:
189
+ x = 0
190
+ if self.x == 0:
191
+ val = Infinity
192
+ else:
193
+ val = self._valuation
194
+ return self.__class__(self.p, x, exp, valuation=val)
195
+
196
+ def reduce_relative(self, prec):
197
+ r"""
198
+ Return this element reduced modulo ``p^n`` where ``n = prec + val(x)``.
199
+
200
+ INPUT:
201
+
202
+ - ``prec`` -- nonnegative integer
203
+
204
+ TESTS::
205
+
206
+ sage: from sage.rings.padics.lattice_precision import pRational
207
+ sage: x = pRational(2, 1234567); x
208
+ 1234567
209
+ sage: x.reduce_relative(12)
210
+ 1671
211
+
212
+ sage: x = pRational(2, 1234/567); x
213
+ 1234/567
214
+ sage: x.reduce_relative(12)
215
+ 190
216
+ """
217
+ v = self.valuation()
218
+ if v is Infinity:
219
+ return self
220
+ return self.reduce(prec+v)
221
+
222
+ def normalize(self):
223
+ r"""
224
+ Normalize this element, i.e. write it as ``p^v * u`` where
225
+ ``u`` is coprime to `p`.
226
+
227
+ TESTS::
228
+
229
+ sage: from sage.rings.padics.lattice_precision import pRational
230
+ sage: x = pRational(2, 123456, 7); x
231
+ 2^7 * 123456
232
+ sage: x.normalize(); x
233
+ 2^13 * 1929
234
+ """
235
+ if self.x == 0:
236
+ self.exponent = 0
237
+ else:
238
+ val = self.valuation()
239
+ exp = self.exponent
240
+ self.x /= self.p ** (val-exp)
241
+ if self.x in ZZ:
242
+ self.x = ZZ(self.x)
243
+ self.exponent = val
244
+
245
+ def valuation(self):
246
+ r"""
247
+ Return the `p`-adic valuation of this element.
248
+
249
+ TESTS::
250
+
251
+ sage: from sage.rings.padics.lattice_precision import pRational
252
+ sage: x = pRational(2, 123456, 7); x
253
+ 2^7 * 123456
254
+ sage: x.valuation()
255
+ 13
256
+ """
257
+ if self._valuation is None:
258
+ valx = self.x.valuation(self.p)
259
+ self._valuation = self.exponent + valx
260
+ return self._valuation
261
+
262
+ def is_p_power(self):
263
+ r"""
264
+ Return ``True`` if this element is a power of `p`.
265
+
266
+ TESTS::
267
+
268
+ sage: from sage.rings.padics.lattice_precision import pRational
269
+ sage: x = pRational(2, 1024, 2); x
270
+ 2^2 * 1024
271
+ sage: x.is_p_power()
272
+ True
273
+
274
+ sage: y = pRational(2, 123456, 7); y
275
+ 2^7 * 123456
276
+ sage: y.is_p_power()
277
+ False
278
+ """
279
+ self.normalize()
280
+ return self.x == 1
281
+
282
+ def is_zero(self):
283
+ r"""
284
+ Return ``True`` if this element vanishes.
285
+
286
+ TESTS::
287
+
288
+ sage: from sage.rings.padics.lattice_precision import pRational
289
+ sage: x = pRational(2, 123456, 7); x
290
+ 2^7 * 123456
291
+ sage: x.is_zero()
292
+ False
293
+
294
+ sage: (x-x).is_zero()
295
+ True
296
+ """
297
+ return self.x == 0
298
+
299
+ def __add__(self, other):
300
+ r"""
301
+ Return the sum of ``self`` and ``other``.
302
+
303
+ TESTS::
304
+
305
+ sage: from sage.rings.padics.lattice_precision import pRational
306
+ sage: x = pRational(2, 123456, 7); x
307
+ 2^7 * 123456
308
+ sage: y = pRational(2, 891011, 12); y
309
+ 2^12 * 891011
310
+ sage: x + y
311
+ 2^7 * 28635808
312
+ """
313
+ p = self.p
314
+ sexp = self.exponent
315
+ oexp = other.exponent
316
+ if sexp is Infinity:
317
+ return other
318
+ if oexp is Infinity:
319
+ return self
320
+ if self._valuation is None or other._valuation is None:
321
+ val = None
322
+ elif self._valuation < other._valuation:
323
+ val = self._valuation
324
+ elif self._valuation > other._valuation:
325
+ val = other._valuation
326
+ else:
327
+ val = None
328
+ if sexp < oexp:
329
+ return self.__class__(p, self.x + other.x * p**(oexp-sexp), sexp, valuation=val)
330
+ else:
331
+ return self.__class__(p, self.x * p**(sexp-oexp) + other.x, oexp, valuation=val)
332
+
333
+ def __sub__(self, other):
334
+ r"""
335
+ Return the subtraction of ``self`` by ``other``.
336
+
337
+ TESTS::
338
+
339
+ sage: from sage.rings.padics.lattice_precision import pRational
340
+ sage: x = pRational(2, 123456, 7); x
341
+ 2^7 * 123456
342
+ sage: y = pRational(2, 891011, 12); y
343
+ 2^12 * 891011
344
+ sage: x - y
345
+ 2^7 * -28388896
346
+ """
347
+ return self + (-other)
348
+
349
+ def __neg__(self):
350
+ r"""
351
+ Return the opposite of this element.
352
+
353
+ TESTS::
354
+
355
+ sage: from sage.rings.padics.lattice_precision import pRational
356
+ sage: x = pRational(2, 123456, 7); x
357
+ 2^7 * 123456
358
+ sage: -x
359
+ 2^7 * -123456
360
+ """
361
+ return self.__class__(self.p, -self.x, self.exponent, valuation=self._valuation)
362
+
363
+ def __mul__(self, other):
364
+ r"""
365
+ Return the product of ``self`` and ``other``.
366
+
367
+ TESTS::
368
+
369
+ sage: from sage.rings.padics.lattice_precision import pRational
370
+ sage: x = pRational(2, 123456, 7); x
371
+ 2^7 * 123456
372
+ sage: y = pRational(2, 891011, 12); y
373
+ 2^12 * 891011
374
+ sage: x * y
375
+ 2^19 * 110000654016
376
+ """
377
+ if self._valuation is None or other._valuation is None:
378
+ val = None
379
+ else:
380
+ val = self._valuation + other._valuation
381
+ return self.__class__(self.p, self.x * other.x, self.exponent + other.exponent, valuation=val)
382
+
383
+ def __truediv__(self, other):
384
+ r"""
385
+ Return the quotient of ``self`` by ``other``.
386
+
387
+ TESTS::
388
+
389
+ sage: from sage.rings.padics.lattice_precision import pRational
390
+ sage: x = pRational(2, 123456, 7); x
391
+ 2^7 * 123456
392
+ sage: y = pRational(2, 891011, 12); y
393
+ 2^12 * 891011
394
+ sage: x / y
395
+ 2^-5 * 123456/891011
396
+ """
397
+ if self._valuation is None or other._valuation is None:
398
+ val = None
399
+ else:
400
+ val = self._valuation - other._valuation
401
+ return self.__class__(self.p, self.x / other.x, self.exponent - other.exponent, valuation=val)
402
+
403
+ def _quo_rem(self, other):
404
+ """
405
+ Quotient with remainder.
406
+
407
+ Returns a pair `q`, `r` where `r` has the `p`-adic expansion of this element,
408
+ truncated at the valuation of other.
409
+
410
+ EXAMPLES::
411
+
412
+ sage: from sage.rings.padics.lattice_precision import pRational
413
+ sage: a = pRational(2, 123456, 3)
414
+ sage: b = pRational(2, 654321, 2)
415
+ sage: q,r = a._quo_rem(b); q, r
416
+ (2^7 * 643/218107, 0)
417
+ sage: q*b+r - a
418
+ 0
419
+ sage: q,r = b._quo_rem(a); q, r
420
+ (5111/1929, 2^2 * 113)
421
+ sage: q*a+r - b
422
+ 2^2 * 0
423
+ """
424
+ other.normalize()
425
+ ox = other.x
426
+ if ox == 0:
427
+ raise ZeroDivisionError
428
+ self.normalize()
429
+ oval = other.exponent
430
+ sx = self.x
431
+ sval = self.exponent
432
+ diff = sval - oval
433
+ if sx == 0:
434
+ return (self.__class__(self.p, 0, 0, valuation=Infinity),
435
+ self.__class__(self.p, 0, 0, valuation=Infinity))
436
+ elif sval >= oval:
437
+ return (self.__class__(self.p, sx / ox, diff, valuation=diff),
438
+ self.__class__(self.p, 0, 0, valuation=Infinity))
439
+ else:
440
+ pd = self.p**(-diff)
441
+ sred = sx % pd
442
+ return (self.__class__(self.p, (sx - sred)/(pd*ox), 0),
443
+ self.__class__(self.p, sred, sval, valuation=sval))
444
+
445
+ def __lshift__(self, n):
446
+ r"""
447
+ Return the product of this element by ``p^n``.
448
+
449
+ INPUT:
450
+
451
+ - ``n`` -- relative integer
452
+
453
+ TESTS::
454
+
455
+ sage: from sage.rings.padics.lattice_precision import pRational
456
+ sage: x = pRational(2, 123456, 7); x
457
+ 2^7 * 123456
458
+ sage: x << 10
459
+ 2^17 * 123456
460
+ """
461
+ if self._valuation is None:
462
+ val = None
463
+ else:
464
+ val = self._valuation + n
465
+ return self.__class__(self.p, self.x, self.exponent + n, valuation=val)
466
+
467
+ def __rshift__(self, n):
468
+ r"""
469
+ Return the quotient of this element by ``p^n``.
470
+
471
+ INPUT:
472
+
473
+ - ``n`` -- relative integer
474
+
475
+ TESTS::
476
+
477
+ sage: from sage.rings.padics.lattice_precision import pRational
478
+ sage: x = pRational(2, 123456, 7); x
479
+ 2^7 * 123456
480
+ sage: x >> 10
481
+ 2^-3 * 123456
482
+ """
483
+ return self << (-n)
484
+
485
+ def unit_part(self):
486
+ r"""
487
+ Return the unit part of this element, that is the part ``u``
488
+ in the writing ``u * p^v`` with ``u`` coprime to `p`.
489
+
490
+ TESTS::
491
+
492
+ sage: from sage.rings.padics.lattice_precision import pRational
493
+ sage: x = pRational(2, 123456, 7); x
494
+ 2^7 * 123456
495
+ sage: x.unit_part()
496
+ 1929
497
+ """
498
+ if self.is_zero():
499
+ raise ValueError("the unit part of zero is not defined")
500
+ p = self.p
501
+ val = self.valuation()
502
+ x = self.x / (p ** (val-self.exponent))
503
+ return self.__class__(p, x, 0, valuation=0)
504
+
505
+ def xgcd(self, other):
506
+ r"""
507
+ Return the gcd of ``self`` and ``other`` together with two
508
+ elements ``u`` and ``v`` such that ``u*self + v*other = gcd``.
509
+
510
+ The ``gcd`` is normalized so that it is a power of `p`.
511
+
512
+ TESTS::
513
+
514
+ sage: from sage.rings.padics.lattice_precision import pRational
515
+ sage: x = pRational(2, 123456, 7); x
516
+ 2^7 * 123456
517
+ sage: y = pRational(2, 891011, 12); y
518
+ 2^12 * 891011
519
+
520
+ sage: d, u, v = x.xgcd(y)
521
+ sage: d
522
+ 2^7 * 32
523
+ sage: d.normalize(); d
524
+ 2^12 * 1
525
+
526
+ sage: u*x + v*y
527
+ 2^7 * 32
528
+ """
529
+ p = self.p
530
+ sexp = self.exponent
531
+ oexp = other.exponent
532
+ if sexp < oexp:
533
+ a = ZZ(self.x)
534
+ b = ZZ(other.x * (p ** (oexp-sexp)))
535
+ exp = sexp
536
+ else:
537
+ a = ZZ(self.x * (p ** (sexp-oexp)))
538
+ b = ZZ(other.x)
539
+ exp = oexp
540
+ d, u, v = a.xgcd(b)
541
+ if self._valuation is None or other._valuation is None:
542
+ val = None
543
+ else:
544
+ val = min(self._valuation, other._valuation)
545
+ d = self.__class__(p, d, exp, valuation=val)
546
+ u = self.__class__(p, u)
547
+ v = self.__class__(p, v)
548
+ return d, u, v
549
+
550
+ def value(self):
551
+ r"""
552
+ Return this element as a rational number.
553
+
554
+ TESTS::
555
+
556
+ sage: from sage.rings.padics.lattice_precision import pRational
557
+ sage: x = pRational(2, 123456, 7); x
558
+ 2^7 * 123456
559
+ sage: x.value()
560
+ 15802368
561
+ """
562
+ return (self.p ** self.exponent) * self.x
563
+
564
+ def list(self, prec):
565
+ r"""
566
+ Return the list of the digits of this element (written in radix
567
+ `p`) up to position ``prec``.
568
+
569
+ The first zeros are omitted.
570
+
571
+ TESTS::
572
+
573
+ sage: from sage.rings.padics.lattice_precision import pRational
574
+ sage: x = pRational(2, 123456); x
575
+ 123456
576
+ sage: x.list(5)
577
+ []
578
+ sage: x.list(20)
579
+ [1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0]
580
+
581
+ sage: y = pRational(2, 123/456); y
582
+ 41/152
583
+ sage: y.list(10)
584
+ [1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1]
585
+
586
+ sage: z = pRational(2, 0)
587
+ sage: z.list(10)
588
+ []
589
+ sage: z.list(100)
590
+ []
591
+ """
592
+ if self.x not in ZZ:
593
+ self = self.reduce(prec)
594
+ val = self.valuation()
595
+ if val is Infinity:
596
+ return []
597
+ p = self.p
598
+ x = ZZ(self.x * p**(self.exponent - val))
599
+ l = []
600
+ for _ in range(val, prec):
601
+ x, digit = x.quo_rem(p)
602
+ l.append(digit)
603
+ return l
604
+
605
+
606
+ class DifferentialPrecisionGeneric(SageObject):
607
+ r"""
608
+ A generic class for precision objects obtained by automatic
609
+ differentiation.
610
+
611
+ INPUT:
612
+
613
+ - ``p`` -- a prime number
614
+
615
+ - ``label`` -- string; the label of the parents to which the elements
616
+ belong that are tracked by this precision module
617
+
618
+ .. NOTE::
619
+
620
+ This object is used internally by the parent ring. You should not
621
+ create instances of this class on your own.
622
+
623
+ EXAMPLES::
624
+
625
+ sage: R = ZpLC(2, label='init')
626
+ sage: R.precision()
627
+ Precision lattice on 0 objects (label: init)
628
+ """
629
+ def __init__(self, p, label):
630
+ r"""
631
+ TESTS::
632
+
633
+ sage: prec = ZpLC(2, label='init').precision()
634
+ sage: from sage.rings.padics.lattice_precision import DifferentialPrecisionGeneric
635
+ sage: isinstance(prec, DifferentialPrecisionGeneric)
636
+ True
637
+ """
638
+ self._p = p
639
+ self._label = label
640
+ self._elements = []
641
+
642
+ self._matrix = {}
643
+ # A dictionary whose keys are weak references to tracked
644
+ # elements and values corresponding columns in the matrix
645
+ # representing the precision lattice
646
+
647
+ self._collected_references = []
648
+ self._marked_for_deletion = []
649
+ self._approx_zero = pRational(p, ZZ.zero())
650
+ self._threshold_deletion = DEFAULT_THRESHOLD_DELETION
651
+ self._history_init = None
652
+ self._history = None
653
+
654
+ def __reduce__(self):
655
+ r"""
656
+ TESTS::
657
+
658
+ sage: R = ZpLF(2)
659
+ sage: prec = R.precision()
660
+ sage: dumps(prec)
661
+ Traceback (most recent call last):
662
+ ...
663
+ NotImplementedError: pickling/unpickling precision modules is not implemented yet
664
+ """
665
+ raise NotImplementedError("pickling/unpickling precision modules is not implemented yet")
666
+
667
+ def _repr_(self):
668
+ r"""
669
+ Return a string representation of this precision object.
670
+
671
+ EXAMPLES::
672
+
673
+ sage: R = ZpLC(2)
674
+ sage: R.precision()
675
+ Precision lattice on ... objects
676
+
677
+ If a label has been specified, it is included in the representation::
678
+
679
+ sage: R = ZpLC(2, label='mylabel')
680
+ sage: R.precision()
681
+ Precision lattice on 0 objects (label: mylabel)
682
+ """
683
+ label = "" if self._label is None else " (label: %s)" % (self._label,)
684
+ count = "1 object" if len(self._elements) == 1 else "%s objects" % len(self._elements)
685
+ return "%s on %s%s" % (self._repr_type, count, label)
686
+
687
+ def threshold_deletion(self, threshold=None):
688
+ r"""
689
+ Return (and set) the threshold for column deletion.
690
+
691
+ When a variable dies, i.e., goes out of scope, the ambient space in
692
+ which the precision module lives can be reduced (by projection onto the
693
+ hyperplane defined by the dead variable).
694
+ This reduction has a cost because it leads to re-echelonization
695
+ of a part of the matrix that encodes the precision. The size of this
696
+ part is roughly measured by the number of columns between the last
697
+ column and the one corresponding to the dead variable.
698
+
699
+ This threshold returned by this method is the maximal distance until
700
+ which a column of a dead variable is removed and the matrix
701
+ re-echelonized. Beyond the threshold, the column of the dead variable
702
+ is kept in this matrix as if the variable were not destroyed.
703
+
704
+ INPUT:
705
+
706
+ - ``threshold`` -- nonnegative integer, ``Infinity`` or ``None``
707
+ (default: ``None``); if not ``None`` set the threshold to the given
708
+ value.
709
+
710
+ .. NOTE::
711
+
712
+ Setting the threshold to ``0`` disables the dimension reduction.
713
+
714
+ Setting the threshold to ``Infinity`` forces the dimension reduction
715
+ after each deletion.
716
+
717
+ EXAMPLES::
718
+
719
+ sage: R = ZpLC(2, label='threshold_deletion')
720
+ sage: prec = R.precision()
721
+ sage: prec.threshold_deletion()
722
+ 50
723
+
724
+ sage: prec.threshold_deletion(20)
725
+ 20
726
+ sage: prec.threshold_deletion()
727
+ 20
728
+
729
+ sage: prec.threshold_deletion(-2)
730
+ Traceback (most recent call last):
731
+ ...
732
+ ValueError: The threshold must be a nonnegative integer or Infinity
733
+ """
734
+ if threshold is not None:
735
+ if threshold is Infinity or (threshold in ZZ and threshold >= 0):
736
+ self._threshold_deletion = threshold
737
+ else:
738
+ raise ValueError("The threshold must be a nonnegative integer or Infinity")
739
+ return self._threshold_deletion
740
+
741
+ def prime(self):
742
+ r"""
743
+ Return the underlying prime number attached to this precision lattice.
744
+
745
+ EXAMPLES::
746
+
747
+ sage: R = ZpLC(2, label='mylabel')
748
+ sage: R.precision().prime()
749
+ 2
750
+ """
751
+ return self._p
752
+
753
+ def _index(self, ref):
754
+ r"""
755
+ Return the index of the column in the precision matrix that
756
+ corresponds to ``ref``.
757
+
758
+ Only for internal use.
759
+
760
+ TESTS::
761
+
762
+ sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
763
+ sage: R = ZpLC(2, label='index')
764
+ sage: prec = R.precision()
765
+ sage: x = R(1, 10)
766
+ sage: y = R(1, 5)
767
+
768
+ sage: prec._index(pAdicLatticeElementWeakProxy(x))
769
+ 0
770
+ sage: prec._index(pAdicLatticeElementWeakProxy(y))
771
+ 1
772
+
773
+ sage: del x
774
+ sage: prec.del_elements()
775
+ sage: prec._index(pAdicLatticeElementWeakProxy(y))
776
+ 0
777
+ """
778
+ return self._elements.index(ref)
779
+
780
+ def ambient_dimension(self):
781
+ r"""
782
+ Return the dimension of the vector space in which the precision
783
+ module/lattice lives.
784
+
785
+ EXAMPLES::
786
+
787
+ sage: R = ZpLC(2, label='ambient_dim')
788
+ sage: prec = R.precision()
789
+
790
+ sage: x, y = R(1, 10), R(1, 5)
791
+ sage: prec.ambient_dimension()
792
+ 2
793
+ sage: prec.dimension()
794
+ 2
795
+
796
+ sage: u = x + y
797
+ sage: prec.ambient_dimension()
798
+ 3
799
+ sage: prec.dimension()
800
+ 3
801
+
802
+ In the case of ``ZpLC`` (lattice-cap precision), it is always
803
+ equal to the dimension of the lattice.
804
+
805
+ In the case of ``ZpLF`` (lattice-float precision), the precision
806
+ object is not necessarily a lattice and then may have smaller
807
+ dimension::
808
+
809
+ sage: R = ZpLF(2, label='ambient_dim')
810
+ sage: prec = R.precision()
811
+
812
+ sage: x, y = R(1, 10), R(1, 5)
813
+ sage: prec.ambient_dimension()
814
+ 2
815
+ sage: prec.dimension()
816
+ 2
817
+
818
+ sage: u = x + y
819
+ sage: prec.ambient_dimension()
820
+ 3
821
+ sage: prec.dimension()
822
+ 2
823
+ """
824
+ return len(self._matrix)
825
+
826
+ @abstract_method
827
+ def dimension(self):
828
+ r"""
829
+ Return the dimension of this precision module.
830
+
831
+ EXAMPLES::
832
+
833
+ sage: R = ZpLC(5, label='dim')
834
+ sage: prec = R.precision()
835
+ sage: prec.dimension()
836
+ 0
837
+
838
+ sage: x = R(1, 10)
839
+ sage: prec.dimension()
840
+ 1
841
+ """
842
+ pass
843
+
844
+ @abstract_method
845
+ def _new_element(self, *args, **kwargs):
846
+ r"""
847
+ Insert a new element in this precision module.
848
+
849
+ TESTS::
850
+
851
+ sage: R = ZpLC(2)
852
+ sage: x = R.random_element()
853
+ sage: y = R.random_element()
854
+ sage: z = x*y # indirect doctest
855
+ """
856
+ pass
857
+
858
+ def _record_collected_element(self, ref):
859
+ r"""
860
+ Record that the element with weak reference ``ref``
861
+ has been collected by the garbage collector.
862
+
863
+ INPUT:
864
+
865
+ - ``ref`` -- the weak reference of the collected element
866
+
867
+ TESTS::
868
+
869
+ sage: R = ZpLC(2, label='gc')
870
+ sage: prec = R.precision()
871
+
872
+ sage: x = R.random_element()
873
+ sage: prec._collected_references
874
+ []
875
+
876
+ sage: del x
877
+ sage: prec._collected_references
878
+ [WeakProxy#...]
879
+ """
880
+ self._collected_references.append(ref)
881
+
882
+ @abstract_method
883
+ def del_elements(self, threshold=None):
884
+ r"""
885
+ Delete (or mark for future deletion) the columns of precision
886
+ matrix corresponding to elements that were collected by the
887
+ garbage collector.
888
+
889
+ INPUT:
890
+
891
+ - ``threshold`` -- integer or ``None`` (default: ``None``);
892
+ a column whose distance to the right is greater than the
893
+ threshold is not erased but marked for deletion.
894
+ If ``None``, always erase (never mark for deletion).
895
+
896
+ EXAMPLES::
897
+
898
+ sage: R = ZpLC(2, label='del_elements')
899
+ sage: prec = R.precision()
900
+
901
+ sage: x = R(1, 10)
902
+ sage: prec
903
+ Precision lattice on 1 object (label: del_elements)
904
+ sage: prec.precision_lattice() # needs sage.geometry.polyhedron
905
+ [1024]
906
+
907
+ sage: del x
908
+ sage: prec
909
+ Precision lattice on 1 object (label: del_elements)
910
+ sage: prec.precision_lattice() # needs sage.geometry.polyhedron
911
+ [1024]
912
+
913
+ sage: prec.del_elements()
914
+ sage: prec
915
+ Precision lattice on 0 objects (label: del_elements)
916
+ sage: prec.precision_lattice() # needs sage.geometry.polyhedron
917
+ []
918
+ """
919
+ pass
920
+
921
+ @abstract_method
922
+ def _precision_absolute(self, x):
923
+ r"""
924
+ Return the absolute precision of the given element.
925
+
926
+ INPUT:
927
+
928
+ - ``x`` -- the element whose absolute precision is requested
929
+
930
+ .. NOTE::
931
+
932
+ The absolute precision is obtained by projecting the precision
933
+ lattice onto the line of coordinate ``dx``.
934
+
935
+ This function is not meant to be called directly. Call
936
+ ``x.precision_absolute()`` instead.
937
+
938
+ EXAMPLES::
939
+
940
+ sage: R = ZpLC(2)
941
+ sage: x = R(1, 10); x
942
+ 1 + O(2^10)
943
+ sage: y = R(1, 5); y
944
+ 1 + O(2^5)
945
+ sage: z = x + y; z
946
+ 2 + O(2^5)
947
+ sage: z.precision_absolute() # indirect doctest
948
+ 5
949
+ """
950
+ pass
951
+
952
+ @abstract_method
953
+ def precision_lattice(self, elements=None):
954
+ r"""
955
+ Return a lattice modeling the precision on the given set of elements
956
+ or, if not given, on the whole set of elements tracked by the precision
957
+ module.
958
+
959
+ INPUT:
960
+
961
+ - ``elements`` -- list of elements or ``None`` (default: ``None``)
962
+
963
+ EXAMPLES::
964
+
965
+ sage: R = ZpLC(2, label='precision_lattice')
966
+ sage: prec = R.precision()
967
+ sage: x = R(1, 10); y = R(1, 5)
968
+ sage: u = x + y
969
+ sage: v = x - y
970
+ sage: prec.precision_lattice() # needs sage.geometry.polyhedron
971
+ [ 1024 0 1024 1024]
972
+ [ 0 32 32 1099511627744]
973
+ [ 0 0 2097152 0]
974
+ [ 0 0 0 1099511627776]
975
+ sage: prec.precision_lattice([u, v]) # needs sage.geometry.polyhedron
976
+ [ 32 2016]
977
+ [ 0 2048]
978
+
979
+ If the precision module does not project to a lattice,
980
+ an error is raised. ::
981
+
982
+ sage: R = ZpLF(2, label='precision_lattice')
983
+ sage: prec = R.precision()
984
+ sage: x = R(1, 10); y = R(1, 5)
985
+ sage: u = x + y
986
+ sage: v = x - y
987
+ sage: prec.precision_lattice([x,y,u,v]) # needs sage.geometry.polyhedron
988
+ Traceback (most recent call last):
989
+ ...
990
+ PrecisionError: the differential is not surjective
991
+ """
992
+ pass
993
+
994
+ def diffused_digits(self, elements=None):
995
+ r"""
996
+ Return the number of diffused digits of precision within a
997
+ subset of elements.
998
+
999
+ A diffused digit of precision is a known digit which is not
1000
+ located on a single variable but only appears on a suitable
1001
+ linear combination of variables.
1002
+
1003
+ The number of diffused digits of precision quantifies the
1004
+ quality of the approximation of the lattice precision by a
1005
+ jagged precision (that is a precision which is split over
1006
+ all variables).
1007
+
1008
+ We refer to [CRV2018]_ for a detail exposition of the notion of
1009
+ diffused digits.
1010
+
1011
+ EXAMPLES::
1012
+
1013
+ sage: R = ZpLC(2)
1014
+ sage: prec = R.precision()
1015
+ sage: x = R(1, 10); y = R(1, 5)
1016
+ sage: u = x + y
1017
+ sage: v = x - y
1018
+
1019
+ sage: prec.diffused_digits([x, y]) # needs sage.geometry.polyhedron
1020
+ 0
1021
+ sage: prec.diffused_digits([u, v]) # needs sage.geometry.polyhedron
1022
+ 6
1023
+
1024
+ The elements `u` and `v` are known at absolute precision `O(2^5)`.
1025
+ However, the sum `u + v = 2x` is known at precision `O(2^11)`, that
1026
+ is with `6` more digits.
1027
+ That is where the `6` diffused digits of precision comes from.
1028
+
1029
+ Here is another example with matrices::
1030
+
1031
+ sage: M = matrix(R, 2, 2, [R(3, 5), R(7, 5), R(1, 5), R(11, 1)]) # needs sage.modules
1032
+ sage: N = M^10 # needs sage.modules
1033
+
1034
+ The next syntax provides as easy way to select an interesting
1035
+ subset of variables (the selected subset consists of the four
1036
+ entries of the matrix ``N``)::
1037
+
1038
+ sage: prec.diffused_digits(N) # needs sage.geometry.polyhedron sage.modules
1039
+ 17
1040
+
1041
+ Note that, in some cases, the number of diffused digits can be
1042
+ infinite::
1043
+
1044
+ sage: R = ZpLF(2)
1045
+ sage: prec = R.precision()
1046
+ sage: x = R(1, 10)
1047
+ sage: y = x
1048
+ sage: prec.diffused_digits([x, y]) # needs sage.geometry.polyhedron
1049
+ +Infinity
1050
+ """
1051
+ try:
1052
+ M = self.precision_lattice(elements)
1053
+ except PrecisionError:
1054
+ return Infinity
1055
+ n = M.nrows()
1056
+ p = self._p
1057
+ return sum(M[i, i].valuation(p) - min(M[j, i].valuation(p) for j in range(i + 1)) for i in range(n))
1058
+
1059
+ def tracked_elements(self, values=True, dead=True):
1060
+ r"""
1061
+ Return the list of tracked elements.
1062
+
1063
+ INPUT:
1064
+
1065
+ - ``values`` -- boolean (default: ``True``); if ``False``,
1066
+ the method returns a list of weak references on tracked
1067
+ elements instead
1068
+
1069
+ - ``dead`` -- boolean (default: ``True``); whether dead
1070
+ elements for which the corresponding column is still not
1071
+ erased should be listed or not
1072
+
1073
+ EXAMPLES::
1074
+
1075
+ sage: R = ZpLC(2, label='tracked')
1076
+ sage: prec = R.precision()
1077
+ sage: x = R(1, 10); y = R(1, 5)
1078
+ sage: prec.tracked_elements()
1079
+ [1 + O(2^10), 1 + O(2^5)]
1080
+ sage: prec.tracked_elements(values=False)
1081
+ [WeakProxy#...,
1082
+ WeakProxy#...,
1083
+ WeakProxy#...]
1084
+ sage: prec.tracked_elements(values=False, dead=False)
1085
+ [WeakProxy#...,
1086
+ WeakProxy#...]
1087
+
1088
+ sage: # needs sage.rings.padics
1089
+ sage: u = x + y
1090
+ sage: v = x - y
1091
+ sage: prec.tracked_elements()
1092
+ [1 + O(2^10), 1 + O(2^5), 2 + O(2^5), O(2^5)]
1093
+ sage: prec.tracked_elements(values=False)
1094
+ [WeakProxy#...,
1095
+ WeakProxy#...,
1096
+ WeakProxy#...,
1097
+ WeakProxy#...,
1098
+ WeakProxy#...]
1099
+ sage: del x; del y
1100
+ sage: prec.tracked_elements()
1101
+ [None, None, 2 + O(2^5), O(2^5), None]
1102
+ sage: prec.tracked_elements(values=False)
1103
+ [WeakProxy#...,
1104
+ WeakProxy#...,
1105
+ WeakProxy#...]
1106
+ """
1107
+ ret = [ ref for ref in self._elements if dead or ref() is not None]
1108
+ if values:
1109
+ ret = [ ref() for ref in ret ]
1110
+ return ret
1111
+
1112
+ # History
1113
+
1114
+ def history_enable(self):
1115
+ r"""
1116
+ Enable history.
1117
+
1118
+ We refer to the documentation of the method :meth:`history` for
1119
+ a complete documentation (including examples) about history.
1120
+
1121
+ TESTS::
1122
+
1123
+ sage: R = ZpLC(2, label='history_en')
1124
+ sage: prec = R.precision()
1125
+
1126
+ sage: print(prec.history()) # history is disabled by default
1127
+ Traceback (most recent call last):
1128
+ ...
1129
+ ValueError: History is not tracked
1130
+
1131
+ sage: prec.history_enable()
1132
+ sage: print(prec.history())
1133
+ Timings
1134
+ ---
1135
+
1136
+ .. SEEALSO::
1137
+
1138
+ :meth:`history`, :meth:`history_disable`, :meth:`history_clear`
1139
+ """
1140
+ if self._history is None:
1141
+ self._history_init = ( len(self._elements), list(self._marked_for_deletion) )
1142
+ self._history = [ ]
1143
+
1144
+ def history_disable(self):
1145
+ r"""
1146
+ Disable history.
1147
+
1148
+ We refer to the documentation of the method :meth:`history` for
1149
+ a complete documentation (including examples) about history.
1150
+
1151
+ TESTS::
1152
+
1153
+ sage: R = ZpLC(2, label='history_dis')
1154
+ sage: prec = R.precision()
1155
+
1156
+ sage: print(prec.history()) # history is disabled by default
1157
+ Traceback (most recent call last):
1158
+ ...
1159
+ ValueError: History is not tracked
1160
+
1161
+ sage: prec.history_enable()
1162
+ sage: print(prec.history())
1163
+ Timings
1164
+ ---
1165
+
1166
+ sage: prec.history_disable()
1167
+ sage: print(prec.history())
1168
+ Traceback (most recent call last):
1169
+ ...
1170
+ ValueError: History is not tracked
1171
+
1172
+ .. SEEALSO::
1173
+
1174
+ :meth:`history`, :meth:`history_enable`, :meth:`history_clear`
1175
+ """
1176
+ self._history = self._history_init = None
1177
+
1178
+ def history_clear(self):
1179
+ r"""
1180
+ Clear history.
1181
+
1182
+ We refer to the documentation of the method :meth:`history` for
1183
+ a complete documentation (including examples) about history.
1184
+
1185
+ TESTS::
1186
+
1187
+ sage: R = ZpLC(2, label='history_clear')
1188
+ sage: prec = R.precision()
1189
+ sage: prec.history_enable()
1190
+
1191
+ sage: x = R(1, 10); y = R(1, 5)
1192
+ sage: x, y = x+y, x-y
1193
+ sage: print(prec.history()) # somewhat random
1194
+ Timings
1195
+ 0.000213s oooo
1196
+
1197
+ When we clear history, only the last line is kept::
1198
+
1199
+ sage: prec.history_clear()
1200
+ sage: print(prec.history())
1201
+ Timings oooo
1202
+ --- oooo
1203
+
1204
+ sage: prec.del_elements()
1205
+
1206
+ sage: print(prec.history()) # somewhat random
1207
+ Timings oooo
1208
+ 0.000005s ~~oo
1209
+ 0.000285s oo
1210
+
1211
+ .. SEEALSO::
1212
+
1213
+ :meth:`history`, :meth:`history_enable`, :meth:`history_disable`
1214
+ """
1215
+ if self._history is None:
1216
+ raise ValueError("History is not tracked")
1217
+ self._history_init = ( len(self._elements), list(self._marked_for_deletion) )
1218
+ self._history = [ ]
1219
+
1220
+ def _format_history(self, time, status, timings):
1221
+ r"""
1222
+ Return a formatted output for the history.
1223
+
1224
+ This is a helper function for the method :meth:`history`.
1225
+
1226
+ TESTS::
1227
+
1228
+ sage: R = ZpLC(2, label='history_en')
1229
+ sage: prec = R.precision()
1230
+ sage: prec._format_history(1.23456789, ['o', 'o', 'o', 'o', 'o', 'o', '~', 'o', 'o'], true)
1231
+ '1.234568s oooooo~oo'
1232
+ sage: prec._format_history(1.23456789, ['o', 'o', 'o', 'o', 'o', 'o', '~', 'o', 'o'], false)
1233
+ 'oooooo~oo'
1234
+
1235
+ sage: prec._format_history(12.3456789, ['o', 'o', 'o', 'o', 'o', 'o', '~', 'o', 'o'], true)
1236
+ ' >= 10s oooooo~oo'
1237
+ sage: prec._format_history(10^(-10), ['o', 'o', 'o', 'o', 'o', 'o', '~', 'o', 'o'], true)
1238
+ ' --- oooooo~oo'
1239
+ sage: prec._format_history(-1, ['o', 'o', 'o', 'o', 'o', 'o', '~', 'o', 'o'], true)
1240
+ ' Timings oooooo~oo'
1241
+ """
1242
+ status = ''.join(status)
1243
+ if timings:
1244
+ if time < 0:
1245
+ s = " Timings "
1246
+ elif time < 0.000001:
1247
+ s = " --- "
1248
+ elif time >= 10:
1249
+ s = " >= 10s "
1250
+ else:
1251
+ s = "%.6fs" % time
1252
+ return s + " " + status
1253
+ else:
1254
+ return status
1255
+
1256
+ def history(self, compact=True, separate_reduce=False, timings=True, output_type='asciiart'):
1257
+ r"""
1258
+ Show history.
1259
+
1260
+ The history records creations and deletions of elements attached
1261
+ to this precision lattice, together with many timings.
1262
+
1263
+ INPUT:
1264
+
1265
+ - ``compact`` -- boolean (default: ``True``); if ``True``, all
1266
+ consecutive operations of the same type appear on a single row
1267
+
1268
+ - ``separate_reduce`` -- boolean (default: ``False``); specify
1269
+ whether partial/full Hermite reduction should be displayed
1270
+ separately
1271
+
1272
+ - ``timings`` -- boolean (default: ``True``); specify whether
1273
+ timings should be displayed
1274
+
1275
+ - ``output_type`` -- only ``asciiart`` is implemented for now
1276
+
1277
+ IMPORTANT NOTE:
1278
+
1279
+ History is disabled by default.
1280
+ It should then be enabled (through a call to the method :meth:`history_enable`)
1281
+ before use.
1282
+
1283
+ EXAMPLES::
1284
+
1285
+ sage: R = ZpLC(2, label='history_en')
1286
+ sage: prec = R.precision()
1287
+
1288
+ We first enable history::
1289
+
1290
+ sage: prec.history_enable()
1291
+
1292
+ At the beginning, the history is of course empty::
1293
+
1294
+ sage: print(prec.history())
1295
+ Timings
1296
+ ---
1297
+
1298
+ Now we start creating and deleting elements::
1299
+
1300
+ sage: L = [ R.random_element() for _ in range(20) ]
1301
+ sage: for p in range(20):
1302
+ ....: if is_prime(p): L[p] = None
1303
+ sage: prec.del_elements()
1304
+
1305
+ sage: print(prec.history()) # somewhat random
1306
+ Timings
1307
+ 0.001108s oooooooooooooooooooo
1308
+ 0.000009s oo~~o~o~ooo~o~ooo~o~
1309
+ 0.014250s oooooooooooo
1310
+
1311
+ The legend is the following:
1312
+
1313
+ - the symbol ``o`` represents a tracked element,
1314
+ - the symbol ``~`` represents an element which is marked for deletion.
1315
+
1316
+ On the history, we see:
1317
+
1318
+ - 1st line: twenty new elements were created
1319
+ (this corresponds to the affectation of the list ``L``);
1320
+ - 2nd line: elements at prime positions were marked for deletion
1321
+ (this corresponds to the ``for`` loop);
1322
+ - 3rd line: the above elements are indeed deleted
1323
+ (this corresponds to the call of the method :meth:`del_elements`.
1324
+
1325
+ Here are some variants::
1326
+
1327
+ sage: print(prec.history(timings=False))
1328
+ oooooooooooooooooooo
1329
+ oo~~o~o~ooo~o~ooo~o~
1330
+ oooooooooooo
1331
+
1332
+ sage: print(prec.history(separate_reduce=True)) # somewhat random
1333
+ Timings
1334
+ 0.001063s oooooooooooooooooooo
1335
+ 0.000014s oo~~o~o~ooo~o~ooo~o~
1336
+ 0.000798s oo~~o~o~ooo~ooooo
1337
+ 0.000233s oo~~o~o~ooo~orrrr
1338
+ 0.000824s oo~~o~o~oooooooo
1339
+ 0.000375s oo~~o~o~ooorrrrr
1340
+ 0.001724s oo~~o~ooooooooo
1341
+ 0.001020s oo~~o~orrrrrrrr
1342
+ 0.001989s oo~~oooooooooo
1343
+ 0.001303s oo~~orrrrrrrrr
1344
+ 0.002352s oo~oooooooooo
1345
+ 0.001632s oo~rrrrrrrrrr
1346
+ 0.002265s oooooooooooo
1347
+ 0.001630s oorrrrrrrrrr
1348
+ --- oooooooooooo
1349
+
1350
+ The symbol ``r`` represents a column of the precision matrix which is
1351
+ currently under partial Hermite reduction.
1352
+
1353
+ Timings for automatic reduction do not appear because they are included
1354
+ in the timings for deletion.
1355
+
1356
+ The symbol ``R`` is used to symbolize a column which is under full
1357
+ Hermite reduction. Note that full Hermite reduction are never performed
1358
+ automatically but needs to be called by hand::
1359
+
1360
+ sage: prec.reduce()
1361
+ sage: print(prec.history(separate_reduce=True)) # somewhat random
1362
+ Timings
1363
+ 0.001063s oooooooooooooooooooo
1364
+ 0.000014s oo~~o~o~ooo~o~ooo~o~
1365
+ 0.000798s oo~~o~o~ooo~ooooo
1366
+ 0.000233s oo~~o~o~ooo~orrrr
1367
+ 0.000824s oo~~o~o~oooooooo
1368
+ 0.000375s oo~~o~o~ooorrrrr
1369
+ 0.001724s oo~~o~ooooooooo
1370
+ 0.001020s oo~~o~orrrrrrrr
1371
+ 0.001989s oo~~oooooooooo
1372
+ 0.001303s oo~~orrrrrrrrr
1373
+ 0.002352s oo~oooooooooo
1374
+ 0.001632s oo~rrrrrrrrrr
1375
+ 0.002265s oooooooooooo
1376
+ 0.001630s oorrrrrrrrrr
1377
+ 0.001486s RRRRRRRRRRRR
1378
+ --- oooooooooooo
1379
+
1380
+ Here is a more common example with matrices::
1381
+
1382
+ sage: R = ZpLC(3)
1383
+ sage: prec = R.precision()
1384
+ sage: prec.history_enable()
1385
+ sage: M = random_matrix(R, 5) # needs sage.geometry.polyhedron
1386
+ sage: d = M.determinant() # needs sage.geometry.polyhedron
1387
+ sage: print(prec.history()) # somewhat random
1388
+ ---
1389
+ 0.004212s oooooooooooooooooooooooooooooooooooo
1390
+ 0.000003s oooooooooooooooooooooooooooooooooo~~
1391
+ 0.000010s oooooooooooooooooooooooooooooooooo
1392
+ 0.001560s ooooooooooooooooooooooooooooooooooooooooo
1393
+ 0.000004s ooooooooooooooooooooooooooooo~oooo~oooo~o
1394
+ 0.002168s oooooooooooooooooooooooooooooooooooooo
1395
+ 0.001787s ooooooooooooooooooooooooooooooooooooooooo
1396
+ 0.000004s oooooooooooooooooooooooooooooooooooooo~~o
1397
+ 0.000198s ooooooooooooooooooooooooooooooooooooooo
1398
+ 0.001152s ooooooooooooooooooooooooooooooooooooooooo
1399
+ 0.000005s ooooooooooooooooooooooooooooooooo~oooo~~o
1400
+ 0.000853s oooooooooooooooooooooooooooooooooooooo
1401
+ 0.000610s ooooooooooooooooooooooooooooooooooooooo
1402
+ [...]
1403
+ 0.003879s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
1404
+ 0.000006s oooooooooooooooooooooooooooooooooooooooooooooooooooo~~~~~
1405
+ 0.000036s oooooooooooooooooooooooooooooooooooooooooooooooooooo
1406
+ 0.006737s oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
1407
+ 0.000005s oooooooooooooooooooooooooooooooooooooooooooooooooooo~~~~~ooooo
1408
+ 0.002637s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
1409
+ 0.007118s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
1410
+ 0.000008s oooooooooooooooooooooooooooooooooooooooooooooooooooo~~~~o~~~~oooo
1411
+ 0.003504s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
1412
+ 0.005371s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
1413
+ 0.000006s ooooooooooooooooooooooooooooooooooooooooooooooooooooo~~~o~~~ooo
1414
+ 0.001858s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
1415
+ 0.003584s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
1416
+ 0.000004s oooooooooooooooooooooooooooooooooooooooooooooooooooooo~~o~~oo
1417
+ 0.000801s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
1418
+ 0.001916s ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
1419
+ 0.000022s ooooooooooooooooooooooooooooo~~~~~~~~~~~~~~~~~~~~~~oooo~o~o
1420
+ 0.014705s ooooooooooooooooooooooooooooooooooo
1421
+ 0.001292s ooooooooooooooooooooooooooooooooooooo
1422
+
1423
+ We observe that deleted variables appear mostly on the right.
1424
+ This is the so-called principal of temporal locality.
1425
+
1426
+ .. SEEALSO::
1427
+
1428
+ :meth:`history_enable`, :meth:`history_disable`, :meth:`history_clear`
1429
+ """
1430
+ if self._history is None:
1431
+ raise ValueError("History is not tracked")
1432
+ total_time = 0
1433
+ if output_type == 'asciiart':
1434
+ # Legend:
1435
+ # o : tracked element
1436
+ # ~ : element marked for deletion
1437
+ # r : partial reduction
1438
+ # R : full Hermite reduction
1439
+ (n, mark) = self._history_init
1440
+ status = n*['o']
1441
+ for index in mark:
1442
+ status[index] = '~'
1443
+ hist = [ self._format_history(-1, status, timings) ]
1444
+ oldevent = ''
1445
+ total_time = 0
1446
+ for (event, index, tme) in self._history:
1447
+ if event == 'partial reduce' or event == 'full reduce':
1448
+ if separate_reduce:
1449
+ if status:
1450
+ hist.append(self._format_history(total_time, status, timings))
1451
+ if event == 'partial reduce':
1452
+ code = 'r'
1453
+ else:
1454
+ code = 'R'
1455
+ status_red = status[:index] + (len(status) - index) * [code]
1456
+ hist.append(self._format_history(tme, status_red, timings))
1457
+ total_time = 0
1458
+ oldevent = ''
1459
+ else:
1460
+ total_time += tme
1461
+ continue
1462
+ if not compact or event != oldevent:
1463
+ if status:
1464
+ hist.append(self._format_history(total_time, status, timings))
1465
+ total_time = 0
1466
+ oldevent = event
1467
+ total_time += tme
1468
+ if event == 'add':
1469
+ if index is None:
1470
+ status.append('o')
1471
+ else:
1472
+ status = status[:index] + ['o'] + status[index:]
1473
+ elif event == 'mark':
1474
+ status[index] = '~'
1475
+ elif event == 'del':
1476
+ del status[index]
1477
+ if status or oldevent == '':
1478
+ hist.append(self._format_history(total_time, status, timings))
1479
+ return '\n'.join(hist)
1480
+ else:
1481
+ raise NotImplementedError
1482
+
1483
+ def timings(self, action=None):
1484
+ r"""
1485
+ Return cumulated timings (grouped by actions) since the last
1486
+ time history has been cleared.
1487
+
1488
+ INPUT:
1489
+
1490
+ - ``action`` -- ``None`` (default), ``'add'``, ``'mark'``, ``'del'``,
1491
+ ``'partial reduce'`` or ``'full reduce'``; if not ``None``, return the
1492
+ cumulated timing corresponding to this action; otherwise, return
1493
+ a dictionary
1494
+
1495
+ Here are the meanings of the keywords above:
1496
+
1497
+ - ``'add'``: time spent in adding new columns to the precision matrix
1498
+ (corresponding to the creation of new elements)
1499
+ - ``'mark'``: time spent in marking elements for deletion
1500
+ - ``'del'``: time spent in deleting columns of the precision matrix
1501
+ and re-echelonizing the matrix
1502
+ - ``'partial reduce'``: time spent in partial Hermite reduction
1503
+ - ``'full reduce'``: time spent in full Hermite reduction.
1504
+
1505
+ EXAMPLES::
1506
+
1507
+ sage: R = ZpLC(2, label='timings')
1508
+ sage: prec = R.precision()
1509
+ sage: prec.history_enable()
1510
+ sage: M = random_matrix(R, 5, 5) # needs sage.geometry.polyhedron
1511
+ sage: N = M^10 # needs sage.geometry.polyhedron
1512
+ sage: prec.timings() # somewhat random
1513
+ {'add': 1.0530245304107666,
1514
+ 'del': 0.24358701705932617,
1515
+ 'mark': 0.0013289451599121094,
1516
+ 'partial reduce': 0.21604204177856445
1517
+ 'full reduce': 0}
1518
+
1519
+ TESTS::
1520
+
1521
+ sage: prec.history_clear()
1522
+ sage: prec.timings()
1523
+ {'add': 0, 'del': 0, 'full reduce': 0, 'mark': 0, 'partial reduce': 0}
1524
+ """
1525
+ if self._history is None:
1526
+ raise ValueError("History is not tracked")
1527
+ tme_by_event = { 'add': 0, 'del': 0, 'mark': 0, 'partial reduce': 0, 'full reduce': 0 }
1528
+ for (event, _, tme) in self._history:
1529
+ tme_by_event[event] += tme
1530
+ if action is None:
1531
+ return tme_by_event
1532
+ if action in tme_by_event:
1533
+ return tme_by_event[action]
1534
+ else:
1535
+ raise ValueError("invalid event")
1536
+
1537
+
1538
+ class PrecisionLattice(UniqueRepresentation, DifferentialPrecisionGeneric):
1539
+ r"""
1540
+ A class for handling precision lattices which are used to
1541
+ track precision in the ZpLC model.
1542
+
1543
+ The precision lattice is stored as a triangular matrix whose
1544
+ rows are generators of the lattice.
1545
+
1546
+ INPUT:
1547
+
1548
+ - ``p`` -- a prime number
1549
+
1550
+ - ``label`` -- string; the label of the parents to which the elements
1551
+ tracked by this lattice belong
1552
+
1553
+ .. NOTE::
1554
+
1555
+ You should not create instances of this class directly. The precision
1556
+ lattice is automatically initialized at the creation of the parent.
1557
+
1558
+ EXAMPLES::
1559
+
1560
+ sage: R = ZpLC(2, label='init')
1561
+ sage: R.precision()
1562
+ Precision lattice on 0 objects (label: init)
1563
+ """
1564
+ def __init__(self, p, label):
1565
+ r"""
1566
+ TESTS::
1567
+
1568
+ sage: from sage.rings.padics.lattice_precision import PrecisionLattice
1569
+ sage: R = ZpLC(2)
1570
+ sage: isinstance(R.precision(), PrecisionLattice)
1571
+ True
1572
+ """
1573
+ DifferentialPrecisionGeneric.__init__(self, p, label)
1574
+ self._repr_type = "Precision lattice"
1575
+ self._capped = { }
1576
+
1577
+ # We need to copy this method.
1578
+ # Indeed otherwise it is inherited from UniqueRepresentation
1579
+ def __reduce__(self):
1580
+ r"""
1581
+ TESTS::
1582
+
1583
+ sage: R = ZpLC(2)
1584
+ sage: prec = R.precision()
1585
+ sage: dumps(prec)
1586
+ Traceback (most recent call last):
1587
+ ...
1588
+ NotImplementedError: pickling/unpickling precision modules is not implemented yet
1589
+ """
1590
+ raise NotImplementedError("pickling/unpickling precision modules is not implemented yet")
1591
+
1592
+ def _index(self, ref):
1593
+ r"""
1594
+ Return the index of the element whose reference is ``ref``.
1595
+
1596
+ TESTS::
1597
+
1598
+ sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
1599
+ sage: R = ZpLC(2, label='index')
1600
+ sage: prec = R.precision()
1601
+ sage: x = R(1, 10)
1602
+ sage: y = R(1, 5)
1603
+
1604
+ sage: prec._index(pAdicLatticeElementWeakProxy(x))
1605
+ 0
1606
+ sage: prec._index(pAdicLatticeElementWeakProxy(y))
1607
+ 1
1608
+
1609
+ sage: del x
1610
+ sage: prec.del_elements()
1611
+ sage: prec._index(pAdicLatticeElementWeakProxy(y))
1612
+ 0
1613
+ """
1614
+ return len(self._matrix[ref]) - 1
1615
+
1616
+ def dimension(self):
1617
+ r"""
1618
+ Return the dimension of this lattice.
1619
+
1620
+ EXAMPLES::
1621
+
1622
+ sage: R = ZpLC(5, label='dimension')
1623
+ sage: prec = R.precision()
1624
+ sage: prec.dimension()
1625
+ 0
1626
+
1627
+ sage: x = R(1, 10)
1628
+ sage: prec.dimension()
1629
+ 1
1630
+ """
1631
+ return len(self._matrix)
1632
+
1633
+ def reduce(self, index=0, partial=False):
1634
+ r"""
1635
+ Reduce the size of the entries above the diagonal of the precision matrix.
1636
+
1637
+ INPUT:
1638
+
1639
+ - ``index`` -- integer; the starting row for which the reduction
1640
+ is performed
1641
+
1642
+ - ``partial`` -- boolean (default: ``False``); specifying whether a
1643
+ partial or a full Hermite reduction should be performed
1644
+
1645
+ NOTE:
1646
+
1647
+ The partial reduction has cost `O(m^2)` where `m` is the number of
1648
+ rows that need to be reduced (that is the difference between the
1649
+ total number of rows and ``index``).
1650
+
1651
+ The full Hermite reduction has cost `O(m^3)`.
1652
+
1653
+ .. NOTE::
1654
+
1655
+ The software ensures that the precision lattice is always partially
1656
+ reduced. Calling the function manually with the argument
1657
+ ``partial=True`` should then just do nothing.
1658
+
1659
+ TESTS::
1660
+
1661
+ sage: R = ZpLC(2)
1662
+ sage: x = R.random_element()
1663
+ sage: del x
1664
+ sage: R.precision().del_elements() # indirect doctest
1665
+ """
1666
+ n = len(self._elements)
1667
+ if index >= n-1:
1668
+ return
1669
+ if partial:
1670
+ # Partial reduction
1671
+ # Cost: O(m^2) with m = n-index
1672
+ tme = walltime()
1673
+ diffval = (n-index) * [0]
1674
+ for j in range(n-1, index, -1):
1675
+ col = self._matrix[self._elements[j]]
1676
+ prec = col[j].valuation() - diffval[j-index]
1677
+ for i in range(index, j):
1678
+ col[i] = col[i].reduce(prec)
1679
+ col[i].normalize()
1680
+ dval = col[i].valuation() - prec
1681
+ diffval[i-index] = min(dval, diffval[i-index])
1682
+ # We update history
1683
+ if self._history is not None:
1684
+ self._history.append(('partial reduce', index, walltime(tme)))
1685
+ else:
1686
+ # Full Hermite reduction
1687
+ # Cost: O(m^3) with m = n-index
1688
+ tme = walltime()
1689
+ for j in range(index+1, n):
1690
+ # In what follows, we assume that col[j] is a power of p
1691
+ col = self._matrix[self._elements[j]]
1692
+ valpivot = col[j].valuation()
1693
+ for i in range(index, j):
1694
+ reduced = col[i].reduce(valpivot)
1695
+ scalar = (col[i] - reduced) >> valpivot
1696
+ if scalar.is_zero():
1697
+ continue
1698
+ col[i] = reduced
1699
+ col[i].normalize()
1700
+ for j2 in range(j+1, n):
1701
+ col2 = self._matrix[self._elements[j2]]
1702
+ col2[i] -= scalar*col2[i]
1703
+ col2[i].normalize()
1704
+ # We update history
1705
+ if self._history is not None:
1706
+ self._history.append(('full reduce', index, walltime(tme)))
1707
+
1708
+ def _new_element(self, x, dx, bigoh, dx_mode='linear_combination', capped=False):
1709
+ r"""
1710
+ Update the lattice when a new element is created.
1711
+
1712
+ This function is not meant to be called manually.
1713
+ It is automatically called by the parent when a new
1714
+ element is created.
1715
+
1716
+ INPUT:
1717
+
1718
+ - ``x`` -- the newly created element
1719
+
1720
+ - ``dx`` -- dictionary representing the differential of ``x``
1721
+
1722
+ - ``bigoh`` -- integer or ``None`` (default: ``None``); the
1723
+ bigoh to be added to the precision of ``x``; if ``None``, the
1724
+ default cap is used.
1725
+
1726
+ - ``dx_mode`` -- string; either ``linear_combination`` (the default)
1727
+ or ``values``
1728
+
1729
+ - ``capped`` -- boolean; whether this element has been capped
1730
+ according to the parent's cap
1731
+
1732
+ If ``dx_mode`` is ``linear_combination``, the dictionary ``dx``
1733
+ encodes the expression of the differential of ``x``.
1734
+ For example, if ``x`` was defined as ``x = y*z`` then:
1735
+
1736
+ .. MATH::
1737
+
1738
+ dx = y dz + z dy
1739
+
1740
+ and the corresponding dictionary is ``{z: y, y: z}`` (except
1741
+ that the keys are not the elements themselves but weak references
1742
+ to them).
1743
+
1744
+ If ``dx_mode`` is ``values``, the dictionary ``dx`` directly
1745
+ specifies the entries that have to be stored in the precision lattice.
1746
+ This mode is only used for multiple conversion between different
1747
+ parents (see :meth:`multiple_conversion`).
1748
+
1749
+ TESTS::
1750
+
1751
+ sage: R = ZpLC(2)
1752
+ sage: x = R.random_element()
1753
+ sage: y = R.random_element()
1754
+ sage: z = x*y # indirect doctest
1755
+ """
1756
+ # First we delete some elements marked for deletion
1757
+ self.del_elements(threshold=self._threshold_deletion)
1758
+
1759
+ # Then we add the new element
1760
+ tme = walltime()
1761
+ p = self._p
1762
+ n = len(self._elements)
1763
+ x_ref = pAdicLatticeElementWeakProxy(x, self._record_collected_element)
1764
+ self._elements.append(x_ref)
1765
+ col = n * [self._approx_zero]
1766
+ if dx_mode == 'linear_combination':
1767
+ for elt, scalar in dx:
1768
+ ref = pAdicLatticeElementWeakProxy(elt)
1769
+ if not isinstance(scalar, pRational):
1770
+ scalar = pRational(p, scalar)
1771
+ c = self._matrix[ref]
1772
+ for i in range(len(c)):
1773
+ col[i] += scalar * c[i]
1774
+ elif dx_mode == 'values':
1775
+ for elt, scalar in dx:
1776
+ ref = pAdicLatticeElementWeakProxy(elt)
1777
+ if not isinstance(scalar, pRational):
1778
+ scalar = pRational(p, scalar)
1779
+ i = self._index(ref)
1780
+ col[i] = scalar
1781
+ else:
1782
+ raise ValueError("dx_mode must be either 'linear_combination' or 'values'")
1783
+ for i in range(n):
1784
+ col[i] = col[i].reduce(bigoh)
1785
+ col.append(pRational(p, ZZ(1), bigoh))
1786
+ self._matrix[x_ref] = col
1787
+ self._capped[x_ref] = capped
1788
+
1789
+ # We update history
1790
+ if self._history is not None:
1791
+ self._history.append(('add', None, walltime(tme)))
1792
+
1793
+ def del_elements(self, threshold=None):
1794
+ r"""
1795
+ Erase columns of the lattice precision matrix corresponding to
1796
+ elements which are marked for deletion and echelonize the matrix
1797
+ in order to keep it upper triangular.
1798
+
1799
+ INPUT:
1800
+
1801
+ - ``threshold`` -- integer or ``None`` (default: ``None``);
1802
+ a column whose distance to the right is greater than the
1803
+ threshold is not erased
1804
+
1805
+ EXAMPLES::
1806
+
1807
+ sage: R = ZpLC(2, label='delelts')
1808
+ sage: prec = R.precision()
1809
+
1810
+ sage: x = R(1, 10)
1811
+ sage: prec
1812
+ Precision lattice on 1 object (label: delelts)
1813
+ sage: prec.precision_lattice() # needs sage.geometry.polyhedron
1814
+ [1024]
1815
+
1816
+ sage: del x
1817
+ sage: prec
1818
+ Precision lattice on 1 object (label: delelts)
1819
+ sage: prec.precision_lattice() # needs sage.geometry.polyhedron
1820
+ [1024]
1821
+
1822
+ sage: prec.del_elements()
1823
+ sage: prec
1824
+ Precision lattice on 0 objects (label: delelts)
1825
+ sage: prec.precision_lattice() # needs sage.geometry.polyhedron
1826
+ []
1827
+ """
1828
+ n = len(self._elements)
1829
+
1830
+ # We mark new collected elements for deletion
1831
+ # The list self._collected_references can be updated while
1832
+ # the loop runs.
1833
+ # However, we do not need to copy it because Python supports
1834
+ # iteration over a list to which elements are added.
1835
+ count = 0
1836
+ for ref in self._collected_references:
1837
+ count += 1
1838
+ tme = walltime()
1839
+ index = self._index(ref)
1840
+ self._marked_for_deletion.append(index)
1841
+ if self._history is not None:
1842
+ self._history.append(('mark', index, walltime(tme)))
1843
+ del self._collected_references[:count]
1844
+
1845
+ # We erase corresponding columns and echelonize
1846
+ self._marked_for_deletion.sort(reverse=True)
1847
+ count = 0
1848
+ for index in self._marked_for_deletion:
1849
+ if threshold is not None and index < n - threshold:
1850
+ break
1851
+ n -= 1
1852
+ count += 1
1853
+
1854
+ tme = walltime()
1855
+ ref = self._elements[index]
1856
+ del self._elements[index]
1857
+ del self._matrix[ref]
1858
+ capped = self._capped[ref]
1859
+ del self._capped[ref]
1860
+
1861
+ # Now, we echelonize
1862
+ for i in range(index, n):
1863
+ ref = self._elements[i]
1864
+ col = self._matrix[ref]
1865
+ if col[i].valuation() < col[i+1].valuation():
1866
+ self._capped[ref], capped = capped, capped or self._capped[ref]
1867
+ else:
1868
+ capped = capped or self._capped[ref]
1869
+
1870
+ d, u, v = col[i].xgcd(col[i+1])
1871
+ up, vp = col[i+1]/d, col[i]/d
1872
+ col[i] = d
1873
+ del col[i+1]
1874
+ for j in range(i+1, n):
1875
+ col = self._matrix[self._elements[j]]
1876
+ col[i], col[i+1] = u*col[i] + v*col[i+1], up*col[i] - vp*col[i+1]
1877
+
1878
+ # We update history
1879
+ if self._history is not None:
1880
+ self._history.append(('del', index, walltime(tme)))
1881
+
1882
+ # And we reduce a bit
1883
+ # (we do not perform a complete reduction because it is costly)
1884
+ self.reduce(index, partial=True)
1885
+
1886
+ del self._marked_for_deletion[:count]
1887
+
1888
+ def _lift_to_precision(self, x, prec):
1889
+ r"""
1890
+ Lift the specified element to the specified precision.
1891
+
1892
+ INPUT:
1893
+
1894
+ - ``x`` -- the element whose precision has to be lifted
1895
+
1896
+ - ``prec`` -- the new precision
1897
+
1898
+ NOTE:
1899
+
1900
+ The new precision lattice is computed as the intersection
1901
+ of the current precision lattice with the subspace
1902
+
1903
+ .. MATH::
1904
+
1905
+ p^{prec} \Z_p dx \oplus \bigoplus_{y \neq x} \Q_p dy
1906
+
1907
+ This function may change at the same time the precision of
1908
+ other elements having the same parent.
1909
+
1910
+ .. NOTE::
1911
+
1912
+ This function is not meant to be called directly. Use
1913
+ ``x.lift_to_precision`` instead.
1914
+
1915
+ EXAMPLES::
1916
+
1917
+ sage: R = ZpLC(2)
1918
+ sage: x = R(1, 10); x
1919
+ 1 + O(2^10)
1920
+ sage: y = R(1, 5); y
1921
+ 1 + O(2^5)
1922
+ sage: z = x + y; z
1923
+ 2 + O(2^5)
1924
+
1925
+ sage: prec = R.precision()
1926
+ sage: prec._lift_to_precision(z, 12)
1927
+ sage: z
1928
+ 2 + O(2^12)
1929
+ sage: y
1930
+ 1 + O(2^10)
1931
+ """
1932
+ ref = pAdicLatticeElementWeakProxy(x)
1933
+ col = self._matrix[ref]
1934
+ n = len(self._elements)
1935
+
1936
+ rows_by_val = defaultdict(list)
1937
+ for i in range(len(col)):
1938
+ v = col[i].valuation()
1939
+ if v >= prec:
1940
+ continue
1941
+ rows_by_val[v].append(i)
1942
+ vals = sorted(rows_by_val)
1943
+ vals.append(prec)
1944
+
1945
+ for t in range(len(vals)-1):
1946
+ v, w = vals[t], vals[t+1]
1947
+ rows = rows_by_val[v]
1948
+ piv = max(rows)
1949
+ for i in rows:
1950
+ if i == piv:
1951
+ continue
1952
+ # We clear the entry on the i-th row
1953
+ scalar = (col[i]/col[piv]).reduce(prec-v)
1954
+ for j in range(piv,n):
1955
+ col_cur = self._matrix[self._elements[j]]
1956
+ col_cur[i] -= scalar*col_cur[piv]
1957
+ # We rescale the piv-th row
1958
+ for j in range(piv,n):
1959
+ col_cur = self._matrix[self._elements[j]]
1960
+ col_cur[piv] <<= w - v
1961
+ # Now the entry on the piv-th row has valuation w
1962
+ # We update the dictionary accordingly
1963
+ if w < prec:
1964
+ rows_by_val[w].append(piv)
1965
+
1966
+ self._precision_absolute_data.clear_cache()
1967
+
1968
+ @cached_method(key=lambda self, x: pAdicLatticeElementWeakProxy(x))
1969
+ def _precision_absolute_data(self, x):
1970
+ r"""
1971
+ Return absolute precision data for ``x``.
1972
+
1973
+ .. NOTE::
1974
+
1975
+ Helper method for :meth:`_precision_absolute` and
1976
+ :meth:`_is_precision_capped`.
1977
+
1978
+ TESTS::
1979
+
1980
+ sage: R = ZpLC(2)
1981
+ sage: x = R(1, 10); x
1982
+ 1 + O(2^10)
1983
+ sage: y = R(1, 5); y
1984
+ 1 + O(2^5)
1985
+ sage: z = x + y; z
1986
+ 2 + O(2^5)
1987
+ sage: z.precision_absolute() # indirect doctest
1988
+ 5
1989
+ """
1990
+ ref = pAdicLatticeElementWeakProxy(x)
1991
+ col = self._matrix[ref]
1992
+ absprec = Infinity
1993
+ capped = False
1994
+ for i in range(len(col)):
1995
+ v = col[i].valuation()
1996
+ if v < absprec:
1997
+ absprec = v
1998
+ capped = self._capped[self._elements[i]]
1999
+ elif v == absprec:
2000
+ capped = capped and self._capped[self._elements[i]]
2001
+ return (absprec, capped)
2002
+
2003
+ def _precision_absolute(self, x):
2004
+ r"""
2005
+ Return the absolute precision of the given element.
2006
+
2007
+ INPUT:
2008
+
2009
+ - ``x`` -- an element in the parent corresponding to this lattice
2010
+
2011
+ .. NOTE::
2012
+
2013
+ The absolute precision is obtained by projecting the precision
2014
+ lattice onto the line of coordinate ``dx``.
2015
+
2016
+ This function is not meant to be called directly. Call
2017
+ ``x.precision_absolute()`` instead.
2018
+
2019
+ EXAMPLES::
2020
+
2021
+ sage: R = ZpLC(2)
2022
+ sage: x = R(1, 10); x
2023
+ 1 + O(2^10)
2024
+ sage: y = R(1, 5); y
2025
+ 1 + O(2^5)
2026
+ sage: z = x + y; z
2027
+ 2 + O(2^5)
2028
+ sage: z.precision_absolute() # indirect doctest
2029
+ 5
2030
+ """
2031
+ return self._precision_absolute_data(x)[0]
2032
+
2033
+ def _is_precision_capped(self, x):
2034
+ r"""
2035
+ Return whether the absolute precision of ``x`` results from a cap
2036
+ coming from the parent.
2037
+
2038
+ INPUT:
2039
+
2040
+ - ``x`` -- an element in the parent corresponding to this lattice
2041
+
2042
+ .. NOTE::
2043
+
2044
+ This function is not meant to be called directly. Call
2045
+ ``x.is_precision_capped`` instead.
2046
+
2047
+ EXAMPLES::
2048
+
2049
+ sage: R = ZpLC(2)
2050
+ sage: x = R(1, 10); x
2051
+ 1 + O(2^10)
2052
+ sage: x.is_precision_capped() # indirect doctest
2053
+ False
2054
+
2055
+ sage: y = x-x; y
2056
+ O(2^40)
2057
+ sage: y.is_precision_capped() # indirect doctest
2058
+ True
2059
+ """
2060
+ return self._precision_absolute_data(x)[1]
2061
+
2062
+ def precision_lattice(self, elements=None):
2063
+ r"""
2064
+ Return a matrix representing the precision lattice on a
2065
+ subset of elements.
2066
+
2067
+ INPUT:
2068
+
2069
+ - ``elements`` -- list of elements or ``None`` (default: ``None``)
2070
+
2071
+ - ``echelon`` -- boolean (default: ``True``); whether the result
2072
+ should be in echelon form
2073
+
2074
+ EXAMPLES::
2075
+
2076
+ sage: R = ZpLC(2, label='preclattice')
2077
+ sage: prec = R.precision()
2078
+ sage: x = R(1, 10); y = R(1, 5)
2079
+ sage: u = x + y
2080
+ sage: v = x - y
2081
+ sage: prec.precision_lattice() # needs sage.geometry.polyhedron
2082
+ [ 1024 0 1024 1024]
2083
+ [ 0 32 32 1099511627744]
2084
+ [ 0 0 2097152 0]
2085
+ [ 0 0 0 1099511627776]
2086
+ sage: prec.precision_lattice([u, v]) # needs sage.geometry.polyhedron
2087
+ [ 32 2016]
2088
+ [ 0 2048]
2089
+
2090
+ Here is another example with matrices::
2091
+
2092
+ sage: M = matrix(R, 2, 2, [R(3, 5), R(7, 5), R(1, 5), R(11, 1)]) # needs sage.modules
2093
+ sage: N = M^10 # needs sage.modules
2094
+ sage: prec.precision_lattice() # needs sage.geometry.polyhedron sage.modules
2095
+ 23 x 23 dense matrix over Integer Ring (use the '.str()' method to see the entries)
2096
+
2097
+ The next syntax provides as easy way to select an interesting
2098
+ subset of variables (the selected subset consists of the four
2099
+ entries of the matrix ``N``)::
2100
+
2101
+ sage: prec.precision_lattice(N) # needs sage.modules
2102
+ [ 2048 512 28160 230400]
2103
+ [ 0 2048 14336 258048]
2104
+ [ 0 0 65536 65536]
2105
+ [ 0 0 0 262144]
2106
+
2107
+ We can give a list of matrices as well::
2108
+
2109
+ sage: prec.precision_lattice([M, N]) # needs sage.modules
2110
+ [ 32 0 0 0 226115584 96788480 52174848 82804736]
2111
+ [ 0 32 0 0 52174848 121765888 11829248 28516352]
2112
+ [ 0 0 32 0 96788480 42762240 121765888 199614464]
2113
+ [ 0 0 0 2 5175296 12475904 1782272 4045824]
2114
+ [ 0 0 0 0 268435456 0 0 0]
2115
+ [ 0 0 0 0 0 268435456 0 0]
2116
+ [ 0 0 0 0 0 0 268435456 0]
2117
+ [ 0 0 0 0 0 0 0 268435456]
2118
+ """
2119
+ if elements is None:
2120
+ elements = self._elements
2121
+ else:
2122
+ elements = list_of_padics(elements)
2123
+ n = len(self._elements)
2124
+ rows = []
2125
+ val = 0
2126
+ for ref in elements:
2127
+ col = self._matrix[ref]
2128
+ row = [ x.value() for x in col ]
2129
+ valcol = min([ x.valuation() for x in col ])
2130
+ val = min(valcol, val)
2131
+ row += (n-len(row)) * [ZZ(0)]
2132
+ rows.append(row)
2133
+ from sage.matrix.constructor import matrix
2134
+ M = matrix(rows).transpose()
2135
+ if val < 0:
2136
+ M *= self._p ** (-val)
2137
+ M = M.change_ring(ZZ)
2138
+ M.echelonize()
2139
+ n = len(elements)
2140
+ M = M.submatrix(0, 0, n, n)
2141
+ if val < 0:
2142
+ M *= self._p ** val
2143
+ return M
2144
+
2145
+
2146
+ class PrecisionModule(UniqueRepresentation, DifferentialPrecisionGeneric):
2147
+ r"""
2148
+ A class for handling precision modules which are used to
2149
+ track precision in the ZpLF model.
2150
+
2151
+ The precision module (which is not necessarily a lattice)
2152
+ is stored as a matrix whose rows are generators.
2153
+ """
2154
+ def __init__(self, p, label, prec):
2155
+ r"""
2156
+ Initialize this precision module.
2157
+
2158
+ INPUT:
2159
+
2160
+ - ``p`` -- a prime number
2161
+
2162
+ - ``label`` -- string; the label of the parents to which belong
2163
+ the elements tracked by this precision module
2164
+
2165
+ NOTE:
2166
+
2167
+ The precision module is automatically initialized at the
2168
+ creation of the parent.
2169
+
2170
+ TESTS::
2171
+
2172
+ sage: R = ZpLF(2, label='init')
2173
+ sage: R.precision()
2174
+ Precision module on 0 objects (label: init)
2175
+ """
2176
+ DifferentialPrecisionGeneric.__init__(self, p, label)
2177
+ # elements whose valuation are not less than self._zero_cap are assumed to vanish
2178
+ self._zero_cap = prec
2179
+ self._internal_prec = prec + STARTING_ADDITIONAL_PREC
2180
+ self._count = 0
2181
+ self._threshold = 1
2182
+ self._repr_type = "Precision module"
2183
+
2184
+ # We need to copy this method.
2185
+ # Indeed otherwise it is inherited from UniqueRepresentation
2186
+ def __reduce__(self):
2187
+ r"""
2188
+ TESTS::
2189
+
2190
+ sage: R = ZpLF(2)
2191
+ sage: prec = R.precision()
2192
+ sage: dumps(prec)
2193
+ Traceback (most recent call last):
2194
+ ...
2195
+ NotImplementedError: pickling/unpickling precision modules is not implemented yet
2196
+ """
2197
+ raise NotImplementedError("pickling/unpickling precision modules is not implemented yet")
2198
+
2199
+ def internal_prec(self):
2200
+ r"""
2201
+ Return the relative precision at which computations is handled
2202
+ internally.
2203
+
2204
+ It is slightly greater than the actual precision and increases
2205
+ a bit (at a logarithmic rate) when new elements are created
2206
+ and/or computed.
2207
+
2208
+ EXAMPLES::
2209
+
2210
+ sage: R = ZpLF(5, prec=20, label='internal_prec')
2211
+ sage: prec = R.precision()
2212
+
2213
+ sage: prec.internal_prec()
2214
+ 25
2215
+
2216
+ sage: L = [ R.random_element() for _ in range(50) ]
2217
+ sage: prec.internal_prec()
2218
+ 28
2219
+ """
2220
+ return self._internal_prec
2221
+
2222
+ def dimension(self):
2223
+ r"""
2224
+ Return the dimension of this precision module.
2225
+
2226
+ EXAMPLES:
2227
+
2228
+ In general, the dimension increases by 1 when a new
2229
+ element with a given precision is created::
2230
+
2231
+ sage: R = ZpLF(2, label='dimension')
2232
+ sage: prec = R.precision()
2233
+
2234
+ sage: prec.dimension()
2235
+ 0
2236
+ sage: x = R.random_element(prec=10)
2237
+ sage: prec.dimension()
2238
+ 1
2239
+ sage: y = R.random_element(prec=10)
2240
+ sage: prec.dimension()
2241
+ 2
2242
+
2243
+ However in general it does not increase while
2244
+ doing computations::
2245
+
2246
+ sage: u = x + y
2247
+ sage: v = x^2 + 3*y + x*y + y^3
2248
+ sage: prec.dimension()
2249
+ 2
2250
+
2251
+ Of course, it may also decrease when a sufficient
2252
+ number of variables are collected::
2253
+
2254
+ sage: del x, y, u
2255
+ sage: prec.del_elements()
2256
+ sage: prec.dimension()
2257
+ 1
2258
+
2259
+ sage: del v
2260
+ sage: prec.del_elements()
2261
+ sage: prec.dimension()
2262
+ 0
2263
+ """
2264
+ if len(self._elements) == 0:
2265
+ return 0
2266
+ return len(self._matrix[self._elements[-1]])
2267
+
2268
+ def is_lattice(self):
2269
+ r"""
2270
+ Return ``True`` if this precision module is a lattice
2271
+ (i.e. has maximal dimension).
2272
+
2273
+ EXAMPLES::
2274
+
2275
+ sage: R = ZpLF(2, label='is_lattice')
2276
+ sage: prec = R.precision()
2277
+
2278
+ sage: x = R(1, 10)
2279
+ sage: y = R(1, 5)
2280
+ sage: prec.is_lattice()
2281
+ True
2282
+
2283
+ sage: u = x + y
2284
+ sage: prec.is_lattice()
2285
+ False
2286
+
2287
+ .. SEEALSO::
2288
+
2289
+ :meth:`dimension`
2290
+ """
2291
+ return self.dimension() == len(self._elements)
2292
+
2293
+ def _new_element(self, x, dx, bigoh, dx_mode='linear_combination'):
2294
+ r"""
2295
+ Update the lattice when a new element is created.
2296
+
2297
+ This function is not meant to be called manually.
2298
+ It is automatically called by the parent when a new
2299
+ element is created.
2300
+
2301
+ INPUT:
2302
+
2303
+ - ``x`` -- the newly created element
2304
+
2305
+ - ``dx`` -- dictionary representing the differential of ``x``
2306
+
2307
+ - ``bigoh`` -- integer or ``None`` (default: ``None``); the
2308
+ bigoh to be added to the precision of ``x``. If ``None``, the
2309
+ default cap is used.
2310
+
2311
+ - ``dx_mode`` -- string; either ``'linear_combination'`` (the
2312
+ default) or ``'values'``
2313
+
2314
+ If ``dx_mode`` is ``'linear_combination'``, the dictionary ``dx``
2315
+ encodes the expression of the differential of ``x``. For example, if
2316
+ ``x`` was defined as ``x = y*z`` then:
2317
+
2318
+ .. MATH::
2319
+
2320
+ dx = y dz + z dy
2321
+
2322
+ and the corresponding dictionary is ``{z: y, y: z}`` (except
2323
+ that the keys are not the elements themselves but weak references
2324
+ to them).
2325
+
2326
+ If ``dx_mode`` is ``'values'``, the dictionary ``dx`` directly
2327
+ specifies the entries that have to stored in the precision module.
2328
+ This mode is only used for multiple conversion between different
2329
+ parents (see :meth:`multiple_conversion`).
2330
+
2331
+ TESTS::
2332
+
2333
+ sage: R = ZpLF(2)
2334
+ sage: x = R.random_element()
2335
+ sage: y = R.random_element()
2336
+ sage: z = x*y # indirect doctest
2337
+ """
2338
+ # First we delete some elements marked for deletion
2339
+ if self._marked_for_deletion:
2340
+ self.del_elements(threshold=self._threshold_deletion)
2341
+
2342
+ # We increase the internal prec
2343
+ # The heuristic behind this is the following: when computing
2344
+ # with N digits of precision, we except that about N-log_p(c)
2345
+ # of them are correct after c elementary operations.
2346
+ self._count += 1
2347
+ if self._count > self._threshold:
2348
+ self._internal_prec += 1
2349
+ self._threshold *= self._p
2350
+
2351
+ tme = walltime()
2352
+ p = self._p
2353
+ n = self.dimension()
2354
+ x_ref = pAdicLatticeElementWeakProxy(x, self._record_collected_element)
2355
+ col = n * [self._approx_zero]
2356
+ if dx_mode == 'linear_combination':
2357
+ expected_vals = n * [ Infinity ]
2358
+ for elt, scalar in dx:
2359
+ ref = pAdicLatticeElementWeakProxy(elt)
2360
+ if not isinstance(scalar, pRational):
2361
+ scalar = pRational(p, scalar)
2362
+ c = self._matrix[ref]
2363
+ for i in range(len(c)):
2364
+ summand = scalar * c[i]
2365
+ expected_vals[i] = min(expected_vals[i], summand.valuation())
2366
+ col[i] += summand
2367
+ for i in range(n):
2368
+ if col[i].valuation() >= expected_vals[i] + self._zero_cap:
2369
+ col[i] = self._approx_zero
2370
+ elif dx_mode == 'values':
2371
+ for elt, scalar in dx:
2372
+ ref = pAdicLatticeElementWeakProxy(elt)
2373
+ if not isinstance(scalar, pRational):
2374
+ scalar = pRational(p, scalar)
2375
+ i = self._index(ref)
2376
+ col[i] = scalar
2377
+ else:
2378
+ raise ValueError("dx_mode must be either 'linear_combination' or 'values'")
2379
+
2380
+ for i in range(n):
2381
+ col[i] = col[i].reduce_relative(self._internal_prec)
2382
+ if bigoh is not None:
2383
+ col.append(pRational(p, ZZ(1), bigoh))
2384
+
2385
+ self._elements.append(x_ref)
2386
+ self._matrix[x_ref] = col
2387
+
2388
+ # We update history
2389
+ if self._history is not None:
2390
+ self._history.append(('add', None, walltime(tme)))
2391
+
2392
+ def del_elements(self, threshold=None):
2393
+ r"""
2394
+ Erase columns of the lattice precision matrix corresponding to
2395
+ elements which were collected by the garbage collector.
2396
+ Then reduce the matrix in order to keep it in echelon form.
2397
+
2398
+ INPUT:
2399
+
2400
+ - ``threshold`` -- integer or ``None`` (default: ``None``);
2401
+ a non-pivot column whose distance to the right is greater than
2402
+ the threshold is not erased but only marked for future deletion
2403
+
2404
+ EXAMPLES::
2405
+
2406
+ sage: R = ZpLF(2, label='delelts')
2407
+ sage: prec = R.precision()
2408
+
2409
+ sage: x = R(1, 10)
2410
+ sage: prec
2411
+ Precision module on 1 object (label: delelts)
2412
+ sage: prec.precision_lattice() # needs sage.geometry.polyhedron
2413
+ [1024]
2414
+
2415
+ sage: del x
2416
+ sage: prec
2417
+ Precision module on 1 object (label: delelts)
2418
+ sage: prec.precision_lattice() # needs sage.geometry.polyhedron
2419
+ [1024]
2420
+
2421
+ sage: prec.del_elements()
2422
+ sage: prec
2423
+ Precision module on 0 objects (label: delelts)
2424
+ sage: prec.precision_lattice() # needs sage.geometry.polyhedron
2425
+ []
2426
+ """
2427
+ # We mark new collected elements for deletion
2428
+ # The list self._collected_references can be updated while
2429
+ # the loop runs.
2430
+ # However, we do not need to copy it because Python supports
2431
+ # iteration over a list to which elements are added.
2432
+ count = 0
2433
+ for ref in self._collected_references:
2434
+ count += 1
2435
+ tme = walltime()
2436
+ index = self._index(ref)
2437
+ if index == 0:
2438
+ length_before = 0
2439
+ else:
2440
+ length_before = len(self._matrix[self._elements[index-1]])
2441
+ length = len(self._matrix[ref])
2442
+ if length > length_before:
2443
+ self._marked_for_deletion.append(index)
2444
+ if self._history is not None:
2445
+ self._history.append(('mark', index, walltime(tme)))
2446
+ else:
2447
+ # if the column is not a pivot, we erase it without delay
2448
+ # (btw, is it a good idea?)
2449
+ del self._elements[index]
2450
+ self._marked_for_deletion = [i if i < index else i - 1
2451
+ for i in self._marked_for_deletion]
2452
+ if self._history is not None:
2453
+ self._history.append(('del', index, walltime(tme)))
2454
+ del self._collected_references[:count]
2455
+
2456
+ # We erase corresponding columns and echelonize
2457
+ n = len(self._elements)
2458
+ self._marked_for_deletion.sort(reverse=True)
2459
+ count = 0
2460
+ for index in self._marked_for_deletion:
2461
+ if threshold is not None and index < n - threshold:
2462
+ break
2463
+ n -= 1
2464
+ count += 1
2465
+
2466
+ tme = walltime()
2467
+
2468
+ length = len(self._matrix[self._elements[index]])
2469
+ del self._matrix[self._elements[index]]
2470
+ del self._elements[index]
2471
+ start = index
2472
+ while start < n:
2473
+ i = start
2474
+ val = Infinity
2475
+ end = n
2476
+ while i < n:
2477
+ col = self._matrix[self._elements[i]]
2478
+ if len(col) > length:
2479
+ end = i
2480
+ break
2481
+ v = col[-1].valuation()
2482
+ if v < val:
2483
+ val = v
2484
+ piv = i
2485
+ i += 1
2486
+ if val < Infinity:
2487
+ # another pivot has been found, we place it in front
2488
+ self._elements[start], self._elements[piv] = self._elements[piv], self._elements[start]
2489
+ break
2490
+
2491
+ # No pivot was found. We re-echelonize
2492
+ for i in range(start, end):
2493
+ del self._matrix[self._elements[i]][-1]
2494
+ if end == n:
2495
+ break
2496
+ # col is the column of index "end"
2497
+ # its size is (length + 1)
2498
+ d, u, v = col[length-1].xgcd(col[length])
2499
+ up, vp = col[length]/d, col[length-1]/d
2500
+ col[length-1] = d.reduce_relative(self._internal_prec)
2501
+ del col[length]
2502
+ start = end + 1
2503
+ for j in range(start, n):
2504
+ col = self._matrix[self._elements[j]]
2505
+ a1 = u*col[length-1]
2506
+ a2 = v*col[length]
2507
+ a = a1 + a2
2508
+ b1 = up*col[length-1]
2509
+ b2 = vp * col[length]
2510
+ b = b1 + b2
2511
+ if a.valuation() > min(a1.valuation(), a2.valuation()) + self._zero_cap:
2512
+ col[length-1] = self._approx_zero
2513
+ else:
2514
+ col[length-1] = a.reduce_relative(self._internal_prec)
2515
+ if b.valuation() > min(b1.valuation(), b2.valuation()) + self._zero_cap:
2516
+ col[length] = self._approx_zero
2517
+ else:
2518
+ col[length] = b.reduce_relative(self._internal_prec)
2519
+ length += 1
2520
+
2521
+ # We update history
2522
+ if self._history is not None:
2523
+ self._history.append(('del', index, walltime(tme)))
2524
+
2525
+ del self._marked_for_deletion[:count]
2526
+
2527
+ def _lift_to_precision(self, x, prec):
2528
+ r"""
2529
+ Lift the specified element to the specified precision.
2530
+
2531
+ INPUT:
2532
+
2533
+ - ``x`` -- the element whose precision has to be lifted
2534
+
2535
+ - ``prec`` -- the new precision
2536
+
2537
+ .. NOTE::
2538
+
2539
+ The new precision lattice is computed as the intersection
2540
+ of the current precision lattice with the subspace.
2541
+
2542
+ .. MATH::
2543
+
2544
+ p^{prec} \Z_p dx \oplus \bigoplus_{y \neq x} \Q_p dy
2545
+
2546
+ This function may change at the same time the precision of
2547
+ other elements having the same parent.
2548
+
2549
+ .. NOTE::
2550
+
2551
+ This function is not meant to be called directly. Use
2552
+ ``x.lift_to_precision`` instead.
2553
+
2554
+ EXAMPLES::
2555
+
2556
+ sage: R = ZpLF(2)
2557
+ sage: x = R(1, 10); x
2558
+ 1 + O(2^10)
2559
+ sage: y = R(1, 5); y
2560
+ 1 + O(2^5)
2561
+ sage: u = x^2 + x*y
2562
+ sage: v = y^2 + x*y
2563
+ sage: w = u + v
2564
+
2565
+ sage: prec = R.precision()
2566
+ sage: prec._lift_to_precision(w, 11)
2567
+ sage: w
2568
+ 2^2 + O(2^11)
2569
+ sage: y
2570
+ 1 + O(2^9)
2571
+ """
2572
+ ref = pAdicLatticeElementWeakProxy(x)
2573
+ col = self._matrix[ref]
2574
+ n = len(self._elements)
2575
+
2576
+ rows_by_val = defaultdict(list)
2577
+ for i in range(len(col)):
2578
+ v = col[i].valuation()
2579
+ if v >= prec:
2580
+ continue
2581
+ rows_by_val[v].append(i)
2582
+ vals = sorted(rows_by_val)
2583
+ vals.append(prec)
2584
+
2585
+ for t in range(len(vals)-1):
2586
+ v, w = vals[t], vals[t+1]
2587
+ rows = rows_by_val[v]
2588
+ piv = max(rows)
2589
+ for i in rows:
2590
+ if i == piv:
2591
+ continue
2592
+ # We clear the entry on the i-th row
2593
+ scalar = (col[i]/col[piv]).reduce(prec-v)
2594
+ for j in range(n):
2595
+ col_cur = self._matrix[self._elements[j]]
2596
+ if len(col_cur) > piv:
2597
+ col_cur[i] -= scalar*col_cur[piv]
2598
+ col_cur[i] = col_cur[i].reduce_relative(self._internal_prec)
2599
+ # We rescale the piv-th row
2600
+ # (if w is Infinity, we delete it)
2601
+ for j in range(n):
2602
+ col_cur = self._matrix[self._elements[j]]
2603
+ if len(col_cur) > piv:
2604
+ if w is Infinity:
2605
+ del col_cur[piv]
2606
+ else:
2607
+ col_cur[piv] <<= w - v
2608
+ # Now the entry on the piv-th row has valuation w
2609
+ # We update the dictionary accordingly
2610
+ if w < prec:
2611
+ rows_by_val[w].append(piv)
2612
+
2613
+ self._precision_absolute.clear_cache()
2614
+
2615
+ @cached_method(key=lambda self, x: pAdicLatticeElementWeakProxy(x))
2616
+ def _precision_absolute(self, x):
2617
+ r"""
2618
+ Return the absolute precision of the given element.
2619
+
2620
+ INPUT:
2621
+
2622
+ - ``x`` -- the element whose absolute precision is requested
2623
+
2624
+ .. NOTE::
2625
+
2626
+ The absolute precision is obtained by projecting the precision
2627
+ module onto the line of coordinate ``dx``.
2628
+
2629
+ This function is not meant to be called directly. Call
2630
+ ``x.precision_absolute()`` instead.
2631
+
2632
+ EXAMPLES::
2633
+
2634
+ sage: R = ZpLF(2)
2635
+ sage: prec = R.precision()
2636
+
2637
+ sage: x = R(1, 10); x
2638
+ 1 + O(2^10)
2639
+ sage: y = R(1, 5); y
2640
+ 1 + O(2^5)
2641
+ sage: z = x + y; z
2642
+ 2 + O(2^5)
2643
+ sage: z.precision_absolute() # indirect doctest
2644
+ 5
2645
+
2646
+ In some cases, the absolute precision returned by this function
2647
+ may be infinite::
2648
+
2649
+ sage: y = R(1)
2650
+ sage: prec._precision_absolute(y)
2651
+ +Infinity
2652
+
2653
+ However calling the method :meth:`absolute_precision` of the
2654
+ element itself reintroduces a cap::
2655
+
2656
+ sage: y.precision_absolute()
2657
+ 20
2658
+ """
2659
+ ref = pAdicLatticeElementWeakProxy(x)
2660
+ col = self._matrix[ref]
2661
+ if len(col) == 0:
2662
+ return Infinity
2663
+ else:
2664
+ return min( [ c.valuation() for c in col ] )
2665
+
2666
+ def precision_lattice(self, elements=None):
2667
+ r"""
2668
+ Return a matrix representing the precision lattice on a
2669
+ subset of elements.
2670
+
2671
+ INPUT:
2672
+
2673
+ - ``elements`` -- list of elements or ``None`` (default: ``None``)
2674
+
2675
+ EXAMPLES::
2676
+
2677
+ sage: R = ZpLF(2, label='preclattice')
2678
+ sage: prec = R.precision()
2679
+ sage: x = R(1, 10); y = R(1, 5)
2680
+ sage: prec.precision_lattice() # needs sage.geometry.polyhedron
2681
+ [1024 0]
2682
+ [ 0 32]
2683
+
2684
+ sage: u = x + y
2685
+ sage: v = x - y
2686
+ sage: prec.precision_lattice([u, v]) # needs sage.geometry.polyhedron
2687
+ [ 32 2016]
2688
+ [ 0 2048]
2689
+
2690
+ If the precision module does not project to a lattice,
2691
+ an error is raised. ::
2692
+
2693
+ sage: prec.precision_lattice([x, y, u, v]) # needs sage.geometry.polyhedron
2694
+ Traceback (most recent call last):
2695
+ ...
2696
+ PrecisionError: the differential is not surjective
2697
+
2698
+ Here is another example with matrices::
2699
+
2700
+ sage: M = matrix(R, 2, 2, [R(3, 5), R(7, 5), R(1, 5), R(11, 1)]) # needs sage.modules
2701
+ sage: N = M^10 # needs sage.modules
2702
+
2703
+ The next syntax provides as easy way to select an interesting
2704
+ subset of variables (the selected subset consists of the four
2705
+ entries of the matrix ``N``)::
2706
+
2707
+ sage: prec.precision_lattice(N) # needs sage.geometry.polyhedron sage.modules
2708
+ [ 2048 512 28160 230400]
2709
+ [ 0 2048 14336 258048]
2710
+ [ 0 0 65536 65536]
2711
+ [ 0 0 0 262144]
2712
+ """
2713
+ if elements is None:
2714
+ elements = self._elements
2715
+ else:
2716
+ elements = list_of_padics(elements)
2717
+ n = len(self._elements)
2718
+ rows = [ ]
2719
+ val = 0
2720
+ for ref in elements:
2721
+ col = self._matrix[ref]
2722
+ row = [ x.value() for x in col ]
2723
+ valcol = min([ x.valuation() for x in col ])
2724
+ val = min(valcol, val)
2725
+ row += (n-len(row)) * [ZZ(0)]
2726
+ rows.append(row)
2727
+ from sage.matrix.constructor import matrix
2728
+ M = matrix(rows).transpose()
2729
+ if val < 0:
2730
+ M *= self._p ** (-val)
2731
+ M = M.change_ring(ZZ)
2732
+ M.echelonize()
2733
+ n = len(elements)
2734
+ if len(M.pivots()) < n:
2735
+ raise PrecisionError("the differential is not surjective")
2736
+ for i in range(n):
2737
+ v = M[i, i].valuation(self._p)
2738
+ M[i, i] = self._p ** v
2739
+ M.echelonize()
2740
+ M = M.submatrix(0, 0, n, n)
2741
+ if val < 0:
2742
+ M *= self._p ** val
2743
+ return M
2744
+
2745
+
2746
+ class pAdicLatticeElementWeakProxy:
2747
+ r"""
2748
+ The implementations of :class:`DifferentialPrecisionGeneric` hold
2749
+ weak references to :class:`pAdicLatticeElement`. They are stored in
2750
+ dictionaries, e.g., a dictionary that maps an element to the corresponding
2751
+ column in the precision lattice matrix.
2752
+ However, weak references as implemented by Python are tricky to use as
2753
+ dictionary keys. Their equality depends on the equality of the element they
2754
+ point to (as long as that element is alive) and then on the equality by
2755
+ ``id``. This means that statements such as: ``ref in D == ref in D`` could
2756
+ be false if the garbage collector kicks in between the two invocations.
2757
+ To prevent very subtle and hardly reproducible bugs, we wrap weak
2758
+ references in a proxy that gives every lattice element a unique increasing
2759
+ id and uses that id for comparisons.
2760
+
2761
+ EXAMPLES:
2762
+
2763
+ Proxy elements exist only internally and are not usually exposed to the user::
2764
+
2765
+ sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
2766
+ sage: R = ZpLF(2, label='proxy')
2767
+ sage: p = R(2)
2768
+ sage: prec = R.precision()
2769
+ sage: proxy = prec._elements[0]
2770
+ sage: isinstance(proxy, pAdicLatticeElementWeakProxy)
2771
+ True
2772
+ """
2773
+ _next_id = 0
2774
+
2775
+ def __init__(self, element, callback=None):
2776
+ r"""
2777
+ TESTS::
2778
+
2779
+ sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
2780
+ sage: R = ZpLF(2, label='proxy')
2781
+ sage: p = R(2)
2782
+ sage: pAdicLatticeElementWeakProxy(p) == pAdicLatticeElementWeakProxy(p)
2783
+ True
2784
+ sage: pAdicLatticeElementWeakProxy(p) is pAdicLatticeElementWeakProxy(p)
2785
+ False
2786
+ """
2787
+ if not hasattr(element, '_proxy_id'):
2788
+ element._proxy_id = pAdicLatticeElementWeakProxy._next_id
2789
+ pAdicLatticeElementWeakProxy._next_id += 1
2790
+ self._id = element._proxy_id
2791
+ from weakref import ref
2792
+ proxy_callback = callback
2793
+ if callback is not None:
2794
+ proxy_callback = lambda _: callback(self)
2795
+ self._weakref = ref(element, proxy_callback)
2796
+
2797
+ def __hash__(self):
2798
+ r"""
2799
+ Return a hash value for this proxy.
2800
+
2801
+ EXAMPLES::
2802
+
2803
+ sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
2804
+ sage: R = ZpLF(2, label='proxy')
2805
+ sage: p = R(2)
2806
+ sage: hash(pAdicLatticeElementWeakProxy(p)) == hash(pAdicLatticeElementWeakProxy(p))
2807
+ True
2808
+ """
2809
+ return self._id
2810
+
2811
+ def __eq__(self, other):
2812
+ r"""
2813
+ Return whether this proxy is undistinguishable from ``other``.
2814
+
2815
+ EXAMPLES::
2816
+
2817
+ sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
2818
+ sage: R = ZpLF(2, label='proxy')
2819
+ sage: p = R(2)
2820
+ sage: q = R(2)
2821
+ sage: pAdicLatticeElementWeakProxy(p) == pAdicLatticeElementWeakProxy(p)
2822
+ True
2823
+ sage: pAdicLatticeElementWeakProxy(q) == pAdicLatticeElementWeakProxy(p)
2824
+ False
2825
+ """
2826
+ return isinstance(other, pAdicLatticeElementWeakProxy) and self._id == other._id
2827
+
2828
+ def __call__(self):
2829
+ r"""
2830
+ Return the lattice element this proxy points to, or ``None`` if the
2831
+ target has already been finalized.
2832
+
2833
+ EXAMPLES::
2834
+
2835
+ sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
2836
+ sage: R = ZpLF(2, label='proxy')
2837
+ sage: p = R(2)
2838
+ sage: pAdicLatticeElementWeakProxy(p)()
2839
+ 2 + O(2^21)
2840
+ """
2841
+ return self._weakref()
2842
+
2843
+ def __repr__(self):
2844
+ r"""
2845
+ Return a printable representation of this proxy.
2846
+
2847
+ EXAMPLES::
2848
+
2849
+ sage: from sage.rings.padics.lattice_precision import pAdicLatticeElementWeakProxy
2850
+ sage: R = ZpLF(2, label='proxy_repr')
2851
+ sage: p = R(2)
2852
+ sage: R.precision()._elements # indirect doctest
2853
+ [WeakProxy#...]
2854
+ """
2855
+ return "WeakProxy#%s" % (self._id,)
2856
+
2857
+
2858
+ def list_of_padics(elements):
2859
+ r"""
2860
+ Convert a list of `p`-adic composed elements (such as polynomials, matrices)
2861
+ to a list of weak references of their `p`-adic coefficients.
2862
+
2863
+ This is a helper function for the method :meth:`precision_lattice`.
2864
+
2865
+ TESTS::
2866
+
2867
+ sage: from sage.rings.padics.lattice_precision import list_of_padics
2868
+ sage: R = ZpLC(2)
2869
+ sage: M = random_matrix(R, 2, 2) # needs sage.geometry.polyhedron
2870
+ sage: list_of_padics(M) # needs sage.geometry.polyhedron
2871
+ [WeakProxy#...,
2872
+ WeakProxy#...,
2873
+ WeakProxy#...,
2874
+ WeakProxy#...]
2875
+ """
2876
+ from sage.rings.padics.padic_lattice_element import pAdicLatticeElement
2877
+ if isinstance(elements, pAdicLatticeElement):
2878
+ return [ pAdicLatticeElementWeakProxy(elements) ]
2879
+ try:
2880
+ if elements.parent().is_sparse():
2881
+ elements = elements.coefficients()
2882
+ except AttributeError:
2883
+ pass
2884
+ if not isinstance(elements, list):
2885
+ elements = list(elements)
2886
+ ans = [ ]
2887
+ for x in elements:
2888
+ ans += list_of_padics(x)
2889
+ return ans