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,1519 @@
1
+ # sage_setup: distribution = sagemath-pari
2
+ # sage.doctest: needs sage.libs.pari sage.rings.padics
3
+ r"""
4
+ Normal forms for `p`-adic quadratic and bilinear forms
5
+
6
+ We represent a quadratic or bilinear form by its `n \times n` Gram matrix `G`.
7
+ Then two `p`-adic forms `G` and `G'` are integrally equivalent if and only if
8
+ there is a matrix `B` in `GL(n,\ZZ_p)` such that `G' = B G B^T`.
9
+
10
+ This module allows the computation of a normal form. This means that two
11
+ `p`-adic forms are integrally equivalent if and only if they have the same
12
+ normal form. Further, we can compute a transformation into normal form
13
+ (up to finite precision).
14
+
15
+ EXAMPLES::
16
+
17
+ sage: from sage.quadratic_forms.genera.normal_form import p_adic_normal_form
18
+ sage: G1 = Matrix(ZZ,4, [2, 0, 0, 1, 0, 2, 0, 1, 0, 0, 4, 2, 1, 1, 2, 6])
19
+ sage: G1
20
+ [2 0 0 1]
21
+ [0 2 0 1]
22
+ [0 0 4 2]
23
+ [1 1 2 6]
24
+ sage: G2 = Matrix(ZZ,4, [2, 1, 1, 0, 1, 2, 0, 0, 1, 0, 2, 0, 0, 0, 0, 16])
25
+ sage: G2
26
+ [ 2 1 1 0]
27
+ [ 1 2 0 0]
28
+ [ 1 0 2 0]
29
+ [ 0 0 0 16]
30
+
31
+ A computation reveals that both forms are equivalent over `\ZZ_2`::
32
+
33
+ sage: D1, U1 = p_adic_normal_form(G1,2, precision=30)
34
+ sage: D2, U2 = p_adic_normal_form(G1,2, precision=30)
35
+ sage: D1
36
+ [ 2 1 0 0]
37
+ [ 1 2 0 0]
38
+ [ 0 0 2^2 + 2^3 0]
39
+ [ 0 0 0 2^4]
40
+ sage: D2
41
+ [ 2 1 0 0]
42
+ [ 1 2 0 0]
43
+ [ 0 0 2^2 + 2^3 0]
44
+ [ 0 0 0 2^4]
45
+
46
+ Moreover, we have computed the `2`-adic isomorphism::
47
+
48
+ sage: U = U2.inverse()*U1
49
+ sage: U*G1*U.T
50
+ [ 2 2^31 + 2^32 2^32 + 2^33 1]
51
+ [2^31 + 2^32 2 2^32 1]
52
+ [2^32 + 2^33 2^32 2^2 2]
53
+ [ 1 1 2 2 + 2^2]
54
+
55
+ As you can see this isomorphism is only up to the precision we set before::
56
+
57
+ sage: (U*G1*U.T).change_ring(IntegerModRing(2^30))
58
+ [2 0 0 1]
59
+ [0 2 0 1]
60
+ [0 0 4 2]
61
+ [1 1 2 6]
62
+
63
+ If you are only interested if the forms are isomorphic,
64
+ there are much faster ways::
65
+
66
+ sage: q1 = QuadraticForm(G1)
67
+ sage: q2 = QuadraticForm(G2)
68
+ sage: q1.is_locally_equivalent_to(q2,2)
69
+ True
70
+
71
+ SEEALSO::
72
+
73
+ :mod:`~sage.quadratic_forms.genera.genus`
74
+ :meth:`~sage.quadratic_forms.quadratic_form.QuadraticForm.is_locally_equivalent_to`
75
+ :meth:`~sage.modules.torsion_quadratic_module.TorsionQuadraticModule.normal_form`
76
+
77
+ AUTHORS:
78
+
79
+ - Simon Brandhorst (2018-01): initial version
80
+ """
81
+
82
+ # ****************************************************************************
83
+ # Copyright (C) 2018 Simon Branhdorst <sbrandhorst@web.de>
84
+ #
85
+ # This program is free software: you can redistribute it and/or modify
86
+ # it under the terms of the GNU General Public License as published by
87
+ # the Free Software Foundation, either version 2 of the License, or
88
+ # (at your option) any later version.
89
+ # https://www.gnu.org/licenses/
90
+ # ****************************************************************************
91
+
92
+ from sage.rings.integer_ring import ZZ
93
+ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
94
+ from sage.matrix.constructor import Matrix
95
+ from copy import copy
96
+ from sage.rings.finite_rings.integer_mod import mod
97
+
98
+
99
+ def collect_small_blocks(G):
100
+ r"""
101
+ Return the blocks as list.
102
+
103
+ INPUT:
104
+
105
+ - ``G`` -- a ``block_diagonal`` matrix consisting of
106
+ `1` by `1` and `2` by `2` blocks
107
+
108
+ OUTPUT: list of `1` by `1` and `2` by `2` matrices; the blocks
109
+
110
+ EXAMPLES::
111
+
112
+ sage: from sage.quadratic_forms.genera.normal_form import collect_small_blocks
113
+ sage: W1 = Matrix([1])
114
+ sage: V = Matrix(ZZ, 2, [2, 1, 1, 2])
115
+ sage: L = [W1, V, V, W1, W1, V, W1, V]
116
+ sage: G = Matrix.block_diagonal(L)
117
+ sage: L == collect_small_blocks(G)
118
+ True
119
+ """
120
+ D = copy(G)
121
+ L = _get_small_block_indices(D)[1:]
122
+ D.subdivide(L, L)
123
+ blocks = []
124
+ for i in range(len(L) + 1):
125
+ block = copy(D.subdivision(i, i))
126
+ blocks.append(block)
127
+ return blocks
128
+
129
+
130
+ def p_adic_normal_form(G, p, precision=None, partial=False, debug=False):
131
+ r"""
132
+ Return the transformation to the `p`-adic normal form of a symmetric matrix.
133
+
134
+ Two ```p`-adic`` quadratic forms are integrally equivalent if and only if
135
+ their Gram matrices have the same normal form.
136
+
137
+ Let `p` be odd and `u` be the smallest non-square modulo `p`.
138
+ The normal form is a block diagonal matrix
139
+ with blocks `p^k G_k` such that `G_k` is either the identity matrix or
140
+ the identity matrix with the last diagonal entry replaced by `u`.
141
+
142
+ If `p=2` is even, define the `1` by `1` matrices::
143
+
144
+ sage: W1 = Matrix([1]); W1
145
+ [1]
146
+ sage: W3 = Matrix([3]); W3
147
+ [3]
148
+ sage: W5 = Matrix([5]); W5
149
+ [5]
150
+ sage: W7 = Matrix([7]); W7
151
+ [7]
152
+
153
+ and the `2` by `2` matrices::
154
+
155
+ sage: U = Matrix(2,[0,1,1,0]); U
156
+ [0 1]
157
+ [1 0]
158
+ sage: V = Matrix(2,[2,1,1,2]); V
159
+ [2 1]
160
+ [1 2]
161
+
162
+ For `p=2` the partial normal form is a block diagonal matrix with blocks
163
+ `2^k G_k` such that `G_k` is a block diagonal matrix of the form
164
+ `[U`, ... , `U`, `V`, `Wa`, `Wb]`
165
+ where we allow `V`, `Wa`, `Wb` to be `0 \times 0` matrices.
166
+
167
+ Further restrictions to the full normal form apply.
168
+ We refer to [MirMor2009]_ IV Definition 4.6. for the details.
169
+
170
+ INPUT:
171
+
172
+ - ``G`` -- a symmetric `n` by `n` matrix in `\QQ`
173
+ - ``p`` -- a prime number -- it is not checked whether it is prime
174
+ - ``precision`` -- if not set, the minimal possible is taken
175
+ - ``partial`` -- boolean (default: ``False``); if set, only the
176
+ partial normal form is returned
177
+
178
+ OUTPUT:
179
+
180
+ - ``D`` -- the jordan matrix over `\QQ_p`
181
+ - ``B`` -- invertible transformation matrix over `\ZZ_p`,
182
+ i.e., `D = B * G * B^T`
183
+
184
+ EXAMPLES::
185
+
186
+ sage: from sage.quadratic_forms.genera.normal_form import p_adic_normal_form
187
+ sage: D4 = Matrix(ZZ, 4, [2,-1,-1,-1,-1,2,0,0,-1,0,2,0,-1,0,0,2])
188
+ sage: D4
189
+ [ 2 -1 -1 -1]
190
+ [-1 2 0 0]
191
+ [-1 0 2 0]
192
+ [-1 0 0 2]
193
+ sage: D, B = p_adic_normal_form(D4, 2)
194
+ sage: D
195
+ [ 2 1 0 0]
196
+ [ 1 2 0 0]
197
+ [ 0 0 2^2 2]
198
+ [ 0 0 2 2^2]
199
+ sage: D == B * D4 * B.T
200
+ True
201
+ sage: A4 = Matrix(ZZ, 4, [2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2])
202
+ sage: A4
203
+ [ 2 -1 0 0]
204
+ [-1 2 -1 0]
205
+ [ 0 -1 2 -1]
206
+ [ 0 0 -1 2]
207
+ sage: D, B = p_adic_normal_form(A4, 2)
208
+ sage: D
209
+ [0 1 0 0]
210
+ [1 0 0 0]
211
+ [0 0 2 1]
212
+ [0 0 1 2]
213
+
214
+ We can handle degenerate forms::
215
+
216
+ sage: A4_extended = Matrix(ZZ, 5, [2, -1, 0, 0, -1, -1, 2, -1, 0, 0, 0, -1, 2, -1, 0, 0, 0, -1, 2, -1, -1, 0, 0, -1, 2])
217
+ sage: D, B = p_adic_normal_form(A4_extended, 5)
218
+ sage: D
219
+ [1 0 0 0 0]
220
+ [0 1 0 0 0]
221
+ [0 0 1 0 0]
222
+ [0 0 0 5 0]
223
+ [0 0 0 0 0]
224
+
225
+ and denominators::
226
+
227
+ sage: A4dual = A4.inverse()
228
+ sage: D, B = p_adic_normal_form(A4dual, 5)
229
+ sage: D
230
+ [5^-1 0 0 0]
231
+ [ 0 1 0 0]
232
+ [ 0 0 1 0]
233
+ [ 0 0 0 1]
234
+
235
+ TESTS::
236
+
237
+ sage: Z = Matrix(ZZ, 0, [])
238
+ sage: p_adic_normal_form(Z, 3)
239
+ ([], [])
240
+ sage: Z = matrix.zero(10)
241
+ sage: p_adic_normal_form(Z, 3)[0] == 0
242
+ True
243
+ """
244
+ from sage.rings.padics.factory import Zp
245
+
246
+ p = ZZ(p)
247
+ # input checks!!
248
+ G0, denom = G._clear_denom()
249
+ d = denom.valuation(p)
250
+ r = G0.rank()
251
+ if r != G0.ncols():
252
+ U = G0.hermite_form(transformation=True)[1]
253
+ else:
254
+ U = G0.parent().identity_matrix()
255
+ kernel = U[r:, :]
256
+ nondeg = U[:r, :]
257
+
258
+ # continue with the non-degenerate part
259
+ G = nondeg * G * nondeg.T * p**d
260
+ if precision is None:
261
+ # in Zp(2) we have to calculate at least mod 8 for things to make sense.
262
+ precision = G.det().valuation(p) + 4
263
+ R = Zp(p, prec=precision, type='fixed-mod')
264
+ G = G.change_ring(R)
265
+ G.set_immutable() # is not changed during computation
266
+ n = G.ncols()
267
+ # The trivial case
268
+ if n == 0:
269
+ return G.parent().zero(), G.parent().zero()
270
+ # the transformation matrix is called B
271
+ if p == 2:
272
+ D, B = _jordan_2_adic(G)
273
+ else:
274
+ D, B = _jordan_odd_adic(G)
275
+ D, B1 = _normalize(D)
276
+ B = B1 * B
277
+ # we have reached a normal form for p != 2
278
+ # for p == 2 extra work is necessary
279
+ if p == 2:
280
+ D, B1 = _two_adic_normal_forms(D, partial=partial)
281
+ B = B1 * B
282
+ nondeg = B * nondeg
283
+ B = nondeg.stack(kernel)
284
+ D = Matrix.block_diagonal([D, Matrix.zero(kernel.nrows())])
285
+ if debug:
286
+ assert B.determinant().valuation() == 0 # B is invertible!
287
+ if p == 2:
288
+ assert B * G * B.T == Matrix.block_diagonal(collect_small_blocks(D))
289
+ else:
290
+ assert B * G * B.T == Matrix.diagonal(D.diagonal())
291
+ return D / p**d, B
292
+
293
+
294
+ def _find_min_p(G, cnt, lower_bound=0):
295
+ r"""
296
+ Find smallest valuation below and right from ``cnt`` preferring the diagonal.
297
+
298
+ INPUT:
299
+
300
+ - ``G`` -- a symmetric `n` by `n` matrix in `\QQ_p`
301
+ - ``cnt`` -- start search from this index
302
+ - ``lower_bound`` -- integer (default: 0)
303
+ a lower bound for the valuations used for optimization
304
+
305
+ OUTPUT:
306
+
307
+ - ``min`` -- minimal valuation
308
+ - ``min_i`` -- row index of the minimal valuation
309
+ - ``min_j`` -- column index of the minimal valuation
310
+
311
+ EXAMPLES::
312
+
313
+ sage: from sage.quadratic_forms.genera.normal_form import _find_min_p
314
+ sage: G = matrix(Qp(2, show_prec=False), 3, 3, [4,0,1,0,4,2,1,2,1])
315
+ sage: G
316
+ [2^2 0 1]
317
+ [ 0 2^2 2]
318
+ [ 1 2 1]
319
+ sage: _find_min_p(G, 0)
320
+ (0, 2, 2)
321
+ sage: G = matrix(Qp(3, show_prec=False), 3, 3, [4,0,1,0,4,2,1,2,1])
322
+ sage: G
323
+ [1 + 3 0 1]
324
+ [ 0 1 + 3 2]
325
+ [ 1 2 1]
326
+ sage: _find_min_p(G, 0)
327
+ (0, 0, 0)
328
+ """
329
+ n = G.ncols()
330
+ minval = G[cnt, cnt].valuation()
331
+ min_i = cnt
332
+ min_j = cnt
333
+ # diagonal has precedence
334
+ for i in range(cnt, n):
335
+ v = G[i, i].valuation()
336
+ if v == lower_bound:
337
+ return lower_bound, i, i
338
+ if v < minval:
339
+ min_i = i
340
+ min_j = i
341
+ minval = v
342
+ # off diagonal
343
+ for i in range(cnt, n):
344
+ for j in range(i + 1, n):
345
+ v = G[i, j].valuation()
346
+ if v == lower_bound:
347
+ return lower_bound, i, j
348
+ if v < minval:
349
+ min_i = i
350
+ min_j = j
351
+ minval = v
352
+ return minval, min_i, min_j
353
+
354
+
355
+ def _get_small_block_indices(G):
356
+ r"""
357
+ Return the indices of the blocks.
358
+
359
+ For internal use in :meth:`collect_small_blocks`.
360
+
361
+ INPUT:
362
+
363
+ - ``G`` -- a block_diagonal matrix consisting of `1` by `1` and `2` by `2` blocks
364
+
365
+ OUTPUT: list of integers
366
+
367
+ EXAMPLES::
368
+
369
+ sage: from sage.quadratic_forms.genera.normal_form import _get_small_block_indices
370
+ sage: W1 = Matrix([1])
371
+ sage: U = Matrix(ZZ, 2, [0, 1, 1, 0])
372
+ sage: G = Matrix.block_diagonal([W1, U, U, W1, W1, U, W1, U])
373
+ sage: _get_small_block_indices(G)
374
+ [0, 1, 3, 5, 6, 7, 9, 10]
375
+ """
376
+ L = []
377
+ n = G.ncols()
378
+ i = 0
379
+ while i < n - 1:
380
+ L.append(i)
381
+ if G[i, i + 1] != 0:
382
+ i += 2
383
+ else:
384
+ i += 1
385
+ if i == n - 1:
386
+ L.append(i)
387
+ return L[:]
388
+
389
+
390
+ def _get_homogeneous_block_indices(G):
391
+ r"""
392
+ Return the indices of the homogeneous blocks.
393
+
394
+ We call a matrix homogeneous if it is a multiple of an invertible matrix.
395
+ Sometimes they are also called modular.
396
+
397
+ INPUT:
398
+
399
+ - ``G`` -- a block diagonal matrix over the `p`-adics
400
+ with blocks of size at most `2`
401
+
402
+ OUTPUT: list of integers
403
+
404
+ EXAMPLES::
405
+
406
+ sage: from sage.quadratic_forms.genera.normal_form import _get_homogeneous_block_indices
407
+ sage: W1 = Matrix(Zp(2), [1])
408
+ sage: V = Matrix(Zp(2), 2, [2, 1, 1, 2])
409
+ sage: G = Matrix.block_diagonal([W1, V, V, 2*W1, 2*W1, 8*V, 8*W1, 16*V])
410
+ sage: _get_homogeneous_block_indices(G)
411
+ ([0, 5, 7, 10], [0, 1, 3, 4])
412
+ sage: G = Matrix.block_diagonal([W1, V, V, 2*W1, 2*W1, 8*V, 8*W1, 16*W1])
413
+ sage: _get_homogeneous_block_indices(G)
414
+ ([0, 5, 7, 10], [0, 1, 3, 4])
415
+ """
416
+ L = []
417
+ vals = []
418
+ n = G.ncols()
419
+ i = 0
420
+ val = -5
421
+ while i < n - 1:
422
+ if G[i, i + 1] != 0:
423
+ m = G[i, i + 1].valuation()
424
+ else:
425
+ m = G[i, i].valuation()
426
+ if m > val:
427
+ L.append(i)
428
+ val = m
429
+ vals.append(val)
430
+ if G[i, i + 1] != 0:
431
+ i += 1
432
+ i += 1
433
+ if i == n - 1:
434
+ m = G[i, i].valuation()
435
+ if m > val:
436
+ L.append(i)
437
+ val = m
438
+ vals.append(val)
439
+ return L, vals
440
+
441
+
442
+ def _homogeneous_normal_form(G, w):
443
+ r"""
444
+ Return the homogeneous normal form of the homogeneous ``G``.
445
+
446
+ INPUT:
447
+
448
+ - ``G`` -- a modular symmetric matrix over the `2`-adic integers
449
+ in partial normal form
450
+
451
+ OUTPUT:
452
+
453
+ - ``B`` -- an invertible matrix over the basering of ``G``
454
+ such that ``B*G*B.T`` is in homogeneous normal form
455
+
456
+ EXAMPLES::
457
+
458
+ sage: from sage.quadratic_forms.genera.normal_form import _homogeneous_normal_form
459
+ sage: R = Zp(2, type='fixed-mod', print_mode='terse', show_prec=False)
460
+ sage: U = Matrix(R, 2, [0,1,1,0])
461
+ sage: V = Matrix(R, 2, [2,1,1,2])
462
+ sage: W1 = Matrix(R, 1, [1])
463
+ sage: W3 = Matrix(R, 1, [3])
464
+ sage: W5 = Matrix(R, 1, [5])
465
+ sage: W7 = Matrix(R, 1, [7])
466
+ sage: G = Matrix.block_diagonal([V, W1])
467
+ sage: B = _homogeneous_normal_form(G, 1)[1]
468
+ sage: B * G * B.T
469
+ [2 1 0]
470
+ [1 2 0]
471
+ [0 0 1]
472
+ sage: G = Matrix.block_diagonal([V, W1, W3])
473
+ sage: B = _homogeneous_normal_form(G, 2)[1]
474
+ sage: B * G * B.T
475
+ [2 1 0 0]
476
+ [1 2 0 0]
477
+ [0 0 1 0]
478
+ [0 0 0 3]
479
+ sage: G = Matrix.block_diagonal([U, V, W1, W5])
480
+ sage: B = _homogeneous_normal_form(G, 2)[1]
481
+ sage: B * G * B.T
482
+ [0 1 0 0 0 0]
483
+ [1 0 0 0 0 0]
484
+ [0 0 0 1 0 0]
485
+ [0 0 1 0 0 0]
486
+ [0 0 0 0 7 0]
487
+ [0 0 0 0 0 7]
488
+ sage: G = Matrix.block_diagonal([U, W7, W3])
489
+ sage: B = _homogeneous_normal_form(G, 2)[1]
490
+ sage: B * G * B.T
491
+ [0 1 0 0]
492
+ [1 0 0 0]
493
+ [0 0 3 0]
494
+ [0 0 0 7]
495
+ sage: G = Matrix.block_diagonal([V, W5, W5])
496
+ sage: B = _homogeneous_normal_form(G, 2)[1]
497
+ sage: B * G * B.T
498
+ [0 1 0 0]
499
+ [1 0 0 0]
500
+ [0 0 3 0]
501
+ [0 0 0 7]
502
+ sage: G = Matrix.block_diagonal([V, W3, W3])
503
+ sage: B = _homogeneous_normal_form(G, 2)[1]
504
+ sage: B * G * B.T
505
+ [0 1 0 0]
506
+ [1 0 0 0]
507
+ [0 0 1 0]
508
+ [0 0 0 5]
509
+ sage: G = Matrix.block_diagonal([V, W1, W3])
510
+ sage: B = _homogeneous_normal_form(G, 2)[1]
511
+ sage: B * G * B.T
512
+ [2 1 0 0]
513
+ [1 2 0 0]
514
+ [0 0 1 0]
515
+ [0 0 0 3]
516
+ sage: G = Matrix.block_diagonal([W3, W3])
517
+ sage: B = _homogeneous_normal_form(G, 2)[1]
518
+ sage: B * G * B.T
519
+ [7 0]
520
+ [0 7]
521
+ """
522
+ B = copy(G.parent().identity_matrix())
523
+ D = copy(G)
524
+ n = B.ncols()
525
+ if w == 2:
526
+ if n > 2 and D[-3, -3] != 0:
527
+ v = 2
528
+ else:
529
+ v = 0
530
+ if v == 2:
531
+ e1 = D[-2, -2].unit_part()
532
+ e2 = D[-1, -1].unit_part()
533
+ e = {e1, e2}
534
+ E = [{1, 3}, {1, 7}, {5, 7}, {3, 5}]
535
+ if e not in E:
536
+ B[-4:, :] = _relations(D[-4:, -4:], 5) * B[-4:, :]
537
+ D = B * G * B.T
538
+ e1 = D[-2, -2].unit_part()
539
+ e2 = D[-1, -1].unit_part()
540
+ e = {e1, e2}
541
+ E = [{3}, {3, 5}, {5}, {5, 7}]
542
+ if e in E:
543
+ B[-2:, :] = _relations(D[-2:, -2:], 1) * B[-2:, :]
544
+ D = B * G * B.T
545
+ # assert that e1 < e2
546
+ e1 = D[-2, -2].unit_part()
547
+ e2 = D[-1, -1].unit_part()
548
+ if ZZ(e1) > ZZ(e2):
549
+ B.swap_rows(n - 1, n - 2)
550
+ D.swap_rows(n - 1, n - 2)
551
+ D.swap_columns(n - 1, n - 2)
552
+ return D, B
553
+
554
+
555
+ def _jordan_odd_adic(G):
556
+ r"""
557
+ Return the Jordan decomposition of a symmetric matrix over an odd prime.
558
+
559
+ INPUT:
560
+
561
+ - ``G`` -- a symmetric matrix over `\ZZ_p` of type ``'fixed-mod'``
562
+
563
+ OUTPUT:
564
+
565
+ - ``D`` -- a diagonal matrix
566
+ - ``B`` -- a unimodular matrix such that ``D = B * G * B.T``
567
+
568
+ EXAMPLES::
569
+
570
+ sage: from sage.quadratic_forms.genera.normal_form import _jordan_odd_adic
571
+ sage: R = Zp(3, prec=2, print_mode='terse', show_prec=False)
572
+ sage: A4 = Matrix(R,4,[2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2])
573
+ sage: A4
574
+ [2 8 0 0]
575
+ [8 2 8 0]
576
+ [0 8 2 8]
577
+ [0 0 8 2]
578
+ sage: D, B = _jordan_odd_adic(A4)
579
+ sage: D
580
+ [2 0 0 0]
581
+ [0 2 0 0]
582
+ [0 0 1 0]
583
+ [0 0 0 8]
584
+ sage: D == B*A4*B.T
585
+ True
586
+ sage: B.determinant().valuation() == 0
587
+ True
588
+ """
589
+ R = G.base_ring()
590
+ D = copy(G)
591
+ n = G.ncols()
592
+
593
+ # transformation matrix
594
+ B = Matrix.identity(R, n)
595
+
596
+ # indices of the diagonal entries which are already used
597
+ cnt = 0
598
+ minval = 0
599
+ while cnt < n:
600
+ pivot = _find_min_p(D, cnt, minval)
601
+ piv1 = pivot[1]
602
+ piv2 = pivot[2]
603
+ minval = pivot[0]
604
+ # the smallest valuation is on the diagonal
605
+ if piv1 == piv2:
606
+ # move pivot to position [cnt,cnt]
607
+ if piv1 != cnt:
608
+ B.swap_rows(cnt, piv1)
609
+ D.swap_rows(cnt, piv1)
610
+ D.swap_columns(cnt, piv1)
611
+ # we are already orthogonal to the part with i < cnt
612
+ # now make the rest orthogonal too
613
+ for i in range(cnt + 1, n):
614
+ if D[i, cnt] != 0:
615
+ c = D[i, cnt] // D[cnt, cnt]
616
+ B[i, :] += - c * B[cnt, :]
617
+ D[i, :] += - c * D[cnt, :]
618
+ D[:, i] += - c * D[:, cnt]
619
+ cnt = cnt + 1
620
+ else:
621
+ # the smallest valuation is off the diagonal
622
+ row = pivot[1]
623
+ col = pivot[2]
624
+ B[row, :] += B[col, :]
625
+ D[row, :] += D[col, :]
626
+ D[:, row] += D[:, col]
627
+ # the smallest valuation is now on the diagonal
628
+ return D, B
629
+
630
+
631
+ def _jordan_2_adic(G):
632
+ r"""
633
+ Transform a symmetric matrix over the `2`-adic integers into Jordan form.
634
+
635
+ Note that if the precision is too low, this method fails.
636
+ The method is only tested for input over `\ZZ_2` of ``'type=fixed-mod'``.
637
+
638
+ INPUT:
639
+
640
+ - ``G`` -- symmetric `n` by `n` matrix in `\ZZ_p`
641
+
642
+ OUTPUT:
643
+
644
+ - ``D`` -- the jordan matrix
645
+ - ``B`` -- transformation matrix, i.e, ``D = B * G * B^T``
646
+
647
+ The matrix ``D`` is a block diagonal matrix consisting
648
+ of `1` by `1` and `2` by `2` blocks.
649
+ The `2` by `2` blocks are matrices of the form
650
+ `[[2a, b], [b, 2c]] * 2^k`
651
+ with `b` of valuation `0`.
652
+
653
+ EXAMPLES::
654
+
655
+ sage: from sage.quadratic_forms.genera.normal_form import _jordan_2_adic
656
+ sage: R = Zp(2, prec=3, print_mode='terse', show_prec=False)
657
+ sage: A4 = Matrix(R, 4, [2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2])
658
+ sage: A4
659
+ [2 7 0 0]
660
+ [7 2 7 0]
661
+ [0 7 2 7]
662
+ [0 0 7 2]
663
+ sage: D, B = _jordan_2_adic(A4)
664
+ sage: D
665
+ [ 2 7 0 0]
666
+ [ 7 2 0 0]
667
+ [ 0 0 12 7]
668
+ [ 0 0 7 2]
669
+ sage: D == B*A4*B.T
670
+ True
671
+ sage: B.determinant().valuation() == 0
672
+ True
673
+ """
674
+ R = G.base_ring()
675
+ D = copy(G)
676
+ n = G.ncols()
677
+
678
+ # transformation matrix
679
+ B = Matrix.identity(R, n)
680
+
681
+ # indices of the diagonal entries which are already used
682
+ cnt = 0
683
+ minval = None
684
+ while cnt < n:
685
+ pivot = _find_min_p(D, cnt)
686
+ piv1 = pivot[1]
687
+ piv2 = pivot[2]
688
+ minval = pivot[0]
689
+ # the smallest valuation is on the diagonal
690
+ if piv1 == piv2:
691
+ # move pivot to position [cnt,cnt]
692
+ if piv1 != cnt:
693
+ B.swap_rows(cnt, piv1)
694
+ D.swap_rows(cnt, piv1)
695
+ D.swap_columns(cnt, piv1)
696
+ # we are already orthogonal to the part with i < cnt
697
+ # now make the rest orthogonal too
698
+ for i in range(cnt + 1, n):
699
+ if D[i, cnt] != 0:
700
+ c = D[i, cnt] // D[cnt, cnt]
701
+ B[i, :] += -c * B[cnt, :]
702
+ D[i, :] += -c * D[cnt, :]
703
+ D[:, i] += -c * D[:, cnt]
704
+ cnt = cnt + 1
705
+ # the smallest valuation is off the diagonal
706
+ else:
707
+ # move this 2 x 2 block to the top left (starting from cnt)
708
+ if piv1 != cnt:
709
+ B.swap_rows(cnt, piv1)
710
+ D.swap_rows(cnt, piv1)
711
+ D.swap_columns(cnt, piv1)
712
+ if piv2 != cnt + 1:
713
+ B.swap_rows(cnt + 1, piv2)
714
+ D.swap_rows(cnt + 1, piv2)
715
+ D.swap_columns(cnt + 1, piv2)
716
+ # we split off a 2 x 2 block
717
+ # if it is the last 2 x 2 block, there is nothing to do.
718
+ if cnt != n - 2:
719
+ content = R(2 ** minval)
720
+ eqn_mat = D[cnt:cnt+2, cnt:cnt+2].list()
721
+ eqn_mat = Matrix(R, 2, 2, [e // content for e in eqn_mat])
722
+ # calculate the inverse without using division
723
+ inv = eqn_mat.adjugate() * eqn_mat.det().inverse_of_unit()
724
+ B1 = B[cnt:cnt+2, :]
725
+ B2 = D[cnt+2:, cnt:cnt+2] * inv
726
+ for i in range(B2.nrows()):
727
+ for j in range(B2.ncols()):
728
+ B2[i, j] = B2[i, j] // content
729
+ B[cnt + 2:, :] -= B2 * B1
730
+ D[cnt:, cnt:] = B[cnt:, :] * G * B[cnt:, :].transpose()
731
+ cnt += 2
732
+ return D, B
733
+
734
+
735
+ def _min_nonsquare(p):
736
+ r"""
737
+ Return the minimal nonsquare modulo the prime `p`.
738
+
739
+ INPUT:
740
+
741
+ - ``p`` -- a prime number
742
+
743
+ EXAMPLES::
744
+
745
+ sage: from sage.quadratic_forms.genera.normal_form import _min_nonsquare
746
+ sage: _min_nonsquare(2)
747
+ sage: _min_nonsquare(3)
748
+ 2
749
+ sage: _min_nonsquare(5)
750
+ 2
751
+ sage: _min_nonsquare(7)
752
+ 3
753
+ """
754
+ for i in GF(p):
755
+ if not i.is_square():
756
+ return i
757
+
758
+
759
+ def _normalize(G, normal_odd=True):
760
+ r"""
761
+ Return the transformation to sums of forms of types `U`, `V` and `W`.
762
+
763
+ Part of the algorithm :meth:`p_adic_normal_form`.
764
+
765
+ INPUT:
766
+
767
+ - ``G`` -- a symmetric matrix over `\ZZ_p` in jordan form --
768
+ the output of :meth:`p_adic_normal_form` or :meth:`_jordan_2_adic`
769
+ - ``normal_odd`` -- boolean (default: ``True``); if ``True`` and `p` is odd,
770
+ compute a normal form
771
+
772
+ OUTPUT:
773
+
774
+ - ``(D, B)`` -- a pair of matrices such that ``D=B*G*B.T``
775
+ is a sum of forms of types `U`, `V` and `W` for `p=2` or
776
+ diagonal with diagonal entries equal `1` or `u`
777
+ where `u` is the smallest non-square modulo the odd prime `p`.
778
+
779
+ EXAMPLES::
780
+
781
+ sage: from sage.quadratic_forms.genera.normal_form import _normalize
782
+ sage: R = Zp(3, prec=5, type='fixed-mod', print_mode='series', show_prec=False)
783
+ sage: G = matrix.diagonal(R, [1,7,3,3*5,3,9,-9,27*13])
784
+ sage: D, B =_normalize(G)
785
+ sage: D
786
+ [ 1 0 0 0 0 0 0 0]
787
+ [ 0 1 0 0 0 0 0 0]
788
+ [ 0 0 3 0 0 0 0 0]
789
+ [ 0 0 0 3 0 0 0 0]
790
+ [ 0 0 0 0 2*3 0 0 0]
791
+ [ 0 0 0 0 0 3^2 0 0]
792
+ [ 0 0 0 0 0 0 2*3^2 0]
793
+ [ 0 0 0 0 0 0 0 3^3]
794
+ """
795
+ R = G.base_ring()
796
+ D = copy(G)
797
+ p = R.prime()
798
+ n = G.ncols()
799
+ B = copy(G.parent().identity_matrix())
800
+ if p != 2:
801
+ # squareclasses 1, v
802
+ v = _min_nonsquare(p)
803
+ v = R(v)
804
+ non_squares = []
805
+ val = 0
806
+ for i in range(n):
807
+ if D[i, i].valuation() > val:
808
+ # a new block starts
809
+ val = D[i, i].valuation()
810
+ if normal_odd and len(non_squares) != 0:
811
+ # move the non-square to
812
+ # the last entry of the previous block
813
+ j = non_squares.pop()
814
+ B.swap_rows(j, i - 1)
815
+ d = D[i, i].unit_part()
816
+ if d.is_square():
817
+ D[i, i] = 1
818
+ B[i, :] *= d.inverse_of_unit().sqrt()
819
+ else:
820
+ D[i, i] = v
821
+ B[i, :] *= (v * d.inverse_of_unit()).sqrt()
822
+ if normal_odd and len(non_squares) != 0:
823
+ # we combine two non-squares to get
824
+ # the 2 x 2 identity matrix
825
+ j = non_squares.pop()
826
+ trafo = _normalize_odd_2x2(D[[i, j], [i, j]])
827
+ B[[i, j], :] = trafo * B[[i, j], :]
828
+ D[i, i] = 1
829
+ D[j, j] = 1
830
+ else:
831
+ non_squares.append(i)
832
+ if normal_odd and non_squares:
833
+ j = non_squares.pop()
834
+ B.swap_rows(j, n - 1)
835
+ else:
836
+ # squareclasses 1,3,5,7 modulo 8
837
+ for i in range(n):
838
+ d = D[i, i].unit_part()
839
+ if d != 0:
840
+ v = R(mod(d, 8))
841
+ B[i, :] *= (v * d.inverse_of_unit()).sqrt()
842
+ D = B * G * B.T
843
+ for i in range(n - 1):
844
+ if D[i, i + 1] != 0: # there is a 2 x 2 block here
845
+ block = D[i:i+2, i:i+2]
846
+ trafo = _normalize_2x2(block)
847
+ B[i:i+2, :] = trafo * B[i:i+2, :]
848
+ D = B * G * B.T
849
+ return D, B
850
+
851
+
852
+ def _normalize_2x2(G):
853
+ r"""
854
+ Normalize this indecomposable `2` by `2` block.
855
+
856
+ INPUT:
857
+
858
+ - ``G`` -- a `2` by `2` matrix over `\ZZ_p`
859
+ with ``type='fixed-mod'`` of the form::
860
+
861
+ [2a b]
862
+ [ b 2c] * 2^n
863
+
864
+ with `b` of valuation 1.
865
+
866
+ OUTPUT:
867
+
868
+ A unimodular `2` by `2` matrix ``B`` over `\ZZ_p` with
869
+ ``B * G * B.transpose()``
870
+ either::
871
+
872
+ [0 1] [2 1]
873
+ [1 0] * 2^n or [1 2] * 2^n
874
+
875
+ EXAMPLES::
876
+
877
+ sage: from sage.quadratic_forms.genera.normal_form import _normalize_2x2
878
+ sage: R = Zp(2, prec=15, type='fixed-mod', print_mode='series', show_prec=False)
879
+ sage: G = Matrix(R, 2, [-17*2,3,3,23*2])
880
+ sage: B =_normalize_2x2(G)
881
+ sage: B * G * B.T
882
+ [2 1]
883
+ [1 2]
884
+
885
+ sage: G = Matrix(R, 2, [-17*4,3,3,23*2])
886
+ sage: B = _normalize_2x2(G)
887
+ sage: B*G*B.T
888
+ [0 1]
889
+ [1 0]
890
+
891
+ sage: G = 2^3 * Matrix(R, 2, [-17*2,3,3,23*2])
892
+ sage: B = _normalize_2x2(G)
893
+ sage: B * G * B.T
894
+ [2^4 2^3]
895
+ [2^3 2^4]
896
+ """
897
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
898
+ from sage.modules.free_module_element import vector
899
+ B = copy(G.parent().identity_matrix())
900
+ R = G.base_ring()
901
+ P = PolynomialRing(R, 'x')
902
+ x = P.gen()
903
+
904
+ # The input must be an even block
905
+ odd1 = (G[0, 0].valuation() < G[1, 0].valuation())
906
+ odd2 = (G[1, 1].valuation() < G[1, 0].valuation())
907
+ if odd1 or odd2:
908
+ raise ValueError("not a valid 2 x 2 block")
909
+ scale = 2 ** G[0, 1].valuation()
910
+ D = Matrix(R, 2, 2, [d // scale for d in G.list()])
911
+ # now D is of the form
912
+ # [2a b ]
913
+ # [b 2c]
914
+ # where b has valuation 1.
915
+ G = copy(D)
916
+
917
+ # Make sure G[1, 1] has valuation 1.
918
+ if D[1, 1].valuation() > D[0, 0].valuation():
919
+ B.swap_columns(0, 1)
920
+ D.swap_columns(0, 1)
921
+ D.swap_rows(0, 1)
922
+ if D[1, 1].valuation() != 1:
923
+ # this works because
924
+ # D[0, 0] has valuation at least 2
925
+ B[1, :] += B[0, :]
926
+ D = B * G * B.transpose()
927
+ assert D[1, 1].valuation() == 1
928
+
929
+ if mod(D.det(), 8) == 3:
930
+ # in this case we can transform D to
931
+ # 2 1
932
+ # 1 2
933
+ # Find a point of norm 2
934
+ # solve: 2 == D[1,1]*x^2 + 2*D[1,0]*x + D[0,0]
935
+ pol = (D[1, 1] * x**2 + 2 * D[1, 0] * x + D[0, 0] - 2) // 2
936
+ # somehow else pari can get a hickup see trac #24065
937
+ pol = pol // pol.leading_coefficient()
938
+ sol = pol.roots()[0][0]
939
+ B[0, 1] = sol
940
+ D = B * G * B.transpose()
941
+ # make D[0, 1] = 1
942
+ B[1, :] *= D[1, 0].inverse_of_unit()
943
+ D = B * G * B.transpose()
944
+
945
+ # solve: v*D*v == 2 with v = (x, -2*x+1)
946
+ if D[1, 1] != 2:
947
+ v = vector([x, -2 * x + 1])
948
+ pol = (v * D * v - 2) // 2
949
+ # somehow else pari can get a hickup see trac #24065
950
+ pol = pol // pol.leading_coefficient()
951
+ sol = pol.roots()[0][0]
952
+ B[1, :] = sol * B[0, :] + (-2 * sol + 1) * B[1, :]
953
+ D = B * G * B.transpose()
954
+ # check the result
955
+ assert D == Matrix(G.parent(), 2, 2, [2, 1, 1, 2]), "D1 \n %r" % D
956
+ elif mod(D.det(), 8) == 7:
957
+ # in this case we can transform D to
958
+ # 0 1
959
+ # 1 0
960
+ # Find a point representing 0
961
+ # solve: 0 == D[1,1]*x^2 + 2*D[1,0]*x + D[0,0]
962
+ pol = (D[1, 1] * x**2 + 2 * D[1, 0] * x + D[0, 0]) // 2
963
+ # somehow else pari can get a hickup, see trac #24065
964
+ pol = pol // pol.leading_coefficient()
965
+ sol = pol.roots()[0][0]
966
+ B[0, :] += sol * B[1, :]
967
+ D = B * G * B.transpose()
968
+ # make the second basis vector have 0 square as well.
969
+ B[1, :] = B[1, :] - D[1, 1] // (2 * D[0, 1]) * B[0, :]
970
+ D = B * G * B.transpose()
971
+ # rescale to get D[0,1] = 1
972
+ B[0, :] *= D[1, 0].inverse_of_unit()
973
+ D = B * G * B.transpose()
974
+ # check the result
975
+ assert D == Matrix(G.parent(), 2, 2, [0, 1, 1, 0]), "D2 \n %r" % D
976
+ return B
977
+
978
+
979
+ def _normalize_odd_2x2(G):
980
+ r"""
981
+ Normalize this `2` by `2` block.
982
+
983
+ INPUT:
984
+
985
+ - ``G`` -- a multiple of the `2` by `2` identity_matrix
986
+ over the `p`-adics for `p` odd
987
+
988
+ OUTPUT:
989
+
990
+ A transformation matrix ``B`` such that ``B * G * B.T`` is the identity
991
+ matrix.
992
+
993
+ EXAMPLES::
994
+
995
+ sage: from sage.quadratic_forms.genera.normal_form import _normalize_odd_2x2
996
+ sage: R = Zp(5, type='fixed-mod', print_mode='terse', show_prec=False)
997
+ sage: G = 2 * Matrix.identity(R, 2)
998
+ sage: B = _normalize_odd_2x2(G)
999
+ sage: B*G*B.T
1000
+ [1 0]
1001
+ [0 1]
1002
+ """
1003
+ assert G[0, 0] == G[1, 1]
1004
+ u = G[0, 0]
1005
+ y = G.base_ring().zero()
1006
+ while not (1 / u - y**2).is_square():
1007
+ y += 1
1008
+ x = (1 / u - y**2).sqrt()
1009
+ B = copy(G.parent().identity_matrix())
1010
+ B[0, 0] = x
1011
+ B[0, 1] = y
1012
+ B[1, 0] = y
1013
+ B[1, 1] = -x
1014
+ return B
1015
+
1016
+
1017
+ def _partial_normal_form_of_block(G):
1018
+ r"""
1019
+ Return the partial normal form of the homogeneous block ``G``.
1020
+
1021
+ For internal use in :meth:`_two_adic_normal_forms`.
1022
+
1023
+ INPUT:
1024
+
1025
+ - ``G`` -- a modular symmetric matrix over the `2`-adic integers
1026
+
1027
+ OUTPUT:
1028
+
1029
+ - ``D``, ``B``, ``w`` -- with ``B`` a transformation matrix such that
1030
+ ``B * G * B.T`` is in partial normal form
1031
+ and `w = 0, 1, 2` is the size of the part consisting of forms of type W
1032
+
1033
+ EXAMPLES::
1034
+
1035
+ sage: from sage.quadratic_forms.genera.normal_form import _partial_normal_form_of_block
1036
+ sage: R = Zp(2, prec=4, type='fixed-mod', print_mode='terse', show_prec=False)
1037
+ sage: U = Matrix(R, 2, [0,1,1,0])
1038
+ sage: V = Matrix(R, 2, [2,1,1,2])
1039
+ sage: W1 = Matrix(R, 1, [1])
1040
+ sage: W3 = Matrix(R, 1, [3])
1041
+ sage: W5 = Matrix(R, 1, [5])
1042
+ sage: W7 = Matrix(R, 1, [7])
1043
+ sage: G = Matrix.block_diagonal([W1, U, V, W5, V, W3, V, W7])
1044
+ sage: B = _partial_normal_form_of_block(G)[1]
1045
+ sage: B * G * B.T
1046
+ [0 1 0 0 0 0 0 0 0 0 0 0]
1047
+ [1 0 0 0 0 0 0 0 0 0 0 0]
1048
+ [0 0 0 1 0 0 0 0 0 0 0 0]
1049
+ [0 0 1 0 0 0 0 0 0 0 0 0]
1050
+ [0 0 0 0 0 1 0 0 0 0 0 0]
1051
+ [0 0 0 0 1 0 0 0 0 0 0 0]
1052
+ [0 0 0 0 0 0 0 1 0 0 0 0]
1053
+ [0 0 0 0 0 0 1 0 0 0 0 0]
1054
+ [0 0 0 0 0 0 0 0 2 1 0 0]
1055
+ [0 0 0 0 0 0 0 0 1 2 0 0]
1056
+ [0 0 0 0 0 0 0 0 0 0 1 0]
1057
+ [0 0 0 0 0 0 0 0 0 0 0 7]
1058
+ sage: G = Matrix.block_diagonal([W1, U, V, W1, V, W1, V, W7])
1059
+ sage: B = _partial_normal_form_of_block(G)[1]
1060
+ sage: B * G * B.T
1061
+ [0 1 0 0 0 0 0 0 0 0 0 0]
1062
+ [1 0 0 0 0 0 0 0 0 0 0 0]
1063
+ [0 0 0 1 0 0 0 0 0 0 0 0]
1064
+ [0 0 1 0 0 0 0 0 0 0 0 0]
1065
+ [0 0 0 0 0 1 0 0 0 0 0 0]
1066
+ [0 0 0 0 1 0 0 0 0 0 0 0]
1067
+ [0 0 0 0 0 0 0 1 0 0 0 0]
1068
+ [0 0 0 0 0 0 1 0 0 0 0 0]
1069
+ [0 0 0 0 0 0 0 0 0 1 0 0]
1070
+ [0 0 0 0 0 0 0 0 1 0 0 0]
1071
+ [0 0 0 0 0 0 0 0 0 0 3 0]
1072
+ [0 0 0 0 0 0 0 0 0 0 0 7]
1073
+ """
1074
+ D = copy(G)
1075
+ n = D.ncols()
1076
+ B = copy(G.parent().identity_matrix()) # the transformation matrix
1077
+ blocks = _get_small_block_indices(D)
1078
+ # collect the indices of forms of types U, V and W
1079
+ U = []
1080
+ V = []
1081
+ W = []
1082
+ for i in blocks:
1083
+ if i + 1 in blocks or i == n - 1:
1084
+ W.append(i)
1085
+ else:
1086
+ if D[i, i] != 0:
1087
+ V += [i, i + 1]
1088
+ else:
1089
+ U += [i, i + 1]
1090
+ if len(W) == 3:
1091
+ # W W W transforms to W U or W V
1092
+ B[W, :] = _relations(D[W, W], 2) * B[W, :]
1093
+ D = B * G * B.T
1094
+ if mod(D[W[1:], W[1:]].det().unit_part(), 8) == 3:
1095
+ V += W[1:]
1096
+ else:
1097
+ U += W[1:]
1098
+ W = W[:1]
1099
+ if len(V) == 4:
1100
+ B[V, :] = _relations(D[V, V], 3) * B[V, :]
1101
+ U += V
1102
+ V = []
1103
+ D = B * G * B.T
1104
+ # put everything into the right order
1105
+ UVW = U + V + W
1106
+ B = B[UVW, :]
1107
+ D = B * G * B.T
1108
+ return D, B, len(W)
1109
+
1110
+
1111
+ def _relations(G, n):
1112
+ r"""
1113
+ Return relations of `2`-adic quadratic forms.
1114
+
1115
+ See [MirMor2009]_ IV Prop. 3.2. This function is for internal use only.
1116
+
1117
+ INPUT:
1118
+
1119
+ - ``n`` -- integer between 1 and 10 -- the number of the relation
1120
+ - ``G`` -- a block diagonal matrix consisting of blocks of types `U, V, W`
1121
+ the left side of the relation. If ``G`` does not match `n` then the
1122
+ results are unpredictable.
1123
+
1124
+ OUTPUT:
1125
+
1126
+ Square matrix ``B`` such that ``B * G * B.T`` is the right side of the
1127
+ relation which consists of blocks of types `U`, `V`, `W` again.
1128
+
1129
+ EXAMPLES::
1130
+
1131
+ sage: from sage.quadratic_forms.genera.normal_form import _relations
1132
+ sage: R = Zp(2, type='fixed-mod', print_mode='terse', show_prec=False)
1133
+ sage: U = Matrix(R, 2, [0,1,1,0])
1134
+ sage: V = Matrix(R, 2, [2,1,1,2])
1135
+ sage: W1 = Matrix(R, 1, [1])
1136
+ sage: W3 = Matrix(R, 1, [3])
1137
+ sage: W5 = Matrix(R, 1, [5])
1138
+ sage: W7 = Matrix(R, 1, [7])
1139
+ sage: G = Matrix.block_diagonal(W1,W1)
1140
+ sage: b = _relations(G,1)
1141
+ sage: b * G * b.T
1142
+ [5 0]
1143
+ [0 5]
1144
+ sage: G = Matrix.block_diagonal(W1,W3)
1145
+ sage: b = _relations(G,1)
1146
+ sage: b * G * b.T
1147
+ [5 0]
1148
+ [0 7]
1149
+ sage: G = Matrix.block_diagonal(W1,W5)
1150
+ sage: b = _relations(G,1)
1151
+ sage: b * G * b.T
1152
+ [5 0]
1153
+ [0 1]
1154
+ sage: G = Matrix.block_diagonal(W1,W7)
1155
+ sage: b = _relations(G,1)
1156
+ sage: b * G * b.T
1157
+ [5 0]
1158
+ [0 3]
1159
+ sage: G = Matrix.block_diagonal(W3,W3)
1160
+ sage: b = _relations(G,1)
1161
+ sage: b * G * b.T
1162
+ [7 0]
1163
+ [0 7]
1164
+ sage: G = Matrix.block_diagonal(W3,W5)
1165
+ sage: b = _relations(G,1)
1166
+ sage: b * G * b.T
1167
+ [7 0]
1168
+ [0 1]
1169
+ sage: G = Matrix.block_diagonal(W3,W7)
1170
+ sage: b = _relations(G,1)
1171
+ sage: b * G * b.T
1172
+ [7 0]
1173
+ [0 3]
1174
+ sage: G = Matrix.block_diagonal(W5,W5)
1175
+ sage: b = _relations(G,1)
1176
+ sage: b * G * b.T
1177
+ [1 0]
1178
+ [0 1]
1179
+ sage: G = Matrix.block_diagonal(W5,W7)
1180
+ sage: b = _relations(G,1)
1181
+ sage: b * G * b.T
1182
+ [1 0]
1183
+ [0 3]
1184
+ sage: G = Matrix.block_diagonal(W7,W7)
1185
+ sage: b = _relations(G,1)
1186
+ sage: b * G * b.T
1187
+ [3 0]
1188
+ [0 3]
1189
+ sage: G = Matrix.block_diagonal([V,V])
1190
+ sage: b = _relations(G,3)
1191
+ sage: b * G * b.T
1192
+ [0 1 0 0]
1193
+ [1 0 0 0]
1194
+ [0 0 0 1]
1195
+ [0 0 1 0]
1196
+ sage: G = Matrix.block_diagonal([V,W1,W1])
1197
+ sage: b = _relations(G,5)
1198
+ sage: b * G * b.T
1199
+ [0 1 0 0]
1200
+ [1 0 0 0]
1201
+ [0 0 7 0]
1202
+ [0 0 0 3]
1203
+ sage: G = Matrix.block_diagonal([V,W1,W5])
1204
+ sage: b = _relations(G,5)
1205
+ sage: b * G * b.T
1206
+ [0 1 0 0]
1207
+ [1 0 0 0]
1208
+ [0 0 3 0]
1209
+ [0 0 0 3]
1210
+ sage: G = Matrix.block_diagonal([V,W3,W7])
1211
+ sage: b = _relations(G,5)
1212
+ sage: b * G * b.T
1213
+ [0 1 0 0]
1214
+ [1 0 0 0]
1215
+ [0 0 5 0]
1216
+ [0 0 0 5]
1217
+ sage: G = Matrix.block_diagonal([W1,2*W1])
1218
+ sage: b = _relations(G,6)
1219
+ sage: b * G * b.T
1220
+ [3 0]
1221
+ [0 6]
1222
+ sage: G = Matrix.block_diagonal([W1,2*W3])
1223
+ sage: b = _relations(G,6)
1224
+ sage: b * G * b.T
1225
+ [ 7 0]
1226
+ [ 0 10]
1227
+ sage: G = Matrix.block_diagonal([W1,2*W5])
1228
+ sage: b = _relations(G,6)
1229
+ sage: b * G * b.T
1230
+ [ 3 0]
1231
+ [ 0 14]
1232
+ sage: G = Matrix.block_diagonal([W1,2*W7])
1233
+ sage: b = _relations(G,6)
1234
+ sage: b * G * b.T
1235
+ [7 0]
1236
+ [0 2]
1237
+ sage: G = Matrix.block_diagonal([W3,2*W5])
1238
+ sage: b = _relations(G,6)
1239
+ sage: b * G * b.T
1240
+ [5 0]
1241
+ [0 6]
1242
+ sage: G = Matrix.block_diagonal([W3,2*W3])
1243
+ sage: b = _relations(G,6)
1244
+ sage: b * G * b.T
1245
+ [1 0]
1246
+ [0 2]
1247
+ sage: G = Matrix.block_diagonal([2*W5,4*W7])
1248
+ sage: b = _relations(G,6)
1249
+ sage: b * G * b.T
1250
+ [6 0]
1251
+ [0 4]
1252
+ sage: G = Matrix.block_diagonal([W3,2*V])
1253
+ sage: b = _relations(G,7)
1254
+ sage: b * G * b.T
1255
+ [7 0 0]
1256
+ [0 0 2]
1257
+ [0 2 0]
1258
+ sage: G = Matrix.block_diagonal([W7,2*V])
1259
+ sage: b = _relations(G,7)
1260
+ sage: b * G * b.T
1261
+ [3 0 0]
1262
+ [0 0 2]
1263
+ [0 2 0]
1264
+ sage: G = Matrix.block_diagonal([U,2*W1])
1265
+ sage: b = _relations(G,8)
1266
+ sage: b * G * b.T
1267
+ [ 2 1 0]
1268
+ [ 1 2 0]
1269
+ [ 0 0 10]
1270
+ sage: G = Matrix.block_diagonal([U,2*W5])
1271
+ sage: b = _relations(G,8)
1272
+ sage: b * G * b.T
1273
+ [2 1 0]
1274
+ [1 2 0]
1275
+ [0 0 2]
1276
+ sage: G = Matrix.block_diagonal([V,2*W1])
1277
+ sage: b = _relations(G,8)
1278
+ sage: b * G * b.T
1279
+ [ 0 1 0]
1280
+ [ 1 0 0]
1281
+ [ 0 0 10]
1282
+ sage: G = Matrix.block_diagonal([V,2*W7])
1283
+ sage: b = _relations(G,8)
1284
+ sage: b * G * b.T
1285
+ [0 1 0]
1286
+ [1 0 0]
1287
+ [0 0 6]
1288
+ sage: G = Matrix.block_diagonal([W1,W5,2*W5])
1289
+ sage: b = _relations(G,9)
1290
+ sage: b * G * b.T
1291
+ [3 0 0]
1292
+ [0 3 0]
1293
+ [0 0 2]
1294
+ sage: G = Matrix.block_diagonal([W3,W3,2*W5])
1295
+ sage: b = _relations(G,9)
1296
+ sage: b * G * b.T
1297
+ [5 0 0]
1298
+ [0 1 0]
1299
+ [0 0 2]
1300
+ sage: G = Matrix.block_diagonal([W3,W3,2*W1])
1301
+ sage: b = _relations(G,9)
1302
+ sage: b * G * b.T
1303
+ [ 5 0 0]
1304
+ [ 0 1 0]
1305
+ [ 0 0 10]
1306
+ sage: G = Matrix.block_diagonal([W3,4*W1])
1307
+ sage: b = _relations(G,10)
1308
+ sage: b * G * b.T
1309
+ [ 7 0]
1310
+ [ 0 20]
1311
+ sage: G = Matrix.block_diagonal([W5,4*W5])
1312
+ sage: b = _relations(G,10)
1313
+ sage: b * G * b.T
1314
+ [1 0]
1315
+ [0 4]
1316
+ """
1317
+ R = G.base_ring()
1318
+ if n == 1:
1319
+ e1 = G[0, 0].unit_part()
1320
+ e2 = G[1, 1].unit_part()
1321
+ B = Matrix(R, 2, 2, [1, 2, 2 * e2, -e1])
1322
+ elif n == 2:
1323
+ e1 = G[0, 0].unit_part()
1324
+ e2 = G[1, 1].unit_part()
1325
+ e3 = G[2, 2].unit_part()
1326
+ B = Matrix(R, 3, 3, [1, 1, 1, e2, -e1, 0, e3, 0, -e1])
1327
+ elif n == 3:
1328
+ B = Matrix(R, 4, 4,
1329
+ [1, 1, 1, 0, 1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, -1])
1330
+ elif n == 4:
1331
+ raise NotImplementedError("relation 4 is not needed")
1332
+ elif n == 5:
1333
+ e1 = G[2, 2].unit_part()
1334
+ e2 = G[3, 3].unit_part()
1335
+ if mod(e1, 4) != mod(e2, 4):
1336
+ raise ValueError("W is of the wrong type for relation 5")
1337
+ B = Matrix(R, 4, [1, 0, 1, 1,
1338
+ 0, 1, 1, 1,
1339
+ -e2, -e2, 0, 3,
1340
+ -e1, -e1, 2 * e2 + 3, -2 * e1])
1341
+ elif n == 6:
1342
+ if G[0, 0].valuation() + 1 != G[1, 1].valuation():
1343
+ raise ValueError("wrong scales for relation 6")
1344
+ e1 = G[0, 0].unit_part()
1345
+ e2 = G[1, 1].unit_part()
1346
+ B = Matrix(R, 2, 2, [1, 1, -2 * e2, e1])
1347
+ elif n == 7:
1348
+ e = G[0, 0].unit_part()
1349
+ B = Matrix(R, 3, 3, [-3, e**2, e**2, 2 * e, 1, 0, 2 * e, 0, 1])
1350
+ elif n == 8:
1351
+ e = G[2, 2].unit_part()
1352
+ if G[0, 0] == 0:
1353
+ B = Matrix(R, 3, 3, [e, 0, -1,
1354
+ 0, e, -1,
1355
+ 2, 2, 1])
1356
+ else:
1357
+ B = Matrix(R, 3, 3, [1, 0, 1,
1358
+ 0, 1, 1,
1359
+ 2 * e, 2 * e, - 3])
1360
+ elif n == 9:
1361
+ e1 = G[0, 0].unit_part()
1362
+ e2 = G[1, 1].unit_part()
1363
+ e3 = G[2, 2].unit_part()
1364
+ B = Matrix(R, 3, 3, [1, 0, 1,
1365
+ 2 * e3, 1, -e1,
1366
+ -2 * e2 * e3, 2 * e1**2 * e3 + 4 * e1 * e3**2,
1367
+ e1 * e2])
1368
+ elif n == 10:
1369
+ e1 = G[0, 0].unit_part()
1370
+ e2 = G[1, 1].unit_part()
1371
+ B = Matrix(R, 2, 2, [1, 1, -4 * e2, e1])
1372
+ _, B1 = _normalize(B * G * B.T)
1373
+ return B1 * B
1374
+
1375
+
1376
+ def _two_adic_normal_forms(G, partial=False):
1377
+ r"""
1378
+ Return the 2-adic normal form of a symmetric matrix.
1379
+
1380
+ INPUT:
1381
+
1382
+ - ``G`` -- block diagonal matrix with blocks of type `U`, `V`, `W`
1383
+ - ``partial`` -- boolean (default: ``False``)
1384
+
1385
+ OUTPUT: ``D``, ``B``; such that ``D = B * G * B.T``
1386
+
1387
+ EXAMPLES::
1388
+
1389
+ sage: from sage.quadratic_forms.genera.normal_form import _two_adic_normal_forms
1390
+ sage: R = Zp(2, type='fixed-mod', print_mode='terse', show_prec=False)
1391
+ sage: U = Matrix(R, 2, [0,1,1,0])
1392
+ sage: V = Matrix(R, 2, [2,1,1,2])
1393
+ sage: W1 = Matrix(R, 1, [1])
1394
+ sage: W3 = Matrix(R, 1, [3])
1395
+ sage: W5 = Matrix(R, 1, [5])
1396
+ sage: W7 = Matrix(R, 1, [7])
1397
+ sage: G = Matrix.block_diagonal([2*W1,2*W1,4*V])
1398
+ sage: B = _two_adic_normal_forms(G)[1]
1399
+ sage: B * G * B.T
1400
+ [ 2 0 0 0]
1401
+ [ 0 10 0 0]
1402
+ [ 0 0 0 4]
1403
+ [ 0 0 4 0]
1404
+ sage: G = Matrix.block_diagonal([W1,2*V,2*W3,2*W5])
1405
+ sage: B = _two_adic_normal_forms(G)[1]
1406
+ sage: B * G * B.T
1407
+ [3 0 0 0 0]
1408
+ [0 0 2 0 0]
1409
+ [0 2 0 0 0]
1410
+ [0 0 0 2 0]
1411
+ [0 0 0 0 2]
1412
+ sage: G = Matrix.block_diagonal([U,2*V,2*W3,2*W5])
1413
+ sage: B = _two_adic_normal_forms(G)[1]
1414
+ sage: B * G * B.T
1415
+ [2 1 0 0 0 0]
1416
+ [1 2 0 0 0 0]
1417
+ [0 0 4 2 0 0]
1418
+ [0 0 2 4 0 0]
1419
+ [0 0 0 0 2 0]
1420
+ [0 0 0 0 0 6]
1421
+ """
1422
+ B = copy(G.parent().identity_matrix())
1423
+ h, scales = _get_homogeneous_block_indices(G)
1424
+ h.append(B.ncols())
1425
+ # UVlist[k] is a list of indices of the block of scale p^k.
1426
+ # It contains the indices of the part of types U or V.
1427
+ # So it may be empty.
1428
+ UVlist = [[], []] # empty lists are appended to avoid special cases.
1429
+ # same as UVlist but contains the indices of the part of type W
1430
+ Wlist = [[], []]
1431
+ # homogeneous normal form for each part
1432
+ for k in range(scales[-1] - scales[0] + 1):
1433
+ if k + scales[0] in scales:
1434
+ i = scales.index(k + scales[0])
1435
+ Gk = G[h[i]:h[i + 1], h[i]:h[i + 1]]
1436
+ Dk, Bk, wk = _partial_normal_form_of_block(Gk)
1437
+ B[h[i]:h[i + 1], :] = Bk * B[h[i]:h[i + 1], :]
1438
+ if not partial:
1439
+ Dk, B1k = _homogeneous_normal_form(Dk, wk)
1440
+ B[h[i]:h[i + 1], :] = B1k * B[h[i]:h[i + 1], :]
1441
+ UVlist.append(list(range(h[i], h[i + 1] - wk)))
1442
+ Wlist.append(list(range(h[i + 1] - wk, h[i + 1])))
1443
+ else:
1444
+ UVlist.append([])
1445
+ Wlist.append([])
1446
+ D = B * G * B.T
1447
+ if partial:
1448
+ return D, B
1449
+ # use relations descending in k
1450
+ # we never leave partial normal form
1451
+ # but the homogeneous normal form may be destroyed
1452
+ # it is restored at the end.
1453
+ for k in range(len(UVlist) - 1, 2, -1):
1454
+ # setup notation
1455
+ W = Wlist[k]
1456
+ Wm = Wlist[k - 1]
1457
+ Wmm = Wlist[k - 2]
1458
+ UV = UVlist[k]
1459
+ UVm = UVlist[k - 1]
1460
+ V = UVlist[k][-2:]
1461
+ if V and D[V[0], V[0]] == 0:
1462
+ V = [] # it is U not V
1463
+ # condition b)
1464
+ if Wm:
1465
+ if len(V) == 2:
1466
+ R = Wm[:1] + V
1467
+ B[R, :] = _relations(D[R, R], 7) * B[R, :]
1468
+ V = []
1469
+ D = B * G * B.T
1470
+ E = {3, 7}
1471
+ for w in W:
1472
+ if D[w, w].unit_part() in E:
1473
+ R = Wm[:1] + [w]
1474
+ B[R, :] = _relations(D[R, R], 6) * B[R, :]
1475
+ D = B * G * B.T
1476
+ # condition c)
1477
+ # We want type a or W = []
1478
+ # modify D[w,w] to go from type b to type a
1479
+ x = [len(V)] + [ZZ(mod(w.unit_part(), 8)) for w in D[W, W].diagonal()]
1480
+ if len(x) == 3 and x[1] > x[2]:
1481
+ x[1], x[2] = x[2], x[1]
1482
+ # the first entry of x is either
1483
+ # 0 if there is no type V component or
1484
+ # 2 if there is a single type V component
1485
+ # a = [[0,1], [2,3], [2,5], [0,7], [0,1,1], [2,1,3], [0,7,7], [0,1,7]]
1486
+ b = [[0, 5], [2, 7], [2, 1], [0, 3],
1487
+ [0, 1, 5], [2, 1, 7], [0, 3, 7], [0, 1, 3]]
1488
+ if x in b:
1489
+ w = W[-1]
1490
+ if x == [0, 3, 7]:
1491
+ # relation 10 should be applied to 3 to stay in homogeneous normal form
1492
+ w = W[0]
1493
+ if UVm:
1494
+ R = UVm[-2:] + [w]
1495
+ B[R, :] = _relations(D[R, R], 8) * B[R, :]
1496
+ elif Wmm:
1497
+ R = Wmm[:1] + [w]
1498
+ B[R, :] = _relations(D[R, R], 10) * B[R, :]
1499
+ elif len(Wm) == 2:
1500
+ e0 = D[Wm, Wm][0, 0].unit_part()
1501
+ e1 = D[Wm, Wm][1, 1].unit_part()
1502
+ if mod(e1 - e0, 4) == 0:
1503
+ R = Wm + [w]
1504
+ B[R, :] = _relations(D[R, R], 9) * B[R, :]
1505
+ D = B * G * B.T
1506
+ # condition a) - stay in homogeneous normal form
1507
+ R = UV + W
1508
+ Dk = D[R, R]
1509
+ Bk = _homogeneous_normal_form(Dk, len(W))[1]
1510
+ B[R, :] = Bk * B[R, :]
1511
+ D = B * G * B.T
1512
+ # we need to restore the homogeneous normal form of k-1
1513
+ if Wm:
1514
+ R = UVm + Wm
1515
+ Dkm = D[R, R]
1516
+ Bkm = _homogeneous_normal_form(Dkm, len(Wm))[1]
1517
+ B[R, :] = Bkm * B[R, :]
1518
+ D = B * G * B.T
1519
+ return D, B