passagemath-flint 10.6.1rc10__cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_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.
Files changed (361) hide show
  1. passagemath_flint-10.6.1rc10.dist-info/METADATA +122 -0
  2. passagemath_flint-10.6.1rc10.dist-info/RECORD +361 -0
  3. passagemath_flint-10.6.1rc10.dist-info/WHEEL +6 -0
  4. passagemath_flint-10.6.1rc10.dist-info/top_level.txt +2 -0
  5. passagemath_flint.libs/libflint-aecb9cc5.so.21.0.0 +0 -0
  6. passagemath_flint.libs/libgf2x-a4cdec90.so.3.0.0 +0 -0
  7. passagemath_flint.libs/libgfortran-8f1e9814.so.5.0.0 +0 -0
  8. passagemath_flint.libs/libgmp-6e109695.so.10.5.0 +0 -0
  9. passagemath_flint.libs/libgsl-cda90e79.so.28.0.0 +0 -0
  10. passagemath_flint.libs/libmpfi-e3c25853.so.0.0.0 +0 -0
  11. passagemath_flint.libs/libmpfr-82690d50.so.6.2.1 +0 -0
  12. passagemath_flint.libs/libntl-74e7d9a3.so.44.0.1 +0 -0
  13. passagemath_flint.libs/libopenblasp-r0-6dcb67f9.3.29.so +0 -0
  14. passagemath_flint.libs/libquadmath-828275a7.so.0.0.0 +0 -0
  15. sage/all__sagemath_flint.py +29 -0
  16. sage/combinat/all__sagemath_flint.py +1 -0
  17. sage/combinat/posets/all__sagemath_flint.py +1 -0
  18. sage/combinat/posets/hasse_cython_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  19. sage/combinat/posets/hasse_cython_flint.pyx +194 -0
  20. sage/data_structures/all__sagemath_flint.py +1 -0
  21. sage/data_structures/bounded_integer_sequences.cpython-312-x86_64-linux-gnu.so +0 -0
  22. sage/data_structures/bounded_integer_sequences.pxd +62 -0
  23. sage/data_structures/bounded_integer_sequences.pyx +1418 -0
  24. sage/graphs/all__sagemath_flint.py +1 -0
  25. sage/graphs/chrompoly.cpython-312-x86_64-linux-gnu.so +0 -0
  26. sage/graphs/chrompoly.pyx +555 -0
  27. sage/graphs/matchpoly.cpython-312-x86_64-linux-gnu.so +0 -0
  28. sage/graphs/matchpoly.pyx +412 -0
  29. sage/libs/all__sagemath_flint.py +17 -0
  30. sage/libs/arb/__init__.py +1 -0
  31. sage/libs/arb/acb.pxd +154 -0
  32. sage/libs/arb/acb_calc.pxd +9 -0
  33. sage/libs/arb/acb_elliptic.pxd +25 -0
  34. sage/libs/arb/acb_hypgeom.pxd +74 -0
  35. sage/libs/arb/acb_mat.pxd +62 -0
  36. sage/libs/arb/acb_modular.pxd +17 -0
  37. sage/libs/arb/acb_poly.pxd +216 -0
  38. sage/libs/arb/arb.pxd +240 -0
  39. sage/libs/arb/arb_fmpz_poly.pxd +21 -0
  40. sage/libs/arb/arb_hypgeom.pxd +83 -0
  41. sage/libs/arb/arb_wrap.h +34 -0
  42. sage/libs/arb/arf.pxd +131 -0
  43. sage/libs/arb/arith.cpython-312-x86_64-linux-gnu.so +0 -0
  44. sage/libs/arb/arith.pyx +87 -0
  45. sage/libs/arb/bernoulli.pxd +6 -0
  46. sage/libs/arb/mag.pxd +77 -0
  47. sage/libs/arb/types.pxd +37 -0
  48. sage/libs/flint/__init__.py +1 -0
  49. sage/libs/flint/acb.pxd +270 -0
  50. sage/libs/flint/acb_calc.pxd +22 -0
  51. sage/libs/flint/acb_dft.pxd +51 -0
  52. sage/libs/flint/acb_dirichlet.pxd +112 -0
  53. sage/libs/flint/acb_elliptic.pxd +42 -0
  54. sage/libs/flint/acb_hypgeom.pxd +169 -0
  55. sage/libs/flint/acb_macros.pxd +9 -0
  56. sage/libs/flint/acb_mat.pxd +136 -0
  57. sage/libs/flint/acb_mat_macros.pxd +10 -0
  58. sage/libs/flint/acb_modular.pxd +62 -0
  59. sage/libs/flint/acb_poly.pxd +251 -0
  60. sage/libs/flint/acb_poly_macros.pxd +8 -0
  61. sage/libs/flint/acb_theta.pxd +124 -0
  62. sage/libs/flint/acf.pxd +32 -0
  63. sage/libs/flint/aprcl.pxd +84 -0
  64. sage/libs/flint/arb.pxd +382 -0
  65. sage/libs/flint/arb_calc.pxd +31 -0
  66. sage/libs/flint/arb_fmpz_poly.pxd +34 -0
  67. sage/libs/flint/arb_fpwrap.pxd +215 -0
  68. sage/libs/flint/arb_hypgeom.pxd +147 -0
  69. sage/libs/flint/arb_macros.pxd +9 -0
  70. sage/libs/flint/arb_mat.pxd +140 -0
  71. sage/libs/flint/arb_mat_macros.pxd +10 -0
  72. sage/libs/flint/arb_poly.pxd +237 -0
  73. sage/libs/flint/arf.pxd +167 -0
  74. sage/libs/flint/arith.cpython-312-x86_64-linux-gnu.so +0 -0
  75. sage/libs/flint/arith.pxd +76 -0
  76. sage/libs/flint/arith.pyx +77 -0
  77. sage/libs/flint/arith_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  78. sage/libs/flint/arith_sage.pyx +308 -0
  79. sage/libs/flint/bernoulli.pxd +28 -0
  80. sage/libs/flint/bool_mat.pxd +52 -0
  81. sage/libs/flint/ca.pxd +203 -0
  82. sage/libs/flint/ca_ext.pxd +34 -0
  83. sage/libs/flint/ca_field.pxd +32 -0
  84. sage/libs/flint/ca_mat.pxd +117 -0
  85. sage/libs/flint/ca_poly.pxd +104 -0
  86. sage/libs/flint/ca_vec.pxd +46 -0
  87. sage/libs/flint/calcium.pxd +27 -0
  88. sage/libs/flint/d_mat.pxd +39 -0
  89. sage/libs/flint/d_vec.pxd +32 -0
  90. sage/libs/flint/dirichlet.pxd +57 -0
  91. sage/libs/flint/dlog.pxd +53 -0
  92. sage/libs/flint/double_extras.pxd +24 -0
  93. sage/libs/flint/double_interval.pxd +36 -0
  94. sage/libs/flint/fexpr.pxd +104 -0
  95. sage/libs/flint/fexpr_builtin.pxd +20 -0
  96. sage/libs/flint/fft.pxd +66 -0
  97. sage/libs/flint/flint.pxd +36 -0
  98. sage/libs/flint/flint_ntl_wrap.h +35 -0
  99. sage/libs/flint/flint_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  100. sage/libs/flint/flint_sage.pyx +163 -0
  101. sage/libs/flint/flint_wrap.h +190 -0
  102. sage/libs/flint/fmpq.pxd +137 -0
  103. sage/libs/flint/fmpq_mat.pxd +105 -0
  104. sage/libs/flint/fmpq_mat_macros.pxd +10 -0
  105. sage/libs/flint/fmpq_mpoly.pxd +165 -0
  106. sage/libs/flint/fmpq_mpoly_factor.pxd +30 -0
  107. sage/libs/flint/fmpq_poly.pxd +241 -0
  108. sage/libs/flint/fmpq_poly_macros.pxd +9 -0
  109. sage/libs/flint/fmpq_poly_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  110. sage/libs/flint/fmpq_poly_sage.pxd +31 -0
  111. sage/libs/flint/fmpq_poly_sage.pyx +48 -0
  112. sage/libs/flint/fmpq_vec.pxd +27 -0
  113. sage/libs/flint/fmpz.pxd +256 -0
  114. sage/libs/flint/fmpz_extras.pxd +32 -0
  115. sage/libs/flint/fmpz_factor.pxd +42 -0
  116. sage/libs/flint/fmpz_factor_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  117. sage/libs/flint/fmpz_factor_sage.pxd +4 -0
  118. sage/libs/flint/fmpz_factor_sage.pyx +29 -0
  119. sage/libs/flint/fmpz_lll.pxd +49 -0
  120. sage/libs/flint/fmpz_macros.pxd +8 -0
  121. sage/libs/flint/fmpz_mat.pxd +184 -0
  122. sage/libs/flint/fmpz_mat_macros.pxd +10 -0
  123. sage/libs/flint/fmpz_mod.pxd +46 -0
  124. sage/libs/flint/fmpz_mod_mat.pxd +71 -0
  125. sage/libs/flint/fmpz_mod_mpoly.pxd +161 -0
  126. sage/libs/flint/fmpz_mod_mpoly_factor.pxd +28 -0
  127. sage/libs/flint/fmpz_mod_poly.pxd +249 -0
  128. sage/libs/flint/fmpz_mod_poly_factor.pxd +46 -0
  129. sage/libs/flint/fmpz_mod_vec.pxd +27 -0
  130. sage/libs/flint/fmpz_mpoly.pxd +224 -0
  131. sage/libs/flint/fmpz_mpoly_factor.pxd +29 -0
  132. sage/libs/flint/fmpz_mpoly_q.pxd +57 -0
  133. sage/libs/flint/fmpz_poly.cpython-312-x86_64-linux-gnu.so +0 -0
  134. sage/libs/flint/fmpz_poly.pxd +407 -0
  135. sage/libs/flint/fmpz_poly.pyx +19 -0
  136. sage/libs/flint/fmpz_poly_factor.pxd +33 -0
  137. sage/libs/flint/fmpz_poly_macros.pxd +8 -0
  138. sage/libs/flint/fmpz_poly_mat.pxd +71 -0
  139. sage/libs/flint/fmpz_poly_q.pxd +55 -0
  140. sage/libs/flint/fmpz_poly_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  141. sage/libs/flint/fmpz_poly_sage.pxd +20 -0
  142. sage/libs/flint/fmpz_poly_sage.pyx +500 -0
  143. sage/libs/flint/fmpz_vec.pxd +80 -0
  144. sage/libs/flint/fmpzi.pxd +52 -0
  145. sage/libs/flint/fq.pxd +97 -0
  146. sage/libs/flint/fq_default.pxd +84 -0
  147. sage/libs/flint/fq_default_mat.pxd +70 -0
  148. sage/libs/flint/fq_default_poly.pxd +97 -0
  149. sage/libs/flint/fq_default_poly_factor.pxd +39 -0
  150. sage/libs/flint/fq_embed.pxd +28 -0
  151. sage/libs/flint/fq_mat.pxd +83 -0
  152. sage/libs/flint/fq_nmod.pxd +95 -0
  153. sage/libs/flint/fq_nmod_embed.pxd +28 -0
  154. sage/libs/flint/fq_nmod_mat.pxd +83 -0
  155. sage/libs/flint/fq_nmod_mpoly.pxd +130 -0
  156. sage/libs/flint/fq_nmod_mpoly_factor.pxd +28 -0
  157. sage/libs/flint/fq_nmod_poly.pxd +202 -0
  158. sage/libs/flint/fq_nmod_poly_factor.pxd +47 -0
  159. sage/libs/flint/fq_nmod_vec.pxd +33 -0
  160. sage/libs/flint/fq_poly.pxd +204 -0
  161. sage/libs/flint/fq_poly_factor.pxd +47 -0
  162. sage/libs/flint/fq_vec.pxd +33 -0
  163. sage/libs/flint/fq_zech.pxd +99 -0
  164. sage/libs/flint/fq_zech_embed.pxd +28 -0
  165. sage/libs/flint/fq_zech_mat.pxd +78 -0
  166. sage/libs/flint/fq_zech_poly.pxd +198 -0
  167. sage/libs/flint/fq_zech_poly_factor.pxd +47 -0
  168. sage/libs/flint/fq_zech_vec.pxd +33 -0
  169. sage/libs/flint/gr.pxd +174 -0
  170. sage/libs/flint/gr_generic.pxd +215 -0
  171. sage/libs/flint/gr_mat.pxd +161 -0
  172. sage/libs/flint/gr_mpoly.pxd +68 -0
  173. sage/libs/flint/gr_poly.pxd +276 -0
  174. sage/libs/flint/gr_special.pxd +237 -0
  175. sage/libs/flint/gr_vec.pxd +120 -0
  176. sage/libs/flint/hypgeom.pxd +24 -0
  177. sage/libs/flint/long_extras.pxd +23 -0
  178. sage/libs/flint/mag.pxd +131 -0
  179. sage/libs/flint/mag_macros.pxd +8 -0
  180. sage/libs/flint/mpf_mat.pxd +36 -0
  181. sage/libs/flint/mpf_vec.pxd +34 -0
  182. sage/libs/flint/mpfr_mat.pxd +27 -0
  183. sage/libs/flint/mpfr_vec.pxd +25 -0
  184. sage/libs/flint/mpn_extras.pxd +41 -0
  185. sage/libs/flint/mpoly.pxd +72 -0
  186. sage/libs/flint/nf.pxd +19 -0
  187. sage/libs/flint/nf_elem.pxd +74 -0
  188. sage/libs/flint/nmod.pxd +35 -0
  189. sage/libs/flint/nmod_mat.pxd +104 -0
  190. sage/libs/flint/nmod_mpoly.pxd +144 -0
  191. sage/libs/flint/nmod_mpoly_factor.pxd +28 -0
  192. sage/libs/flint/nmod_poly.pxd +339 -0
  193. sage/libs/flint/nmod_poly_factor.pxd +44 -0
  194. sage/libs/flint/nmod_poly_linkage.pxi +710 -0
  195. sage/libs/flint/nmod_poly_mat.pxd +76 -0
  196. sage/libs/flint/nmod_vec.pxd +40 -0
  197. sage/libs/flint/ntl_interface.pxd +17 -0
  198. sage/libs/flint/padic.pxd +93 -0
  199. sage/libs/flint/padic_mat.pxd +64 -0
  200. sage/libs/flint/padic_poly.pxd +88 -0
  201. sage/libs/flint/partitions.pxd +23 -0
  202. sage/libs/flint/perm.pxd +26 -0
  203. sage/libs/flint/profiler.pxd +24 -0
  204. sage/libs/flint/qadic.pxd +77 -0
  205. sage/libs/flint/qfb.pxd +44 -0
  206. sage/libs/flint/qqbar.pxd +172 -0
  207. sage/libs/flint/qsieve.cpython-312-x86_64-linux-gnu.so +0 -0
  208. sage/libs/flint/qsieve.pxd +41 -0
  209. sage/libs/flint/qsieve.pyx +21 -0
  210. sage/libs/flint/qsieve_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  211. sage/libs/flint/qsieve_sage.pyx +67 -0
  212. sage/libs/flint/thread_pool.pxd +25 -0
  213. sage/libs/flint/types.pxd +2076 -0
  214. sage/libs/flint/ulong_extras.cpython-312-x86_64-linux-gnu.so +0 -0
  215. sage/libs/flint/ulong_extras.pxd +141 -0
  216. sage/libs/flint/ulong_extras.pyx +21 -0
  217. sage/libs/flint/ulong_extras_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  218. sage/libs/flint/ulong_extras_sage.pyx +21 -0
  219. sage/matrix/all__sagemath_flint.py +1 -0
  220. sage/matrix/change_ring.cpython-312-x86_64-linux-gnu.so +0 -0
  221. sage/matrix/change_ring.pyx +43 -0
  222. sage/matrix/matrix_complex_ball_dense.cpython-312-x86_64-linux-gnu.so +0 -0
  223. sage/matrix/matrix_complex_ball_dense.pxd +14 -0
  224. sage/matrix/matrix_complex_ball_dense.pyx +973 -0
  225. sage/matrix/matrix_cyclo_dense.cpython-312-x86_64-linux-gnu.so +0 -0
  226. sage/matrix/matrix_cyclo_dense.pxd +16 -0
  227. sage/matrix/matrix_cyclo_dense.pyx +1761 -0
  228. sage/matrix/matrix_integer_dense.cpython-312-x86_64-linux-gnu.so +0 -0
  229. sage/matrix/matrix_integer_dense.pxd +32 -0
  230. sage/matrix/matrix_integer_dense.pyx +5801 -0
  231. sage/matrix/matrix_integer_dense_hnf.py +1294 -0
  232. sage/matrix/matrix_integer_dense_saturation.py +346 -0
  233. sage/matrix/matrix_integer_sparse.cpython-312-x86_64-linux-gnu.so +0 -0
  234. sage/matrix/matrix_integer_sparse.pxd +9 -0
  235. sage/matrix/matrix_integer_sparse.pyx +1090 -0
  236. sage/matrix/matrix_rational_dense.cpython-312-x86_64-linux-gnu.so +0 -0
  237. sage/matrix/matrix_rational_dense.pxd +23 -0
  238. sage/matrix/matrix_rational_dense.pyx +2995 -0
  239. sage/matrix/matrix_rational_sparse.cpython-312-x86_64-linux-gnu.so +0 -0
  240. sage/matrix/matrix_rational_sparse.pxd +11 -0
  241. sage/matrix/matrix_rational_sparse.pyx +789 -0
  242. sage/matrix/misc_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  243. sage/matrix/misc_flint.pyx +109 -0
  244. sage/modular/all__sagemath_flint.py +1 -0
  245. sage/modular/modform/all__sagemath_flint.py +1 -0
  246. sage/modular/modform/eis_series_cython.cpython-312-x86_64-linux-gnu.so +0 -0
  247. sage/modular/modform/eis_series_cython.pyx +226 -0
  248. sage/modular/modsym/all__sagemath_flint.py +1 -0
  249. sage/modular/modsym/apply.cpython-312-x86_64-linux-gnu.so +0 -0
  250. sage/modular/modsym/apply.pxd +6 -0
  251. sage/modular/modsym/apply.pyx +113 -0
  252. sage/modular/modsym/heilbronn.cpython-312-x86_64-linux-gnu.so +0 -0
  253. sage/modular/modsym/heilbronn.pyx +966 -0
  254. sage/modular/pollack_stevens/all__sagemath_flint.py +1 -0
  255. sage/modular/pollack_stevens/dist.cpython-312-x86_64-linux-gnu.so +0 -0
  256. sage/modular/pollack_stevens/dist.pxd +38 -0
  257. sage/modular/pollack_stevens/dist.pyx +1439 -0
  258. sage/quivers/algebra.py +691 -0
  259. sage/quivers/algebra_elements.cpython-312-x86_64-linux-gnu.so +0 -0
  260. sage/quivers/algebra_elements.pxd +97 -0
  261. sage/quivers/algebra_elements.pxi +1324 -0
  262. sage/quivers/algebra_elements.pyx +1424 -0
  263. sage/quivers/all.py +1 -0
  264. sage/quivers/ar_quiver.py +917 -0
  265. sage/quivers/homspace.py +640 -0
  266. sage/quivers/morphism.py +1282 -0
  267. sage/quivers/path_semigroup.py +1155 -0
  268. sage/quivers/paths.cpython-312-x86_64-linux-gnu.so +0 -0
  269. sage/quivers/paths.pxd +13 -0
  270. sage/quivers/paths.pyx +809 -0
  271. sage/quivers/representation.py +2975 -0
  272. sage/rings/all__sagemath_flint.py +37 -0
  273. sage/rings/cif.py +4 -0
  274. sage/rings/complex_arb.cpython-312-x86_64-linux-gnu.so +0 -0
  275. sage/rings/complex_arb.pxd +29 -0
  276. sage/rings/complex_arb.pyx +5176 -0
  277. sage/rings/complex_interval.cpython-312-x86_64-linux-gnu.so +0 -0
  278. sage/rings/complex_interval.pxd +30 -0
  279. sage/rings/complex_interval.pyx +2475 -0
  280. sage/rings/complex_interval_field.py +711 -0
  281. sage/rings/convert/all.py +1 -0
  282. sage/rings/convert/mpfi.cpython-312-x86_64-linux-gnu.so +0 -0
  283. sage/rings/convert/mpfi.pxd +6 -0
  284. sage/rings/convert/mpfi.pyx +576 -0
  285. sage/rings/factorint_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  286. sage/rings/factorint_flint.pyx +99 -0
  287. sage/rings/fraction_field_FpT.cpython-312-x86_64-linux-gnu.so +0 -0
  288. sage/rings/fraction_field_FpT.pxd +28 -0
  289. sage/rings/fraction_field_FpT.pyx +2043 -0
  290. sage/rings/imaginary_unit.py +5 -0
  291. sage/rings/monomials.py +73 -0
  292. sage/rings/number_field/S_unit_solver.py +2870 -0
  293. sage/rings/number_field/all__sagemath_flint.py +7 -0
  294. sage/rings/number_field/bdd_height.py +664 -0
  295. sage/rings/number_field/class_group.py +762 -0
  296. sage/rings/number_field/galois_group.py +1307 -0
  297. sage/rings/number_field/homset.py +612 -0
  298. sage/rings/number_field/maps.py +687 -0
  299. sage/rings/number_field/morphism.py +272 -0
  300. sage/rings/number_field/number_field.py +12820 -0
  301. sage/rings/number_field/number_field_element.cpython-312-x86_64-linux-gnu.so +0 -0
  302. sage/rings/number_field/number_field_element.pxd +59 -0
  303. sage/rings/number_field/number_field_element.pyx +5735 -0
  304. sage/rings/number_field/number_field_element_quadratic.cpython-312-x86_64-linux-gnu.so +0 -0
  305. sage/rings/number_field/number_field_element_quadratic.pxd +34 -0
  306. sage/rings/number_field/number_field_element_quadratic.pyx +3185 -0
  307. sage/rings/number_field/number_field_ideal_rel.py +925 -0
  308. sage/rings/number_field/number_field_morphisms.cpython-312-x86_64-linux-gnu.so +0 -0
  309. sage/rings/number_field/number_field_morphisms.pyx +781 -0
  310. sage/rings/number_field/number_field_rel.py +2734 -0
  311. sage/rings/number_field/order.py +2981 -0
  312. sage/rings/number_field/order_ideal.py +804 -0
  313. sage/rings/number_field/selmer_group.py +715 -0
  314. sage/rings/number_field/small_primes_of_degree_one.py +242 -0
  315. sage/rings/number_field/splitting_field.py +606 -0
  316. sage/rings/number_field/structure.py +380 -0
  317. sage/rings/number_field/unit_group.py +721 -0
  318. sage/rings/padics/all__sagemath_flint.py +3 -0
  319. sage/rings/polynomial/all__sagemath_flint.py +1 -0
  320. sage/rings/polynomial/complex_roots.py +312 -0
  321. sage/rings/polynomial/evaluation_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  322. sage/rings/polynomial/evaluation_flint.pxd +7 -0
  323. sage/rings/polynomial/evaluation_flint.pyx +68 -0
  324. sage/rings/polynomial/hilbert.cpython-312-x86_64-linux-gnu.so +0 -0
  325. sage/rings/polynomial/hilbert.pyx +602 -0
  326. sage/rings/polynomial/polynomial_complex_arb.cpython-312-x86_64-linux-gnu.so +0 -0
  327. sage/rings/polynomial/polynomial_complex_arb.pxd +7 -0
  328. sage/rings/polynomial/polynomial_complex_arb.pyx +963 -0
  329. sage/rings/polynomial/polynomial_integer_dense_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  330. sage/rings/polynomial/polynomial_integer_dense_flint.pxd +13 -0
  331. sage/rings/polynomial/polynomial_integer_dense_flint.pyx +1881 -0
  332. sage/rings/polynomial/polynomial_number_field.cpython-312-x86_64-linux-gnu.so +0 -0
  333. sage/rings/polynomial/polynomial_number_field.pyx +345 -0
  334. sage/rings/polynomial/polynomial_rational_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  335. sage/rings/polynomial/polynomial_rational_flint.pxd +20 -0
  336. sage/rings/polynomial/polynomial_rational_flint.pyx +2598 -0
  337. sage/rings/polynomial/polynomial_zmod_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  338. sage/rings/polynomial/polynomial_zmod_flint.pxd +20 -0
  339. sage/rings/polynomial/polynomial_zmod_flint.pyx +1063 -0
  340. sage/rings/polynomial/real_roots.cpython-312-x86_64-linux-gnu.so +0 -0
  341. sage/rings/polynomial/real_roots.pxd +81 -0
  342. sage/rings/polynomial/real_roots.pyx +4704 -0
  343. sage/rings/polynomial/refine_root.cpython-312-x86_64-linux-gnu.so +0 -0
  344. sage/rings/polynomial/refine_root.pyx +142 -0
  345. sage/rings/polynomial/weil/all.py +4 -0
  346. sage/rings/polynomial/weil/power_sums.h +46 -0
  347. sage/rings/polynomial/weil/weil_polynomials.cpython-312-x86_64-linux-gnu.so +0 -0
  348. sage/rings/polynomial/weil/weil_polynomials.pyx +596 -0
  349. sage/rings/qqbar.py +9025 -0
  350. sage/rings/real_arb.cpython-312-x86_64-linux-gnu.so +0 -0
  351. sage/rings/real_arb.pxd +21 -0
  352. sage/rings/real_arb.pyx +4065 -0
  353. sage/rings/real_interval_absolute.cpython-312-x86_64-linux-gnu.so +0 -0
  354. sage/rings/real_interval_absolute.pyx +1073 -0
  355. sage/rings/real_mpfi.cpython-312-x86_64-linux-gnu.so +0 -0
  356. sage/rings/real_mpfi.pyx +5428 -0
  357. sage/schemes/all__sagemath_flint.py +1 -0
  358. sage/schemes/elliptic_curves/all__sagemath_flint.py +1 -0
  359. sage/schemes/elliptic_curves/descent_two_isogeny.cpython-312-x86_64-linux-gnu.so +0 -0
  360. sage/schemes/elliptic_curves/descent_two_isogeny.pyx +1387 -0
  361. sage/schemes/elliptic_curves/descent_two_isogeny_pari.pxd +5 -0
@@ -0,0 +1,2995 @@
1
+ # sage_setup: distribution = sagemath-flint
2
+ """
3
+ Dense matrices over the rational field
4
+
5
+ EXAMPLES:
6
+
7
+ We create a 3x3 matrix with rational entries and do some
8
+ operations with it.
9
+
10
+ ::
11
+
12
+ sage: a = matrix(QQ, 3,3, [1,2/3, -4/5, 1,1,1, 8,2, -3/19]); a
13
+ [ 1 2/3 -4/5]
14
+ [ 1 1 1]
15
+ [ 8 2 -3/19]
16
+ sage: a.det()
17
+ 2303/285
18
+ sage: a.charpoly()
19
+ x^3 - 35/19*x^2 + 1259/285*x - 2303/285
20
+ sage: b = a^(-1); b
21
+ [ -615/2303 -426/2303 418/2303]
22
+ [ 2325/2303 1779/2303 -513/2303]
23
+ [-1710/2303 950/2303 95/2303]
24
+ sage: b.det()
25
+ 285/2303
26
+ sage: a == b
27
+ False
28
+ sage: a < b
29
+ False
30
+ sage: b < a
31
+ True
32
+ sage: a > b
33
+ True
34
+ sage: a*b
35
+ [1 0 0]
36
+ [0 1 0]
37
+ [0 0 1]
38
+
39
+ TESTS::
40
+
41
+ sage: a = matrix(QQ, 2, range(4), sparse=False)
42
+ sage: TestSuite(a).run()
43
+
44
+ Test hashing::
45
+
46
+ sage: m = matrix(QQ, 2, [1/2, -1, 2, 3])
47
+ sage: hash(m)
48
+ Traceback (most recent call last):
49
+ ...
50
+ TypeError: mutable matrices are unhashable
51
+ sage: m.set_immutable()
52
+ sage: hash(m)
53
+ 2212268000387745777 # 64-bit
54
+ 1997752305 # 32-bit
55
+ """
56
+
57
+ # ****************************************************************************
58
+ # Copyright (C) 2004,2005,2006 William Stein <wstein@gmail.com>
59
+ # 2017 Vincent Delecroix <20100.delecroix@gmail.com>
60
+ #
61
+ # This program is free software: you can redistribute it and/or modify
62
+ # it under the terms of the GNU General Public License as published by
63
+ # the Free Software Foundation, either version 2 of the License, or
64
+ # (at your option) any later version.
65
+ # https://www.gnu.org/licenses/
66
+ # ****************************************************************************
67
+
68
+ from libc.string cimport strcpy, strlen
69
+
70
+ from sage.categories.rings import Rings
71
+ from sage.cpython.string cimport char_to_str
72
+
73
+ from sage.modules.vector_rational_dense cimport Vector_rational_dense
74
+ from sage.ext.stdsage cimport PY_NEW
75
+ from sage.misc.randstate cimport randstate, current_randstate
76
+
77
+ from cysignals.signals cimport sig_on, sig_off
78
+ from cysignals.memory cimport sig_malloc, sig_free
79
+
80
+ from sage.libs.gmp.types cimport mpz_t, mpq_t
81
+ from sage.libs.gmp.mpz cimport mpz_init, mpz_clear, mpz_cmp_si
82
+ from sage.libs.gmp.mpq cimport mpq_init, mpq_clear, mpq_set_si, mpq_mul, mpq_add, mpq_set
83
+ from sage.libs.gmp.randomize cimport (mpq_randomize_entry,
84
+ mpq_randomize_entry_as_int,
85
+ mpq_randomize_entry_recip_uniform,
86
+ mpq_randomize_entry_nonzero,
87
+ mpq_randomize_entry_as_int_nonzero,
88
+ mpq_randomize_entry_recip_uniform_nonzero)
89
+
90
+ from sage.libs.flint.fmpz cimport *
91
+ from sage.libs.flint.fmpq cimport *
92
+ from sage.libs.flint.fmpz_mat cimport *
93
+ from sage.libs.flint.fmpq_mat cimport *
94
+
95
+ cimport sage.structure.element
96
+
97
+ from sage.structure.richcmp cimport rich_to_bool
98
+ from sage.rings.rational cimport Rational
99
+ from sage.matrix.matrix cimport Matrix
100
+ from sage.matrix.args cimport SparseEntry, MatrixArgs_init
101
+ from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense
102
+ from sage.structure.element cimport Element, Vector
103
+ from sage.rings.integer cimport Integer
104
+ from sage.rings.integer_ring import ZZ, IntegerRing_class
105
+ import sage.rings.abc
106
+ from sage.rings.rational_field import QQ
107
+
108
+ from sage.matrix.matrix2 import decomp_seq
109
+ from sage.misc.verbose import verbose
110
+
111
+
112
+ cdef class Matrix_rational_dense(Matrix_dense):
113
+ def __cinit__(self):
114
+ """
115
+ Create and allocate memory for the matrix.
116
+
117
+ EXAMPLES::
118
+
119
+ sage: from sage.matrix.matrix_rational_dense import Matrix_rational_dense
120
+ sage: a = Matrix_rational_dense.__new__(Matrix_rational_dense, Mat(ZZ,3), 0,0,0)
121
+ sage: type(a)
122
+ <class 'sage.matrix.matrix_rational_dense.Matrix_rational_dense'>
123
+
124
+ .. WARNING::
125
+
126
+ This is for internal use only, or if you really know what
127
+ you're doing.
128
+ """
129
+ sig_on()
130
+ fmpq_mat_init(self._matrix, self._nrows, self._ncols)
131
+ sig_off()
132
+
133
+ cdef inline Matrix_rational_dense _new_matrix(self, Py_ssize_t nrows, Py_ssize_t ncols):
134
+ if nrows == self._nrows and ncols == self._ncols:
135
+ parent = self._parent
136
+ else:
137
+ parent = self.matrix_space(nrows, ncols)
138
+
139
+ return Matrix_rational_dense.__new__(Matrix_rational_dense, parent, None, None, None)
140
+
141
+ def __dealloc__(self):
142
+ fmpq_mat_clear(self._matrix)
143
+
144
+ def __init__(self, parent, entries=None, copy=None, bint coerce=True):
145
+ r"""
146
+ INPUT:
147
+
148
+ - ``parent`` -- a matrix space over ``QQ``
149
+
150
+ - ``entries`` -- see :func:`matrix`
151
+
152
+ - ``copy`` -- ignored (for backwards compatibility)
153
+
154
+ - ``coerce`` -- if ``False``, assume without checking that the
155
+ entries are of type :class:`Rational`
156
+
157
+ TESTS::
158
+
159
+ sage: matrix(QQ, 2, 2, 1/4)
160
+ [1/4 0]
161
+ [ 0 1/4]
162
+ sage: matrix(QQ, 3, 1, [1/2, -3/4, 0])
163
+ [ 1/2]
164
+ [-3/4]
165
+ [ 0]
166
+ sage: matrix(QQ, 2, 2, 0.5)
167
+ [1/2 0]
168
+ [ 0 1/2]
169
+ """
170
+ ma = MatrixArgs_init(parent, entries)
171
+ cdef Rational z
172
+ for t in ma.iter(coerce, True):
173
+ se = <SparseEntry>t
174
+ z = <Rational>se.entry
175
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, se.i, se.j), z.value)
176
+
177
+ def matrix_from_columns(self, columns):
178
+ """
179
+ Return the matrix constructed from ``self`` using columns with indices
180
+ in the columns list.
181
+
182
+ EXAMPLES::
183
+
184
+ sage: A = matrix(QQ, 3, range(9))
185
+ sage: A
186
+ [0 1 2]
187
+ [3 4 5]
188
+ [6 7 8]
189
+ sage: A.matrix_from_columns([2,1])
190
+ [2 1]
191
+ [5 4]
192
+ [8 7]
193
+ sage: A.matrix_from_columns((2,1,0,2))
194
+ [2 1 0 2]
195
+ [5 4 3 5]
196
+ [8 7 6 8]
197
+ """
198
+ cdef Matrix_rational_dense A
199
+ cdef Py_ssize_t k, r, col
200
+
201
+ A = self._new_matrix(self._nrows, len(columns))
202
+ k = 0
203
+ for col in columns:
204
+ if col < 0 or col >= self._ncols:
205
+ raise IndexError("column out of range")
206
+ for r in range(self._nrows):
207
+ fmpq_set(fmpq_mat_entry(A._matrix, r, k), fmpq_mat_entry(self._matrix, r, col))
208
+ k = k + 1
209
+ return A
210
+
211
+ def add_to_entry(self, Py_ssize_t i, Py_ssize_t j, elt):
212
+ r"""
213
+ Add ``elt`` to the entry at position ``(i,j)``.
214
+
215
+ EXAMPLES::
216
+
217
+ sage: m = matrix(QQ, 2, 2)
218
+ sage: m.add_to_entry(0, 0, -1/3)
219
+ sage: m
220
+ [-1/3 0]
221
+ [ 0 0]
222
+ """
223
+ if not isinstance(elt, Rational):
224
+ elt = Rational(elt)
225
+ if i < 0:
226
+ i += self._nrows
227
+ if i < 0 or i >= self._nrows:
228
+ raise IndexError("row index out of range")
229
+ if j < 0:
230
+ j += self._ncols
231
+ if j < 0 or j >= self._ncols:
232
+ raise IndexError("column index out of range")
233
+ cdef fmpq_t tmp
234
+ fmpq_init(tmp)
235
+ fmpq_set_mpq(tmp, (<Rational>elt).value)
236
+ fmpq_add(fmpq_mat_entry(self._matrix, i, j),
237
+ fmpq_mat_entry(self._matrix, i, j),
238
+ tmp)
239
+ fmpq_clear(tmp)
240
+
241
+ cdef set_unsafe(self, Py_ssize_t i, Py_ssize_t j, value):
242
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, i, j), (<Rational> value).value)
243
+
244
+ cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j):
245
+ cdef Rational x
246
+ x = Rational.__new__(Rational)
247
+ fmpq_get_mpq(x.value, fmpq_mat_entry(self._matrix, i, j))
248
+ return x
249
+
250
+ cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1:
251
+ """
252
+ Return 1 if the entry (i, j) is zero, otherwise 0.
253
+
254
+ .. WARNING::
255
+
256
+ This is very unsafe; it assumes i and j are in the right
257
+ range.
258
+ """
259
+ return fmpq_is_zero(fmpq_mat_entry(self._matrix, i,j))
260
+
261
+ cdef _add_ui_unsafe_assuming_int(self, Py_ssize_t i, Py_ssize_t j, unsigned long int n):
262
+ # doesn't check immutability
263
+ # doesn't do bounds checks.
264
+ # assumes that self[i,j] is an integer.
265
+ cdef fmpz * entry = fmpq_numref(fmpq_mat_entry(self._matrix, i, j))
266
+ fmpz_add_ui(entry, entry, n)
267
+
268
+ cdef _sub_ui_unsafe_assuming_int(self, Py_ssize_t i, Py_ssize_t j, unsigned long int n):
269
+ # doesn't check immutability
270
+ # doesn't do bounds checks.
271
+ # assumes that self[i,j] is an integer.
272
+ cdef fmpz * entry = fmpq_numref(fmpq_mat_entry(self._matrix, i, j))
273
+ fmpz_sub_ui(entry, entry, n)
274
+
275
+ def _pickle(self):
276
+ return self._pickle_version0(), 0
277
+
278
+ def _unpickle(self, data, int version):
279
+ if version == 0:
280
+ self._unpickle_version0(data)
281
+ else:
282
+ raise RuntimeError("unknown matrix version (=%s)" % version)
283
+
284
+ cdef _pickle_version0(self):
285
+ return self._export_as_string(32)
286
+
287
+ cpdef _export_as_string(self, int base=10):
288
+ """
289
+ Return space separated string of the entries in this matrix, in the
290
+ given base. This is optimized for speed.
291
+
292
+ INPUT:
293
+
294
+ - ``base`` -- integer (default: `10`)
295
+
296
+ EXAMPLES::
297
+
298
+ sage: m = matrix(QQ,2,3,[1,2/3,-3/4,1,-2/3,-45/17])
299
+ sage: m._export_as_string(10)
300
+ '1 2/3 -3/4 1 -2/3 -45/17'
301
+ sage: m._export_as_string(16)
302
+ '1 2/3 -3/4 1 -2/3 -2d/11'
303
+ """
304
+ cdef Py_ssize_t i, j, len_so_far, m, n
305
+ cdef char *s
306
+ cdef char *t
307
+ cdef char *tmp
308
+
309
+ if self._nrows == 0 or self._ncols == 0:
310
+ data = ''
311
+ else:
312
+ n = self._nrows * self._ncols * 10
313
+ s = <char*> sig_malloc(n * sizeof(char))
314
+ t = s
315
+ len_so_far = 0
316
+
317
+ sig_on()
318
+ for i in range(self._nrows):
319
+ for j in range(self._ncols):
320
+ m = fmpz_sizeinbase (fmpq_mat_entry_num(self._matrix, i, j), base) + \
321
+ fmpz_sizeinbase (fmpq_mat_entry_den(self._matrix, i, j), base) + 3
322
+ if len_so_far + m + 1 >= n:
323
+ # copy to new string with double the size
324
+ n = 2*n + m + 1
325
+ tmp = <char*> sig_malloc(n * sizeof(char))
326
+ strcpy(tmp, s)
327
+ sig_free(s)
328
+ s = tmp
329
+ t = s + len_so_far
330
+ fmpq_get_str(t, base, fmpq_mat_entry(self._matrix, i, j))
331
+ m = strlen(t)
332
+ len_so_far = len_so_far + m + 1
333
+ t = t + m
334
+ t[0] = <char>32
335
+ t[1] = <char>0
336
+ t = t + 1
337
+ sig_off()
338
+ data = char_to_str(s)[:-1]
339
+ sig_free(s)
340
+ return data
341
+
342
+ cdef _unpickle_version0(self, data):
343
+ r"""
344
+ TESTS::
345
+
346
+ sage: a = random_matrix(QQ, 4, 3, num_bound=2**500, den_bound=2**500)
347
+ sage: loads(dumps(a)) == a # indirect doctest
348
+ True
349
+ """
350
+ cdef Py_ssize_t i, j, k
351
+ data = data.split()
352
+ if len(data) != self._nrows * self._ncols:
353
+ raise RuntimeError("invalid pickle data")
354
+ k = 0
355
+ for i in range(self._nrows):
356
+ for j in range(self._ncols):
357
+ s = data[k]
358
+ k += 1
359
+ if '/' in s:
360
+ num, den = (n.encode() for n in s.split('/'))
361
+ if fmpz_set_str(fmpq_mat_entry_num(self._matrix, i, j), num, 32) or \
362
+ fmpz_set_str(fmpq_mat_entry_den(self._matrix, i, j), den, 32):
363
+ raise RuntimeError("invalid pickle data")
364
+ else:
365
+ num = s.encode()
366
+ if fmpz_set_str(fmpq_mat_entry_num(self._matrix, i, j), num, 32):
367
+ raise RuntimeError("invalid pickle data")
368
+ fmpz_one(fmpq_mat_entry_den(self._matrix, i, j))
369
+
370
+ # #######################################################################
371
+ # LEVEL 2 functionality
372
+ # x * cdef _add_
373
+ # x * cdef _mul_
374
+ # x * cdef _vector_times_matrix_
375
+ # x * cpdef _richcmp_
376
+ # x * __neg__
377
+ # * __invert__
378
+ # x * __copy__
379
+ # x * _multiply_classical
380
+ # * _list -- list of underlying elements (need not be a copy)
381
+ # * _dict -- sparse dictionary of underlying elements (need not be a copy)
382
+ # #######################################################################
383
+
384
+ cpdef _lmul_(self, Element right):
385
+ """
386
+ EXAMPLES::
387
+
388
+ sage: a = matrix(QQ, 2, range(6))
389
+ sage: (3/4) * a
390
+ [ 0 3/4 3/2]
391
+ [ 9/4 3 15/4]
392
+ """
393
+ cdef Matrix_rational_dense M
394
+ cdef fmpq_t x
395
+ fmpq_init(x)
396
+ fmpq_set_mpq(x, (<Rational>right).value)
397
+ M = Matrix_rational_dense.__new__(Matrix_rational_dense, self._parent, None, None, None)
398
+ fmpq_mat_scalar_mul_fmpz(M._matrix, self._matrix, fmpq_numref(x))
399
+ fmpq_mat_scalar_div_fmpz(M._matrix, M._matrix, fmpq_denref(x))
400
+ fmpq_clear(x)
401
+ return M
402
+
403
+ cpdef _add_(self, right):
404
+ """
405
+ Add two dense matrices over QQ.
406
+
407
+ EXAMPLES::
408
+
409
+ sage: a = MatrixSpace(QQ,3)(range(9))
410
+ sage: b = MatrixSpace(QQ,3)([1/n for n in range(1,10)])
411
+ sage: a+b
412
+ [ 1 3/2 7/3]
413
+ [13/4 21/5 31/6]
414
+ [43/7 57/8 73/9]
415
+ sage: b.swap_rows(1,2)
416
+ sage: #a+b
417
+ """
418
+ cdef Matrix_rational_dense ans
419
+ ans = Matrix_rational_dense.__new__(Matrix_rational_dense, self._parent, None, None, None)
420
+
421
+ sig_on()
422
+ fmpq_mat_add(ans._matrix, self._matrix, (<Matrix_rational_dense> right)._matrix)
423
+ sig_off()
424
+ return ans
425
+
426
+ cpdef _sub_(self, right):
427
+ """
428
+ Subtract two dense matrices over QQ.
429
+
430
+ EXAMPLES::
431
+
432
+ sage: a = MatrixSpace(QQ,3)(range(9))
433
+ sage: b = MatrixSpace(QQ,3)([1/n for n in range(1,10)])
434
+ sage: a-b
435
+ [ -1 1/2 5/3]
436
+ [11/4 19/5 29/6]
437
+ [41/7 55/8 71/9]
438
+ """
439
+ cdef Matrix_rational_dense ans
440
+ ans = Matrix_rational_dense.__new__(Matrix_rational_dense, self._parent, None, None, None)
441
+
442
+ sig_on()
443
+ fmpq_mat_sub(ans._matrix, self._matrix, (<Matrix_rational_dense> right)._matrix)
444
+ sig_off()
445
+ return ans
446
+
447
+ cpdef _richcmp_(self, right, int op):
448
+ r"""
449
+ TESTS::
450
+
451
+ sage: M = MatrixSpace(QQ, 1)
452
+ sage: M(1) < M(2)
453
+ True
454
+ sage: M(1/3) >= M(5/2)
455
+ False
456
+ sage: M(2) == M(2)
457
+ True
458
+ sage: M(3/4) != M(2)
459
+ True
460
+
461
+ sage: matrix(QQ, 2, 3) == matrix(QQ, 2, 3)
462
+ True
463
+ sage: matrix(QQ, 2, 2) == matrix(QQ, 2, 3)
464
+ False
465
+ sage: matrix(QQ, 2, 2) == matrix(QQ, 3, 2)
466
+ False
467
+ sage: matrix(QQ, 2, 3) == matrix(QQ, 3, 2)
468
+ False
469
+
470
+ sage: mats = [matrix(QQ, 2, 2, 1), matrix(QQ, 2, 2, -1), matrix(QQ, 2, 2, 0)]
471
+ sage: mats.sort()
472
+ sage: mats == [-1, 0, 1]
473
+ True
474
+ """
475
+ cdef Py_ssize_t i, j
476
+ cdef int k
477
+ for i in range(self._nrows):
478
+ for j in range(self._ncols):
479
+ k = fmpq_cmp(fmpq_mat_entry(self._matrix, i, j),
480
+ fmpq_mat_entry((<Matrix_rational_dense> right)._matrix, i, j))
481
+ if k:
482
+ if k > 0:
483
+ return rich_to_bool(op, 1)
484
+ else:
485
+ return rich_to_bool(op, -1)
486
+ return rich_to_bool(op, 0)
487
+
488
+ cdef _vector_times_matrix_(self, Vector v):
489
+ r"""
490
+ Return the vector times matrix product.
491
+
492
+ INPUT:
493
+
494
+ - ``v`` -- a free module element
495
+
496
+ OUTPUT: the vector times matrix product v\*A
497
+
498
+ EXAMPLES::
499
+
500
+ sage: B = matrix(QQ,2, [1,2,3,4])
501
+ sage: V = QQ^2
502
+ sage: w = V([-1,5/2])
503
+ sage: w * B
504
+ (13/2, 8)
505
+ """
506
+ cdef Vector_rational_dense w, ans
507
+ cdef Py_ssize_t i, j
508
+ cdef mpq_t x, y, z
509
+
510
+ M = self.row_ambient_module()
511
+ w = <Vector_rational_dense> v
512
+ ans = M.zero_vector()
513
+
514
+ mpq_init(x)
515
+ mpq_init(y)
516
+ mpq_init(z)
517
+ for i in range(self._ncols):
518
+ mpq_set_si(x, 0, 1)
519
+ for j in range(self._nrows):
520
+ fmpq_get_mpq(z, fmpq_mat_entry(self._matrix, j, i))
521
+ mpq_mul(y, w._entries[j], z)
522
+ mpq_add(x, x, y)
523
+ mpq_set(ans._entries[i], x)
524
+ mpq_clear(x)
525
+ mpq_clear(y)
526
+ mpq_clear(z)
527
+ return ans
528
+
529
+ def __neg__(self):
530
+ """
531
+ Negate a matrix over QQ.
532
+
533
+ EXAMPLES::
534
+
535
+ sage: a = matrix(QQ, 3, [1/n for n in range(1,10)])
536
+ sage: -a
537
+ [ -1 -1/2 -1/3]
538
+ [-1/4 -1/5 -1/6]
539
+ [-1/7 -1/8 -1/9]
540
+ """
541
+ cdef Matrix_rational_dense ans
542
+ ans = Matrix_rational_dense.__new__(Matrix_rational_dense, self._parent, None, None, None)
543
+ fmpq_mat_neg(ans._matrix, self._matrix)
544
+ return ans
545
+
546
+ def __copy__(self):
547
+ """
548
+ Copy a matrix over QQ.
549
+
550
+ TESTS::
551
+
552
+ sage: a = matrix(QQ, 3, [1/n for n in range(1,10)])
553
+ sage: b = a.__copy__()
554
+ sage: a == b
555
+ True
556
+ sage: a is b
557
+ False
558
+ sage: b[0,0] = 5
559
+ sage: a == b
560
+ False
561
+
562
+ sage: a.subdivide(2, 1)
563
+ sage: b = a.__copy__()
564
+ sage: b.subdivisions()
565
+ ([2], [1])
566
+ sage: a.subdivide(2, 2)
567
+ sage: b.subdivisions()
568
+ ([2], [1])
569
+ """
570
+ cdef Matrix_rational_dense ans
571
+ ans = Matrix_rational_dense.__new__(Matrix_rational_dense, self._parent, None, None, None)
572
+ fmpq_mat_set(ans._matrix, self._matrix)
573
+ ans._subdivisions = self._subdivisions
574
+ return ans
575
+
576
+ # #######################################################################
577
+ # LEVEL 3 functionality (Optional)
578
+ # x * cdef _sub_
579
+ # * __deepcopy__
580
+ # * __invert__
581
+ # * Matrix windows -- only if you need strassen for that base
582
+ # * Other functions (list them here):
583
+ # x * denom(self):
584
+ # x * mpz_denom(self, mpz_t d):
585
+ # x * _clear_denom(self):
586
+ # o * echelon_modular(self, height_guess=None):
587
+ # #######################################################################
588
+ def __invert__(self):
589
+ """
590
+ EXAMPLES::
591
+
592
+ sage: a = matrix(QQ,3,range(9))
593
+ sage: a.inverse()
594
+ Traceback (most recent call last):
595
+ ...
596
+ ZeroDivisionError: input matrix must be nonsingular
597
+ sage: a = matrix(QQ, 2, [1, 5, 17, 3])
598
+ sage: a.inverse()
599
+ [-3/82 5/82]
600
+ [17/82 -1/82]
601
+ sage: ~matrix(QQ, 2, 3)
602
+ Traceback (most recent call last):
603
+ ...
604
+ ArithmeticError: self must be a square matrix
605
+ """
606
+ return self.inverse()
607
+
608
+ def _invert_flint(self):
609
+ r"""
610
+ TESTS::
611
+
612
+ sage: matrix(QQ, 2, [1,2,3,4])._invert_flint()
613
+ [ -2 1]
614
+ [ 3/2 -1/2]
615
+ sage: matrix(QQ, 1)._invert_flint()
616
+ Traceback (most recent call last):
617
+ ...
618
+ ZeroDivisionError: input matrix must be nonsingular
619
+ """
620
+ cdef int ret
621
+ cdef Matrix_rational_dense ans
622
+ ans = Matrix_rational_dense.__new__(Matrix_rational_dense, self._parent, None, None, None)
623
+ sig_on()
624
+ ret = fmpq_mat_inv(ans._matrix, self._matrix)
625
+ sig_off()
626
+ if ret == 0:
627
+ raise ZeroDivisionError("input matrix must be nonsingular")
628
+ return ans
629
+
630
+ def inverse(self, algorithm=None, check_invertible=True):
631
+ """
632
+ Return the inverse of this matrix.
633
+
634
+ INPUT:
635
+
636
+ - ``algorithm`` -- an optional specification of an algorithm. It can be one of
637
+
638
+ - ``None``: (default) uses flint
639
+
640
+ - ``'flint'``: uses flint library
641
+
642
+ - ``'pari'``: uses PARI library
643
+
644
+ - ``'iml'``: uses IML library
645
+
646
+ - ``check_invertible`` -- only used when ``algorithm=iml``; whether to
647
+ check that matrix is invertible
648
+
649
+ EXAMPLES::
650
+
651
+ sage: a = matrix(QQ,3,[1,2,5,3,2,1,1,1,1,])
652
+ sage: a.inverse()
653
+ [1/2 3/2 -4]
654
+ [ -1 -2 7]
655
+ [1/2 1/2 -2]
656
+
657
+ sage: a = matrix(QQ, 2, [1, 5, 17, 3])
658
+ sage: a.inverse(algorithm='flint')
659
+ [-3/82 5/82]
660
+ [17/82 -1/82]
661
+ sage: a.inverse(algorithm='flint') * a
662
+ [1 0]
663
+ [0 1]
664
+
665
+ sage: # needs sage.libs.iml
666
+ sage: a = matrix(QQ, 2, [-1, 5, 12, -3])
667
+ sage: a.inverse(algorithm='iml')
668
+ [1/19 5/57]
669
+ [4/19 1/57]
670
+ sage: a.inverse(algorithm='iml') * a
671
+ [1 0]
672
+ [0 1]
673
+
674
+ sage: a = matrix(QQ, 4, primes_first_n(16))
675
+ sage: a.inverse(algorithm='pari') # needs sage.libs.pari
676
+ [ 3/11 -12/55 -1/5 2/11]
677
+ [ -5/11 -2/55 3/10 -3/22]
678
+ [ -13/22 307/440 -1/10 -9/88]
679
+ [ 15/22 -37/88 0 7/88]
680
+
681
+ On singular matrices this method raises a :exc:`ZeroDivisionError`::
682
+
683
+ sage: a = matrix(QQ, 2)
684
+ sage: a.inverse(algorithm='flint')
685
+ Traceback (most recent call last):
686
+ ...
687
+ ZeroDivisionError: input matrix must be nonsingular
688
+ sage: a.inverse(algorithm='iml') # needs sage.libs.iml
689
+ Traceback (most recent call last):
690
+ ...
691
+ ZeroDivisionError: input matrix must be nonsingular
692
+ sage: a.inverse(algorithm='pari') # needs sage.libs.pari
693
+ Traceback (most recent call last):
694
+ ...
695
+ ZeroDivisionError: input matrix must be nonsingular
696
+
697
+ TESTS::
698
+
699
+ sage: a = matrix(QQ, 2)
700
+ sage: a.inverse(algorithm="IAmNotAnAlgorithm")
701
+ Traceback (most recent call last):
702
+ ...
703
+ ValueError: unknown algorithm 'IAmNotAnAlgorithm'
704
+
705
+ sage: for _ in range(30):
706
+ ....: dim = randint(1, 20)
707
+ ....: a = random_matrix(QQ, dim, num_bound=10, den_bound=10)
708
+ ....: while a.rank() != dim: a = random_matrix(QQ, dim)
709
+ ....: inv_flint = a.inverse(algorithm='flint')
710
+ ....: inv_pari = a.inverse(algorithm='pari')
711
+ ....: inv_iml = a.inverse(algorithm='iml')
712
+ ....: assert inv_flint == inv_pari == inv_iml
713
+ """
714
+ if self._nrows != self._ncols:
715
+ raise ArithmeticError("self must be a square matrix")
716
+
717
+ if self._nrows == 0:
718
+ return self
719
+
720
+ if algorithm is None:
721
+ algorithm = "flint"
722
+
723
+ if algorithm == "flint":
724
+ return self._invert_flint()
725
+ elif algorithm == "pari":
726
+ from cypari2.handle_error import PariError
727
+ from .matrix_rational_pari import _invert_pari
728
+ try:
729
+ return _invert_pari(self)
730
+ except PariError:
731
+ raise ZeroDivisionError("input matrix must be nonsingular")
732
+ elif algorithm == "iml":
733
+ from .matrix_integer_iml import _invert_iml
734
+ AZ, denom = self._clear_denom()
735
+ B, d = _invert_iml(AZ, check_invertible=check_invertible)
736
+ return (denom/d)*B
737
+
738
+ else:
739
+ raise ValueError("unknown algorithm '%s'" % algorithm)
740
+
741
+ def determinant(self, algorithm=None, proof=None):
742
+ """
743
+ Return the determinant of this matrix.
744
+
745
+ INPUT:
746
+
747
+ - ``algorithm`` -- an optional specification of an algorithm. It can be one of
748
+
749
+ - ``None``: (default) uses flint
750
+
751
+ - ``'flint'``: uses flint library
752
+
753
+ - ``'pari'``: uses PARI library
754
+
755
+ - ``'integer'``: removes denominator and call determinant on the corresponding
756
+ integer matrix
757
+
758
+ - ``'generic'``: calls the generic Sage implementation
759
+
760
+ - ``proof`` -- boolean or ``None``; if ``None`` use
761
+ proof.linear_algebra(); only relevant for the padic algorithm
762
+
763
+ .. NOTE::
764
+
765
+ It would be *VERY VERY* hard for det to fail even with
766
+ proof=False.
767
+
768
+ EXAMPLES::
769
+
770
+ sage: m = matrix(QQ,3,[1,2/3,4/5, 2,2,2, 5,3,2/5])
771
+ sage: m.determinant()
772
+ -34/15
773
+ sage: m.charpoly()
774
+ x^3 - 17/5*x^2 - 122/15*x + 34/15
775
+
776
+ sage: m = matrix(QQ, 3, [(1/i)**j for i in range(2,5) for j in range(3)])
777
+ sage: m.determinant(algorithm='flint')
778
+ -1/288
779
+
780
+ sage: m = matrix(QQ, 4, [(-1)**n/n for n in range(1,17)])
781
+ sage: m.determinant(algorithm='pari') # needs sage.libs.pari
782
+ 2/70945875
783
+
784
+ sage: m = matrix(QQ, 5, [1/(i+j+1) for i in range(5) for j in range(5)])
785
+ sage: m.determinant(algorithm='integer')
786
+ 1/266716800000
787
+
788
+ On non-square matrices, the method raises a :exc:`ValueError`::
789
+
790
+ sage: matrix(QQ, 2, 3).determinant(algorithm='flint')
791
+ Traceback (most recent call last):
792
+ ...
793
+ ValueError: non square matrix
794
+ sage: matrix(QQ, 2, 3).determinant(algorithm='pari') # needs sage.libs.pari
795
+ Traceback (most recent call last):
796
+ ...
797
+ ValueError: non square matrix
798
+ sage: matrix(QQ, 2, 3).determinant(algorithm='integer')
799
+ Traceback (most recent call last):
800
+ ...
801
+ ValueError: non square matrix
802
+ sage: matrix(QQ, 2, 3).determinant(algorithm='generic')
803
+ Traceback (most recent call last):
804
+ ...
805
+ ValueError: non square matrix
806
+
807
+ TESTS:
808
+
809
+ Check that the four algorithms agree::
810
+
811
+ sage: # needs sage.libs.pari
812
+ sage: for _ in range(20):
813
+ ....: dim = randint(0, 30)
814
+ ....: m = random_matrix(QQ, dim, num_bound=10, den_bound=10)
815
+ ....: det_flint = m.determinant("flint"); m._clear_cache()
816
+ ....: det_pari = m.determinant("pari"); m._clear_cache()
817
+ ....: det_int = m.determinant("integer"); m._clear_cache()
818
+ ....: det_gen = m.determinant("generic")
819
+ ....: assert det_flint == det_pari == det_int == det_gen
820
+ """
821
+ if self._nrows != self._ncols:
822
+ raise ValueError("non square matrix")
823
+
824
+ det = self.fetch('det')
825
+ if det is not None:
826
+ return det
827
+
828
+ if algorithm is None or algorithm == "flint":
829
+ det = self._det_flint()
830
+ elif algorithm == "pari":
831
+ from .matrix_rational_pari import _det_pari
832
+ det = _det_pari(self)
833
+ elif algorithm == "integer":
834
+ A, denom = self._clear_denom()
835
+ det = Rational(A.determinant(proof=proof))
836
+ if not denom.is_one():
837
+ det = det / (denom ** self.nrows())
838
+ elif algorithm == "generic":
839
+ det = Matrix_dense.determinant(self)
840
+ else:
841
+ raise ValueError("unknown algorithm '%s'" % algorithm)
842
+
843
+ self.cache('det', det)
844
+ return det
845
+
846
+ def _det_flint(self):
847
+ r"""
848
+ Return the determinant (computed using flint).
849
+
850
+ EXAMPLES::
851
+
852
+ sage: matrix(QQ, 2, [1/3, 2/5, 3/4, 7/8])._det_flint()
853
+ -1/120
854
+ sage: matrix(QQ, 0)._det_flint()
855
+ 1
856
+ sage: matrix(QQ, 1, [0])._det_flint()
857
+ 0
858
+ """
859
+ cdef Rational d = Rational.__new__(Rational)
860
+ cdef fmpq_t e
861
+ fmpq_init(e)
862
+ sig_on()
863
+ fmpq_mat_det(e, self._matrix)
864
+ fmpq_get_mpq(d.value, e)
865
+ sig_off()
866
+ return d
867
+
868
+ def denominator(self):
869
+ """
870
+ Return the denominator of this matrix.
871
+
872
+ OUTPUT: a Sage Integer
873
+
874
+ EXAMPLES::
875
+
876
+ sage: b = matrix(QQ,2,range(6)); b[0,0]=-5007/293; b
877
+ [-5007/293 1 2]
878
+ [ 3 4 5]
879
+ sage: b.denominator()
880
+ 293
881
+
882
+ sage: matrix(QQ, 2, [1/2, 1/3, 1/4, 1/5]).denominator()
883
+ 60
884
+ """
885
+ cdef Integer z = Integer.__new__(Integer)
886
+ cdef fmpz_t tmp
887
+ fmpz_init(tmp)
888
+ self.fmpz_denom(tmp)
889
+ fmpz_get_mpz(z.value, tmp)
890
+ fmpz_clear(tmp)
891
+ return z
892
+
893
+ cdef int fmpz_denom(self, fmpz_t d) except -1:
894
+ cdef Py_ssize_t i, j
895
+ sig_on()
896
+ fmpz_one(d)
897
+ for i in range(self._nrows):
898
+ for j in range(self._ncols):
899
+ fmpz_lcm(d, d, fmpq_mat_entry_den(self._matrix, i, j))
900
+ sig_off()
901
+ return 0
902
+
903
+ def _clear_denom(self):
904
+ r"""
905
+ INPUT:
906
+
907
+ - ``self`` -- a matrix
908
+
909
+ OUTPUT: ``D*self, D``
910
+
911
+ The product is a matrix over `\ZZ`.
912
+
913
+ EXAMPLES::
914
+
915
+ sage: a = matrix(QQ,2,[-1/6,-7,3,5/4]); a
916
+ [-1/6 -7]
917
+ [ 3 5/4]
918
+ sage: b, d = a._clear_denom()
919
+ sage: b
920
+ [ -2 -84]
921
+ [ 36 15]
922
+ sage: d
923
+ 12
924
+ sage: b == d * a
925
+ True
926
+ """
927
+ X = self.fetch('clear_denom')
928
+ if X is not None:
929
+ return X
930
+
931
+ cdef Py_ssize_t i, j
932
+ cdef Matrix_integer_dense A
933
+ cdef fmpz * entry
934
+ cdef fmpz_t denom
935
+ fmpz_init(denom)
936
+ self.fmpz_denom(denom)
937
+
938
+ from sage.matrix.matrix_space import MatrixSpace
939
+ MZ = MatrixSpace(ZZ, self._nrows, self._ncols, sparse=False)
940
+ A = Matrix_integer_dense.__new__(Matrix_integer_dense, MZ, None, None, None)
941
+
942
+ sig_on()
943
+ for i in range(self._nrows):
944
+ for j in range(self._ncols):
945
+ entry = fmpz_mat_entry(A._matrix, i, j)
946
+ fmpz_divexact(entry, denom, fmpq_mat_entry_den(self._matrix, i, j))
947
+ fmpz_mul(entry, entry, fmpq_mat_entry_num(self._matrix, i, j))
948
+ sig_off()
949
+
950
+ cdef Integer D = PY_NEW(Integer)
951
+ fmpz_get_mpz(D.value, denom)
952
+ fmpz_clear(denom)
953
+ X = (A, D)
954
+ self.cache('clear_denom', X)
955
+ return X
956
+
957
+ def charpoly(self, var='x', algorithm=None):
958
+ r"""
959
+ Return the characteristic polynomial of this matrix.
960
+
961
+ .. NOTE::
962
+
963
+ The characteristic polynomial is defined as `\det(xI-A)`.
964
+
965
+ INPUT:
966
+
967
+ - ``var`` -- (optional) name of the variable as a string
968
+
969
+ - ``algorithm`` -- an optional specification of an algorithm. It can be
970
+ one of:
971
+
972
+ - ``None``: (default) will use flint for small dimensions and linbox
973
+ otherwise
974
+
975
+ - ``'flint'``: uses flint library
976
+
977
+ - ``'linbox'``: uses linbox library
978
+
979
+ - ``'generic'``: uses Sage generic implementation
980
+
981
+ OUTPUT: a polynomial over the rational numbers
982
+
983
+ EXAMPLES::
984
+
985
+ sage: a = matrix(QQ, 3, [4/3, 2/5, 1/5, 4, -3/2, 0, 0, -2/3, 3/4])
986
+ sage: f = a.charpoly(); f
987
+ x^3 - 7/12*x^2 - 149/40*x + 97/30
988
+ sage: f(a)
989
+ [0 0 0]
990
+ [0 0 0]
991
+ [0 0 0]
992
+
993
+ TESTS:
994
+
995
+ The cached polynomial should be independent of the ``var``
996
+ argument (:issue:`12292`). We check (indirectly) that the
997
+ second call uses the cached value by noting that its result is
998
+ not cached::
999
+
1000
+ sage: M = MatrixSpace(QQ, 2)
1001
+ sage: A = M(range(0, 2^2))
1002
+ sage: type(A)
1003
+ <class 'sage.matrix.matrix_rational_dense.Matrix_rational_dense'>
1004
+ sage: A.charpoly('x')
1005
+ x^2 - 3*x - 2
1006
+ sage: A.charpoly('y')
1007
+ y^2 - 3*y - 2
1008
+ sage: A._cache['charpoly']
1009
+ x^2 - 3*x - 2
1010
+
1011
+ Check consistency::
1012
+
1013
+ sage: for _ in range(100): # needs sage.libs.linbox
1014
+ ....: dim = randint(0, 10)
1015
+ ....: m = random_matrix(QQ, dim, num_bound=8, den_bound=8)
1016
+ ....: p_flint = m.charpoly(algorithm='flint'); m._clear_cache()
1017
+ ....: p_linbox = m.charpoly(algorithm='linbox'); m._clear_cache()
1018
+ ....: p_generic = m.charpoly(algorithm='generic')
1019
+ ....: assert p_flint == p_linbox == p_generic
1020
+ """
1021
+ poly = self.fetch('charpoly')
1022
+ if poly is not None:
1023
+ return poly.change_variable_name(var)
1024
+
1025
+ if algorithm is None:
1026
+ algorithm = 'flint' if self._nrows <= 40 else 'linbox'
1027
+
1028
+ if algorithm == 'flint' or algorithm == 'linbox':
1029
+ A, denom = self._clear_denom()
1030
+ f = A.charpoly(var, algorithm=algorithm)
1031
+ x = f.parent().gen()
1032
+ g = f(x * denom) / denom ** f.degree()
1033
+ elif algorithm == 'generic':
1034
+ g = Matrix_dense.charpoly(self, var)
1035
+ else:
1036
+ raise ValueError("no algorithm '%s'" % algorithm)
1037
+
1038
+ self.cache('charpoly', g)
1039
+ return g
1040
+
1041
+ def minpoly(self, var='x', algorithm=None):
1042
+ """
1043
+ Return the minimal polynomial of this matrix.
1044
+
1045
+ INPUT:
1046
+
1047
+ - ``var`` -- (optional) the variable name as a string (default: ``'x'``)
1048
+
1049
+ - ``algorithm`` -- an optional specification of an algorithm. It can
1050
+ be one of
1051
+
1052
+ - ``None``: (default) will use linbox
1053
+
1054
+ - ``'linbox'``: uses the linbox library
1055
+
1056
+ - ``'generic'``: uses the generic Sage implementation
1057
+
1058
+ OUTPUT: a polynomial over the rationals
1059
+
1060
+ EXAMPLES::
1061
+
1062
+ sage: a = matrix(QQ, 3, [4/3, 2/5, 1/5, 4, -3/2, 0, 0, -2/3, 3/4])
1063
+ sage: f = a.minpoly(); f
1064
+ x^3 - 7/12*x^2 - 149/40*x + 97/30
1065
+ sage: a = Mat(ZZ,4)(range(16))
1066
+ sage: f = a.minpoly(); f.factor() # needs sage.libs.pari
1067
+ x * (x^2 - 30*x - 80)
1068
+ sage: f(a) == 0 # needs sage.libs.pari
1069
+ True
1070
+
1071
+ ::
1072
+
1073
+ sage: # needs sage.libs.pari
1074
+ sage: a = matrix(QQ, 4, [1..4^2])
1075
+ sage: factor(a.minpoly())
1076
+ x * (x^2 - 34*x - 80)
1077
+ sage: factor(a.minpoly('y'))
1078
+ y * (y^2 - 34*y - 80)
1079
+ sage: factor(a.charpoly())
1080
+ x^2 * (x^2 - 34*x - 80)
1081
+ sage: b = matrix(QQ, 4, [-1, 2, 2, 0, 0, 4, 2, 2, 0, 0, -1, -2, 0, -4, 0, 4])
1082
+ sage: a = matrix(QQ, 4, [1, 1, 0,0, 0,1,0,0, 0,0,5,0, 0,0,0,5])
1083
+ sage: c = b^(-1)*a*b
1084
+ sage: factor(c.minpoly())
1085
+ (x - 5) * (x - 1)^2
1086
+ sage: factor(c.charpoly())
1087
+ (x - 5)^2 * (x - 1)^2
1088
+
1089
+ Check consistency::
1090
+
1091
+ sage: for _ in range(100): # needs sage.libs.linbox sage.libs.pari
1092
+ ....: dim = randint(0, 10)
1093
+ ....: m = random_matrix(QQ, dim, num_bound=8, den_bound=8)
1094
+ ....: p_linbox = m.charpoly(algorithm='linbox'); m._clear_cache()
1095
+ ....: p_generic = m.charpoly(algorithm='generic')
1096
+ ....: assert p_linbox == p_generic
1097
+ """
1098
+ poly = self.fetch('minpoly')
1099
+ if poly is not None:
1100
+ return poly.change_variable_name(var)
1101
+
1102
+ if algorithm is None:
1103
+ try:
1104
+ from .matrix_integer_linbox import _minpoly_linbox
1105
+ except ImportError:
1106
+ algorithm = 'generic'
1107
+ else:
1108
+ algorithm = 'linbox'
1109
+
1110
+ if algorithm == 'linbox':
1111
+ A, denom = self._clear_denom()
1112
+ f = A.minpoly(var, algorithm='linbox')
1113
+ x = f.parent().gen()
1114
+ g = f(x * denom) / denom**f.degree()
1115
+ elif algorithm == 'generic':
1116
+ g = Matrix_dense.minpoly(self, var)
1117
+ else:
1118
+ raise ValueError("no algorithm '%s'" % algorithm)
1119
+
1120
+ self.cache('minpoly', g)
1121
+ return g
1122
+
1123
+ cdef sage.structure.element.Matrix _matrix_times_matrix_(self, sage.structure.element.Matrix right):
1124
+ """
1125
+ EXAMPLES::
1126
+
1127
+ sage: a = matrix(QQ, 3, range(9))/3
1128
+ sage: b = matrix(QQ, 3, range(1, 10))/5
1129
+ sage: a * b # indirect doctest
1130
+ [ 6/5 7/5 8/5]
1131
+ [18/5 22/5 26/5]
1132
+ [ 6 37/5 44/5]
1133
+
1134
+ sage: matrix(QQ, 2, 3) * matrix(QQ, 4, 5)
1135
+ Traceback (most recent call last):
1136
+ ...
1137
+ TypeError: unsupported operand parent(s) for *: 'Full MatrixSpace of 2 by 3 dense matrices over Rational Field' and 'Full MatrixSpace of 4 by 5 dense matrices over Rational Field'
1138
+ """
1139
+ return self._multiply_flint(right)
1140
+
1141
+ def _multiply_flint(self, Matrix_rational_dense right):
1142
+ r"""
1143
+ Multiply this matrix by ``right`` using the flint library.
1144
+
1145
+ EXAMPLES::
1146
+
1147
+ sage: n = 3
1148
+ sage: a = matrix(QQ,n,range(n^2))/3
1149
+ sage: b = matrix(QQ,n,range(1, n^2 + 1))/5
1150
+ sage: a._multiply_flint(b)
1151
+ [ 6/5 7/5 8/5]
1152
+ [18/5 22/5 26/5]
1153
+ [ 6 37/5 44/5]
1154
+ """
1155
+ if self._nrows == right._nrows:
1156
+ # self acts on the space of right
1157
+ parent = right.parent()
1158
+ if self._ncols == right._ncols:
1159
+ # right acts on the space of self
1160
+ parent = self.parent()
1161
+ else:
1162
+ parent = self.matrix_space(self._nrows, right._ncols)
1163
+
1164
+ cdef Matrix_rational_dense ans
1165
+ ans = Matrix_rational_dense.__new__(Matrix_rational_dense, parent, None, None, None)
1166
+
1167
+ sig_on()
1168
+ fmpq_mat_mul(ans._matrix, self._matrix, (<Matrix_rational_dense> right)._matrix)
1169
+ sig_off()
1170
+ return ans
1171
+
1172
+ def _multiply_over_integers(self, Matrix_rational_dense right, algorithm='default'):
1173
+ r"""
1174
+ Multiply this matrix by right using a multimodular algorithm and
1175
+ return the result.
1176
+
1177
+ INPUT:
1178
+
1179
+ - ``self`` -- matrix over QQ
1180
+
1181
+ - ``right`` -- matrix over QQ
1182
+
1183
+ - ``algorithm``
1184
+
1185
+ - 'default': use whatever is the default for A\*B when A, B
1186
+ are over ZZ.
1187
+
1188
+ - 'multimodular': use a multimodular algorithm
1189
+
1190
+ EXAMPLES::
1191
+
1192
+ sage: a = MatrixSpace(QQ,10,5)(range(50))
1193
+ sage: b = MatrixSpace(QQ,5,12)([1/n for n in range(1,61)])
1194
+ sage: a._multiply_over_integers(b) == a._multiply_over_integers(b, algorithm='multimodular')
1195
+ True
1196
+
1197
+ ::
1198
+
1199
+ sage: a = MatrixSpace(QQ,3)(range(9))
1200
+ sage: b = MatrixSpace(QQ,3)([1/n for n in range(1,10)])
1201
+ sage: c = a._multiply_over_integers(b, algorithm = 'multimodular')
1202
+ sage: c
1203
+ [ 15/28 9/20 7/18]
1204
+ [ 33/7 117/40 20/9]
1205
+ [249/28 27/5 73/18]
1206
+ sage: c == a._multiply_flint(b)
1207
+ True
1208
+ """
1209
+ cdef Matrix_integer_dense A, B, AB
1210
+ cdef Matrix_rational_dense res
1211
+ cdef Integer D
1212
+ sig_on()
1213
+ A, A_denom = self._clear_denom()
1214
+ B, B_denom = right._clear_denom()
1215
+ if algorithm == 'default' or algorithm == 'multimodular':
1216
+ AB = A*B
1217
+ else:
1218
+ sig_off()
1219
+ raise ValueError("unknown algorithm '%s'" % algorithm)
1220
+ D = A_denom * B_denom
1221
+ if self._nrows == right._nrows:
1222
+ # self acts on the space of right
1223
+ res = Matrix_rational_dense.__new__(Matrix_rational_dense, right.parent(), 0, 0, 0)
1224
+ if self._ncols == right._ncols:
1225
+ # right acts on the space of self
1226
+ res = Matrix_rational_dense.__new__(Matrix_rational_dense, self.parent(), 0, 0, 0)
1227
+ else:
1228
+ res = Matrix_rational_dense.__new__(Matrix_rational_dense, self.matrix_space(AB._nrows, AB._ncols), 0, 0, 0)
1229
+ for i in range(res._nrows):
1230
+ for j in range(res._ncols):
1231
+ fmpz_set(fmpq_mat_entry_num(res._matrix, i, j), fmpz_mat_entry(AB._matrix,i,j))
1232
+ fmpz_set_mpz(fmpq_mat_entry_den(res._matrix, i, j), D.value)
1233
+ fmpq_canonicalise(fmpq_mat_entry(res._matrix, i, j))
1234
+ sig_off()
1235
+ return res
1236
+
1237
+ def height(self):
1238
+ """
1239
+ Return the height of this matrix, which is the maximum of the
1240
+ absolute values of all numerators and denominators of entries in
1241
+ this matrix.
1242
+
1243
+ OUTPUT: integer
1244
+
1245
+ EXAMPLES::
1246
+
1247
+ sage: b = matrix(QQ,2,range(6)); b[0,0]=-5007/293; b
1248
+ [-5007/293 1 2]
1249
+ [ 3 4 5]
1250
+ sage: b.height()
1251
+ 5007
1252
+ """
1253
+ cdef Integer z
1254
+ cdef fmpz_t tmp
1255
+ fmpz_init(tmp)
1256
+ self.fmpz_height(tmp)
1257
+ z = PY_NEW(Integer)
1258
+ fmpz_get_mpz(z.value, tmp)
1259
+ fmpz_clear(tmp)
1260
+ return z
1261
+
1262
+ cdef int fmpz_height(self, fmpz_t h) except -1:
1263
+ cdef fmpz_t x
1264
+ cdef Py_ssize_t i, j
1265
+ sig_on()
1266
+ fmpz_init(x)
1267
+ fmpz_zero(h)
1268
+ for i in range(self._nrows):
1269
+ for j in range(self._ncols):
1270
+ fmpz_abs(x, fmpq_mat_entry_num(self._matrix, i, j))
1271
+ if fmpz_cmp(h, x) < 0:
1272
+ fmpz_set(h, x)
1273
+ fmpz_abs(x, fmpq_mat_entry_den(self._matrix, i, j))
1274
+ if fmpz_cmp(h, x) < 0:
1275
+ fmpz_set(h, x)
1276
+ fmpz_clear(x)
1277
+ sig_off()
1278
+ return 0
1279
+
1280
+ def _adjugate(self):
1281
+ """
1282
+ Return the adjugate of this matrix.
1283
+
1284
+ Assumes ``self`` is a square matrix (checked in adjugate).
1285
+
1286
+ EXAMPLES::
1287
+
1288
+ sage: m = matrix(QQ,3,[1..9])/9; m
1289
+ [1/9 2/9 1/3]
1290
+ [4/9 5/9 2/3]
1291
+ [7/9 8/9 1]
1292
+ sage: m.adjugate() # needs sage.libs.pari
1293
+ [-1/27 2/27 -1/27]
1294
+ [ 2/27 -4/27 2/27]
1295
+ [-1/27 2/27 -1/27]
1296
+ """
1297
+ return self.parent()(self.__pari__().matadjoint().sage())
1298
+
1299
+ def _magma_init_(self, magma):
1300
+ """
1301
+ EXAMPLES::
1302
+
1303
+ sage: m = matrix(QQ,2,3,[1,2/3,-3/4,1,-2/3,-45/17])
1304
+ sage: m._magma_init_(magma)
1305
+ 'Matrix(RationalField(),2,3,StringToIntegerSequence("204 136 -153 204 -136 -540"))/204'
1306
+ sage: magma(m) # optional - magma
1307
+ [ 1 2/3 -3/4]
1308
+ [ 1 -2/3 -45/17]
1309
+ """
1310
+ X, d = self._clear_denom()
1311
+ s = X._magma_init_(magma).replace('IntegerRing','RationalField')
1312
+ if d != 1:
1313
+ s += '/%s' % d._magma_init_(magma)
1314
+ return s
1315
+
1316
+ def prod_of_row_sums(self, cols):
1317
+ cdef Py_ssize_t i, c
1318
+ cdef fmpq_t s, pr
1319
+ fmpq_init(s)
1320
+ fmpq_init(pr)
1321
+
1322
+ fmpq_one(pr)
1323
+ for i in range(self._nrows):
1324
+ fmpq_zero(s)
1325
+ for c in cols:
1326
+ if c < 0 or c >= self._ncols:
1327
+ raise IndexError("matrix column index out of range")
1328
+ fmpq_add(s, s, fmpq_mat_entry(self._matrix, i, c))
1329
+ fmpq_mul(pr, pr, s)
1330
+ cdef Rational ans
1331
+ ans = Rational.__new__(Rational)
1332
+ fmpq_get_mpq(ans.value, pr)
1333
+ fmpq_clear(s)
1334
+ fmpq_clear(pr)
1335
+ return ans
1336
+
1337
+ def _right_kernel_matrix(self, **kwds):
1338
+ r"""
1339
+ Return a pair that includes a matrix of basis vectors
1340
+ for the right kernel of ``self``.
1341
+
1342
+ INPUT:
1343
+
1344
+ - ``kwds`` -- these are provided for consistency with other versions
1345
+ of this method. Here they are ignored as there is no optional
1346
+ behavior available.
1347
+
1348
+ OUTPUT:
1349
+
1350
+ Returns a pair. First item is the string 'computed-iml-rational'
1351
+ that identifies the nature of the basis vectors.
1352
+
1353
+ Second item is a matrix whose rows are a basis for the right kernel,
1354
+ over the rationals, as computed by the IML library. Notice that the
1355
+ IML library returns a matrix that is in the 'pivot' format, once the
1356
+ whole matrix is multiplied by -1. So the 'computed' format is very
1357
+ close to the 'pivot' format.
1358
+
1359
+ EXAMPLES::
1360
+
1361
+ sage: A = matrix(QQ, [
1362
+ ....: [1, 0, 1, -3, 1],
1363
+ ....: [-5, 1, 0, 7, -3],
1364
+ ....: [0, -1, -4, 6, -2],
1365
+ ....: [4, -1, 0, -6, 2]])
1366
+ sage: result = A._right_kernel_matrix()
1367
+ sage: result[0] # needs sage.libs.iml
1368
+ 'computed-iml-rational'
1369
+ sage: result[1]
1370
+ [-1 2 -2 -1 0]
1371
+ [ 1 2 0 0 -1]
1372
+ sage: X = result[1].transpose()
1373
+ sage: A*X == zero_matrix(QQ, 4, 2)
1374
+ True
1375
+
1376
+ Computed result is the negative of the pivot basis, which
1377
+ is just slightly more efficient to compute. ::
1378
+
1379
+ sage: A.right_kernel_matrix(basis='pivot') == -A.right_kernel_matrix(basis='computed')
1380
+ True
1381
+
1382
+ TESTS:
1383
+
1384
+ We test three trivial cases. ::
1385
+
1386
+ sage: A = matrix(QQ, 0, 2)
1387
+ sage: A._right_kernel_matrix()[1]
1388
+ [1 0]
1389
+ [0 1]
1390
+ sage: A = matrix(QQ, 2, 0)
1391
+ sage: A._right_kernel_matrix()[1].parent()
1392
+ Full MatrixSpace of 0 by 0 dense matrices over Rational Field
1393
+ sage: A = zero_matrix(QQ, 4, 3)
1394
+ sage: A._right_kernel_matrix()[1]
1395
+ [1 0 0]
1396
+ [0 1 0]
1397
+ [0 0 1]
1398
+ """
1399
+ tm = verbose("computing right kernel matrix over the rationals for %sx%s matrix" % (self.nrows(), self.ncols()),level=1)
1400
+ # _rational_kernel_flint() gets the zero-row case wrong, fix it there
1401
+ if self.nrows()==0:
1402
+ from sage.matrix.constructor import identity_matrix
1403
+ K = identity_matrix(QQ, self.ncols())
1404
+ else:
1405
+ try:
1406
+ from .matrix_integer_iml import _rational_kernel_iml
1407
+ except ImportError:
1408
+ return self._right_kernel_matrix_over_field()
1409
+ A, _ = self._clear_denom()
1410
+ K = _rational_kernel_iml(A).transpose().change_ring(QQ)
1411
+ verbose("done computing right kernel matrix over the rationals for %sx%s matrix" % (self.nrows(), self.ncols()),level=1, t=tm)
1412
+ return 'computed-iml-rational', K
1413
+
1414
+ # ###############################################
1415
+ # Change ring
1416
+ # ###############################################
1417
+ def change_ring(self, R):
1418
+ """
1419
+ Create the matrix over R with entries the entries of ``self`` coerced
1420
+ into R.
1421
+
1422
+ EXAMPLES::
1423
+
1424
+ sage: a = matrix(QQ,2,[1/2,-1,2,3])
1425
+ sage: a.change_ring(GF(3))
1426
+ [2 2]
1427
+ [2 0]
1428
+ sage: a.change_ring(ZZ)
1429
+ Traceback (most recent call last):
1430
+ ...
1431
+ TypeError: matrix has denominators so can...t change to ZZ
1432
+ sage: b = a.change_ring(QQ['x']); b
1433
+ [1/2 -1]
1434
+ [ 2 3]
1435
+ sage: b.parent()
1436
+ Full MatrixSpace of 2 by 2 dense matrices over Univariate Polynomial Ring in x over Rational Field
1437
+
1438
+ TESTS:
1439
+
1440
+ Make sure that subdivisions are preserved when changing rings::
1441
+
1442
+ sage: a = matrix(QQ, 3, range(9))
1443
+ sage: a.subdivide(2,1); a
1444
+ [0|1 2]
1445
+ [3|4 5]
1446
+ [-+---]
1447
+ [6|7 8]
1448
+ sage: a.change_ring(ZZ).change_ring(QQ)
1449
+ [0|1 2]
1450
+ [3|4 5]
1451
+ [-+---]
1452
+ [6|7 8]
1453
+ sage: a.change_ring(GF(3))
1454
+ [0|1 2]
1455
+ [0|1 2]
1456
+ [-+---]
1457
+ [0|1 2]
1458
+ """
1459
+ if R not in Rings():
1460
+ raise TypeError("R must be a ring")
1461
+ if R == self._base_ring:
1462
+ if self._is_immutable:
1463
+ return self
1464
+ return self.__copy__()
1465
+ if isinstance(R, IntegerRing_class):
1466
+ A, d = self._clear_denom()
1467
+ if not d.is_one():
1468
+ raise TypeError("matrix has denominators so can't change to ZZ")
1469
+ if self._subdivisions is not None:
1470
+ A.subdivide(self.subdivisions())
1471
+ return A
1472
+
1473
+ if isinstance(R, sage.rings.abc.IntegerModRing):
1474
+ try:
1475
+ from sage.matrix.matrix_modn_dense_double import MAX_MODULUS
1476
+ except ImportError:
1477
+ pass
1478
+ else:
1479
+ if R.order() < MAX_MODULUS:
1480
+ b = R.order()
1481
+ A, d = self._clear_denom()
1482
+ if not b.gcd(d).is_one():
1483
+ raise TypeError("matrix denominator not coprime to modulus")
1484
+ B = A._mod_int(b)
1485
+ C = (1/(B.base_ring()(d))) * B
1486
+ if self._subdivisions is not None:
1487
+ C.subdivide(self.subdivisions())
1488
+ return C
1489
+
1490
+ # fallback to the generic version
1491
+ return Matrix_dense.change_ring(self, R)
1492
+
1493
+ # ###############################################
1494
+ # Echelon form
1495
+ # ###############################################
1496
+ def echelonize(self, algorithm=None,
1497
+ height_guess=None, proof=None, **kwds):
1498
+ """
1499
+ Transform the matrix ``self`` into reduced row echelon form
1500
+ in place.
1501
+
1502
+ INPUT:
1503
+
1504
+ - ``algorithm`` -- an optional specification of an algorithm. One of
1505
+
1506
+ - ``None``: (default) try to pick the best choice,
1507
+
1508
+ - ``'flint'``: use flint library
1509
+ `function <https://flintlib.org/doc/fmpq_mat.html#c.fmpq_mat_rref>`_,
1510
+ which automatically chooses between
1511
+ `classical algorithm <https://flintlib.org/doc/fmpq_mat.html#c.fmpq_mat_rref_classical>`_
1512
+ (Gaussian elimination),
1513
+ `fraction-free multimodular <https://flintlib.org/doc/fmpz_mat.html#c.fmpz_mat_rref_mul>`_,
1514
+ and `fraction-free LU decomposition <https://flintlib.org/doc/fmpz_mat.html#c.fmpz_mat_rref_fflu>`_,
1515
+
1516
+ - ``'flint:classical'``, ``'flint:multimodular'``, ``'flint:fflu'``: use the
1517
+ flint library as above, but select an algorithm explicitly,
1518
+
1519
+ - ``'padic'``: an algorithm based on the IML `p`-adic solver,
1520
+
1521
+ - ``'multimodular'``: uses a multimodular algorithm implemented in Cython
1522
+ that uses linbox modulo many primes,
1523
+ see :func:`~sage.matrix.misc.matrix_rational_echelon_form_multimodular`,
1524
+
1525
+ - ``'classical'``: just clear each column using Gauss elimination.
1526
+
1527
+ - ``height_guess``, ``**kwds`` -- all passed to the
1528
+ ``'multimodular'`` algorithm; ignored by other algorithms
1529
+
1530
+ - ``proof`` -- boolean or ``None`` (default: None, see
1531
+ proof.linear_algebra or sage.structure.proof). Passed to the
1532
+ ``'multimodular'`` algorithm. Note that the Sage global default is
1533
+ ``proof=True``.
1534
+
1535
+ EXAMPLES::
1536
+
1537
+ sage: a = matrix(QQ, 4, range(16)); a[0,0] = 1/19; a[0,1] = 1/5; a
1538
+ [1/19 1/5 2 3]
1539
+ [ 4 5 6 7]
1540
+ [ 8 9 10 11]
1541
+ [ 12 13 14 15]
1542
+ sage: a.echelonize()
1543
+ sage: a
1544
+ [ 1 0 0 -76/157]
1545
+ [ 0 1 0 -5/157]
1546
+ [ 0 0 1 238/157]
1547
+ [ 0 0 0 0]
1548
+
1549
+ ::
1550
+
1551
+ sage: # needs sage.libs.linbox
1552
+ sage: a = matrix(QQ, 4, range(16)); a[0,0] = 1/19; a[0,1] = 1/5
1553
+ sage: a.echelonize(algorithm='multimodular')
1554
+ sage: a
1555
+ [ 1 0 0 -76/157]
1556
+ [ 0 1 0 -5/157]
1557
+ [ 0 0 1 238/157]
1558
+ [ 0 0 0 0]
1559
+
1560
+ TESTS:
1561
+
1562
+ Echelonizing a matrix in place throws away the cache of
1563
+ the old matrix (:issue:`14506`)::
1564
+
1565
+ sage: for algo in ["flint", "padic", "multimodular", "classical", # needs sage.libs.linbox
1566
+ ....: "flint:classical", "flint:multimodular", "flint:fflu"]:
1567
+ ....: a = Matrix(QQ, [[1,2],[3,4]])
1568
+ ....: _ = a.det() # fills the cache
1569
+ ....: _ = a._clear_denom() # fills the cache
1570
+ ....: a.echelonize(algorithm=algo)
1571
+ ....: assert sorted(a._cache.keys()) == ['echelon_form', 'in_echelon_form', 'pivots', 'rank'], (algo, a._cache.keys())
1572
+ """
1573
+ if self.fetch('in_echelon_form'):
1574
+ return # already known to be in echelon form
1575
+ self.check_mutability()
1576
+
1577
+ if algorithm is None:
1578
+ algorithm = 'flint:multimodular'
1579
+
1580
+ if algorithm in ('flint', 'flint:classical', 'flint:multimodular', 'flint:fflu'):
1581
+ pivots = self._echelonize_flint(algorithm)
1582
+ elif algorithm == 'multimodular':
1583
+ pivots = self._echelonize_multimodular(height_guess, proof, **kwds)
1584
+ elif algorithm == 'classical':
1585
+ pivots = self._echelon_in_place_classical()
1586
+ elif algorithm == 'padic':
1587
+ pivots = self._echelonize_padic()
1588
+ else:
1589
+ raise ValueError("no algorithm '%s'" % algorithm)
1590
+
1591
+ if type(pivots) is not tuple:
1592
+ raise RuntimeError("BUG: pivots must get set as a tuple. Got {} for algo {} with {}x{} matrix.".format(
1593
+ type(pivots), algorithm, self._nrows, self._ncols))
1594
+
1595
+ self.cache('in_echelon_form', True)
1596
+ self.cache('echelon_form', self)
1597
+ self.cache('pivots', pivots)
1598
+ self.cache('rank', len(pivots))
1599
+
1600
+ def echelon_form(self, algorithm=None,
1601
+ height_guess=None, proof=None, **kwds):
1602
+ r"""
1603
+ Return the echelon form of this matrix.
1604
+
1605
+ The (row) echelon form of a matrix, see :wikipedia:`Row_echelon_form`,
1606
+ is the matrix obtained by performing Gauss elimination on the rows
1607
+ of the matrix.
1608
+
1609
+ INPUT: See :meth:`echelonize` for the options.
1610
+
1611
+ EXAMPLES::
1612
+
1613
+ sage: a = matrix(QQ, 4, range(16)); a[0,0] = 1/19; a[0,1] = 1/5; a
1614
+ [1/19 1/5 2 3]
1615
+ [ 4 5 6 7]
1616
+ [ 8 9 10 11]
1617
+ [ 12 13 14 15]
1618
+ sage: a.echelon_form()
1619
+ [ 1 0 0 -76/157]
1620
+ [ 0 1 0 -5/157]
1621
+ [ 0 0 1 238/157]
1622
+ [ 0 0 0 0]
1623
+ sage: a.echelon_form(algorithm='multimodular')
1624
+ [ 1 0 0 -76/157]
1625
+ [ 0 1 0 -5/157]
1626
+ [ 0 0 1 238/157]
1627
+ [ 0 0 0 0]
1628
+
1629
+ The result is an immutable matrix, so if you want to modify the result
1630
+ then you need to make a copy. This checks that :issue:`10543` is
1631
+ fixed.::
1632
+
1633
+ sage: A = matrix(QQ, 2, range(6))
1634
+ sage: E = A.echelon_form()
1635
+ sage: E.is_mutable()
1636
+ False
1637
+ sage: F = copy(E)
1638
+ sage: F[0,0] = 50
1639
+ sage: F
1640
+ [50 0 -1]
1641
+ [ 0 1 2]
1642
+
1643
+ TESTS:
1644
+
1645
+ Check consistency::
1646
+
1647
+ sage: for _ in range(100): # needs sage.libs.linbox
1648
+ ....: nrows = randint(0, 30)
1649
+ ....: ncols = randint(0, 30)
1650
+ ....: m = random_matrix(QQ, nrows, ncols, num_bound=10, den_bound=10)
1651
+ ....: ech_flint = m.echelon_form('flint'); m._clear_cache()
1652
+ ....: ech_padic = m.echelon_form('padic'); m._clear_cache()
1653
+ ....: ech_multi = m.echelon_form('multimodular'); m._clear_cache()
1654
+ ....: ech_class = m.echelon_form('classical')
1655
+ ....: assert ech_flint == ech_padic == ech_multi == ech_class
1656
+ """
1657
+ x = self.fetch('echelon_form')
1658
+ if x is not None:
1659
+ return x
1660
+ if self.fetch('in_echelon_form'):
1661
+ raise RuntimeError('in_echelon_form set but not echelon_form')
1662
+
1663
+ E = self.__copy__()
1664
+ E.echelonize(algorithm)
1665
+ E.set_immutable()
1666
+ self.cache('echelon_form', E)
1667
+ self.cache('pivots', E.pivots())
1668
+ self.cache('rank', len(E.pivots()))
1669
+ return E
1670
+
1671
+ def _echelonize_flint(self, algorithm: str):
1672
+ r"""
1673
+ INPUT: See :meth:`echelonize` for the options.
1674
+ Only options that use flint are allowed, passing other algorithms may
1675
+ trigger undefined behavior.
1676
+
1677
+ EXAMPLES::
1678
+
1679
+ sage: m = matrix(QQ, 4, range(16))
1680
+ sage: m._echelonize_flint("flint")
1681
+ (0, 1)
1682
+ sage: m
1683
+ [ 1 0 -1 -2]
1684
+ [ 0 1 2 3]
1685
+ [ 0 0 0 0]
1686
+ [ 0 0 0 0]
1687
+ sage: m = matrix(QQ, 4, 6, [-1,0,0,-2,-1,-2,-1,0,0,-2,-1,0,3,3,-2,0,0,3,-2,-3,1,1,-2,3])
1688
+ sage: m._echelonize_flint("flint")
1689
+ (0, 1, 2, 5)
1690
+ sage: m
1691
+ [ 1 0 0 2 1 0]
1692
+ [ 0 1 0 -4/3 1 0]
1693
+ [ 0 0 1 1 3 0]
1694
+ [ 0 0 0 0 0 1]
1695
+ """
1696
+ self.clear_cache()
1697
+
1698
+ if fmpq_mat_is_empty(self._matrix):
1699
+ return ()
1700
+
1701
+ cdef long r
1702
+ cdef fmpz_mat_t Aclear
1703
+ cdef fmpz_t den
1704
+
1705
+ sig_on()
1706
+
1707
+ if algorithm == 'flint':
1708
+ r = fmpq_mat_rref(self._matrix, self._matrix)
1709
+ elif algorithm == 'flint:classical':
1710
+ r = fmpq_mat_rref_classical(self._matrix, self._matrix)
1711
+ else:
1712
+ # copied from fmpq_mat_rref_fraction_free
1713
+ fmpz_mat_init(Aclear, self._nrows, self._ncols)
1714
+ fmpq_mat_get_fmpz_mat_rowwise(Aclear, NULL, self._matrix)
1715
+ fmpz_init(den)
1716
+
1717
+ if algorithm == 'flint:fflu':
1718
+ r = fmpz_mat_rref_fflu(Aclear, den, Aclear)
1719
+ else:
1720
+ assert algorithm == 'flint:multimodular'
1721
+ r = fmpz_mat_rref_mul(Aclear, den, Aclear)
1722
+
1723
+ if r == 0:
1724
+ fmpq_mat_zero(self._matrix)
1725
+ else:
1726
+ fmpq_mat_set_fmpz_mat_div_fmpz(self._matrix, Aclear, den)
1727
+
1728
+ fmpz_mat_clear(Aclear)
1729
+ fmpz_clear(den)
1730
+
1731
+ sig_off()
1732
+
1733
+ # compute pivots
1734
+ cdef long i, j, k
1735
+ cdef list p = []
1736
+ k = 0
1737
+ for i in range(r):
1738
+ for j in range(k, self._ncols):
1739
+ if not fmpq_is_zero(fmpq_mat_entry(self._matrix, i, j)):
1740
+ p.append(j)
1741
+ k = j+1 # so start at next position next time
1742
+ break
1743
+ else:
1744
+ break
1745
+ return tuple(p)
1746
+
1747
+ def _echelonize_padic(self):
1748
+ """
1749
+ Echelonize ``self`` using a `p`-adic nullspace algorithm.
1750
+
1751
+ EXAMPLES::
1752
+
1753
+ sage: # needs sage.libs.linbox
1754
+ sage: m = matrix(QQ, 4, range(16))
1755
+ sage: m._echelonize_padic()
1756
+ (0, 1)
1757
+ sage: m
1758
+ [ 1 0 -1 -2]
1759
+ [ 0 1 2 3]
1760
+ [ 0 0 0 0]
1761
+ [ 0 0 0 0]
1762
+ sage: m = matrix(QQ, 4, 6, [-1,0,0,-2,-1,-2,-1,0,0,-2,-1,0,3,3,-2,0,0,3,-2,-3,1,1,-2,3])
1763
+ sage: m._echelonize_padic()
1764
+ (0, 1, 2, 5)
1765
+ sage: m
1766
+ [ 1 0 0 2 1 0]
1767
+ [ 0 1 0 -4/3 1 0]
1768
+ [ 0 0 1 1 3 0]
1769
+ [ 0 0 0 0 0 1]
1770
+ """
1771
+ cdef Matrix_integer_dense X
1772
+ cdef Integer d
1773
+ cdef fmpq * entry
1774
+
1775
+ A, _ = self._clear_denom()
1776
+ pivots, nonpivots, X, d = A._rational_echelon_via_solve()
1777
+ self.clear_cache()
1778
+
1779
+ # FIXME: we should always have X.nrows() == len(pivots)
1780
+ if X.nrows() != len(pivots):
1781
+ assert X.ncols() == len(pivots) == 0
1782
+ assert type(pivots) is list
1783
+ fmpq_mat_zero(self._matrix)
1784
+ return tuple(pivots)
1785
+
1786
+ cdef Py_ssize_t i,j
1787
+ for i in range(X.nrows()):
1788
+ # 1 at pivot
1789
+ fmpq_one(fmpq_mat_entry(self._matrix, i, pivots[i]))
1790
+
1791
+ # nonzero part
1792
+ for j in range(X.ncols()):
1793
+ entry = fmpq_mat_entry(self._matrix, i, nonpivots[j])
1794
+ fmpz_set(fmpq_numref(entry), fmpz_mat_entry(X._matrix, i, j))
1795
+ fmpz_set_mpz(fmpq_denref(entry), d.value)
1796
+ fmpq_canonicalise(entry)
1797
+
1798
+ # zeros on the left of the pivot
1799
+ for j in range(pivots[i]):
1800
+ fmpq_zero(fmpq_mat_entry(self._matrix, i, j))
1801
+
1802
+ # zeros on top of the other pivots
1803
+ for j in range(i):
1804
+ fmpq_zero(fmpq_mat_entry(self._matrix, j, pivots[i]))
1805
+
1806
+ # Fill in the 0-rows at the bottom.
1807
+ for i in range(len(pivots), self._nrows):
1808
+ for j in range(self._ncols):
1809
+ fmpq_zero(fmpq_mat_entry(self._matrix, i, j))
1810
+
1811
+ # FIXME: pivots should already be a tuple in all cases
1812
+ return tuple(pivots)
1813
+
1814
+ def _echelonize_multimodular(self, height_guess=None, proof=None):
1815
+ """
1816
+ Echelonize ``self`` using multimodular recomposition.
1817
+
1818
+ REFERENCE:
1819
+
1820
+ - Chapter 7 of Stein's "Explicitly Computing Modular Forms".
1821
+
1822
+ INPUT:
1823
+
1824
+ - ``height_guess`` -- integer or ``None``
1825
+
1826
+ - ``proof`` -- boolean (default: ``None``, see
1827
+ proof.linear_algebra or sage.structure.proof); Note that the Sage
1828
+ global default is ``proof=True``
1829
+
1830
+ EXAMPLES::
1831
+
1832
+ sage: # needs sage.libs.linbox
1833
+ sage: m = matrix(QQ, 4, range(16))
1834
+ sage: m._echelonize_multimodular()
1835
+ (0, 1)
1836
+ sage: m
1837
+ [ 1 0 -1 -2]
1838
+ [ 0 1 2 3]
1839
+ [ 0 0 0 0]
1840
+ [ 0 0 0 0]
1841
+ sage: m = matrix(QQ, 4, 6, [-1,0,0,-2,-1,-2,-1,0,0,-2,-1,0,3,3,-2,0,0,3,-2,-3,1,1,-2,3])
1842
+ sage: m._echelonize_multimodular()
1843
+ (0, 1, 2, 5)
1844
+ sage: m
1845
+ [ 1 0 0 2 1 0]
1846
+ [ 0 1 0 -4/3 1 0]
1847
+ [ 0 0 1 1 3 0]
1848
+ [ 0 0 0 0 0 1]
1849
+ """
1850
+ from sage.matrix.misc import matrix_rational_echelon_form_multimodular
1851
+ E, pivots = matrix_rational_echelon_form_multimodular(self, height_guess, proof=proof)
1852
+ self.clear_cache()
1853
+ fmpq_mat_swap(self._matrix, (<Matrix_rational_dense>E)._matrix)
1854
+ return pivots
1855
+
1856
+ cdef swap_rows_c(self, Py_ssize_t r1, Py_ssize_t r2):
1857
+ """
1858
+ EXAMPLES::
1859
+
1860
+ sage: a = matrix(QQ,2,[1..6])
1861
+ sage: a.swap_rows(0,1) # indirect doctest
1862
+ sage: a
1863
+ [4 5 6]
1864
+ [1 2 3]
1865
+ """
1866
+ # no bounds checking!
1867
+ cdef Py_ssize_t c
1868
+ for c in range(self._ncols):
1869
+ fmpq_swap(fmpq_mat_entry(self._matrix, r1, c),
1870
+ fmpq_mat_entry(self._matrix, r2, c))
1871
+
1872
+ cdef swap_columns_c(self, Py_ssize_t c1, Py_ssize_t c2):
1873
+ """
1874
+ EXAMPLES::
1875
+
1876
+ sage: a = matrix(QQ,2,[1..6])
1877
+ sage: a.swap_columns(0,1) # indirect doctest
1878
+ sage: a
1879
+ [2 1 3]
1880
+ [5 4 6]
1881
+ """
1882
+ # no bounds checking!
1883
+ for r in range(self._nrows):
1884
+ fmpq_swap(fmpq_mat_entry(self._matrix, r, c1),
1885
+ fmpq_mat_entry(self._matrix, r, c2))
1886
+
1887
+ def decomposition(self, is_diagonalizable=False, dual=False,
1888
+ algorithm=None, height_guess=None, proof=None):
1889
+ """
1890
+ Return the decomposition of the free module on which this matrix A
1891
+ acts from the right (i.e., the action is x goes to x A), along with
1892
+ whether this matrix acts irreducibly on each factor. The factors
1893
+ are guaranteed to be sorted in the same way as the corresponding
1894
+ factors of the characteristic polynomial.
1895
+
1896
+ Let A be the matrix acting from the on the vector space V of column
1897
+ vectors. Assume that A is square. This function computes maximal
1898
+ subspaces W_1, ..., W_n corresponding to Galois conjugacy classes
1899
+ of eigenvalues of A. More precisely, let f(X) be the characteristic
1900
+ polynomial of A. This function computes the subspace
1901
+ `W_i = ker(g_(A)^n)`, where g_i(X) is an irreducible
1902
+ factor of f(X) and g_i(X) exactly divides f(X). If the optional
1903
+ parameter is_diagonalizable is True, then we let W_i = ker(g(A)),
1904
+ since then we know that ker(g(A)) = `ker(g(A)^n)`.
1905
+
1906
+ If dual is True, also returns the corresponding decomposition of V
1907
+ under the action of the transpose of A. The factors are guaranteed
1908
+ to correspond.
1909
+
1910
+ INPUT:
1911
+
1912
+ - ``is_diagonalizable`` -- ignored
1913
+
1914
+ - ``dual`` -- whether to also return decompositions for
1915
+ the dual
1916
+
1917
+ - ``algorithm`` -- an optional specification of an algorithm
1918
+
1919
+ - ``None`` -- (default) use default algorithm for computing Echelon
1920
+ forms
1921
+
1922
+ - 'multimodular': much better if the answers
1923
+ factors have small height
1924
+
1925
+ - ``height_guess`` -- positive integer; only used by
1926
+ the multimodular algorithm
1927
+
1928
+ - ``proof`` -- boolean or ``None`` (default: ``None``, see
1929
+ proof.linear_algebra or sage.structure.proof); only used by the
1930
+ multimodular algorithm. Note that the Sage global default is
1931
+ proof=True.
1932
+
1933
+
1934
+ .. NOTE::
1935
+
1936
+ IMPORTANT: If you expect that the subspaces in the answer
1937
+ are spanned by vectors with small height coordinates, use
1938
+ algorithm='multimodular' and height_guess=1; this is
1939
+ potentially much faster than the default. If you know for a
1940
+ fact the answer will be very small, use
1941
+ algorithm='multimodular', height_guess=bound on height,
1942
+ proof=False.
1943
+
1944
+ You can get very very fast decomposition with proof=False.
1945
+
1946
+ EXAMPLES::
1947
+
1948
+ sage: a = matrix(QQ,3,[1..9])
1949
+ sage: a.decomposition()
1950
+ [(Vector space of degree 3 and dimension 1 over Rational Field
1951
+ Basis matrix:
1952
+ [ 1 -2 1],
1953
+ True),
1954
+ (Vector space of degree 3 and dimension 2 over Rational Field
1955
+ Basis matrix:
1956
+ [ 1 0 -1]
1957
+ [ 0 1 2],
1958
+ True)]
1959
+ """
1960
+ X = self._decomposition_rational(is_diagonalizable=is_diagonalizable,
1961
+ echelon_algorithm=algorithm,
1962
+ height_guess=height_guess, proof=proof)
1963
+ if not dual:
1964
+ return X
1965
+
1966
+ Y = self.transpose()._decomposition_rational(is_diagonalizable=is_diagonalizable,
1967
+ echelon_algorithm=algorithm, height_guess=height_guess, proof=proof)
1968
+ return X, Y
1969
+
1970
+ def _decomposition_rational(self, is_diagonalizable = False,
1971
+ echelon_algorithm=None,
1972
+ kernel_algorithm='default',
1973
+ **kwds):
1974
+ """
1975
+ Return the decomposition of the free module on which this matrix A
1976
+ acts from the right (i.e., the action is x goes to x A), along with
1977
+ whether this matrix acts irreducibly on each factor. The factors
1978
+ are guaranteed to be sorted in the same way as the corresponding
1979
+ factors of the characteristic polynomial.
1980
+
1981
+ INPUT:
1982
+
1983
+ - ``self`` -- a square matrix over the rational
1984
+ numbers
1985
+
1986
+ - ``echelon_algorithm`` -- an optional algorithm to be passed to the
1987
+ method ``echelon_form``
1988
+
1989
+ - ``'multimodular'`` -- use this if the answers have
1990
+ small height
1991
+
1992
+ - ``**kwds`` -- passed on to echelon function
1993
+
1994
+ .. NOTE::
1995
+
1996
+ IMPORTANT: If you expect that the subspaces in the answer are
1997
+ spanned by vectors with small height coordinates, use
1998
+ algorithm='multimodular' and height_guess=1; this is potentially
1999
+ much faster than the default. If you know for a fact the answer
2000
+ will be very small, use algorithm='multimodular',
2001
+ height_guess=bound on height, proof=False
2002
+
2003
+ OUTPUT:
2004
+
2005
+ - ``Sequence`` -- list of tuples (V,t), where V is a
2006
+ vector spaces and t is ``True`` if and only if the charpoly of ``self`` on
2007
+ V is irreducible. The tuples are in order corresponding to the
2008
+ elements of the sorted list self.charpoly().factor().
2009
+ """
2010
+ cdef Py_ssize_t k
2011
+
2012
+ if not self.is_square():
2013
+ raise ArithmeticError("self must be a square matrix")
2014
+
2015
+ if self.nrows() == 0:
2016
+ return decomp_seq([])
2017
+
2018
+ A, _ = self._clear_denom()
2019
+
2020
+ f = A.charpoly('x')
2021
+ E = decomp_seq([])
2022
+
2023
+ t = verbose('factoring the characteristic polynomial', level=2, caller_name='rational decomp')
2024
+ F = f.factor()
2025
+ verbose('done factoring', t=t, level=2, caller_name='rational decomp')
2026
+
2027
+ if len(F) == 1:
2028
+ V = QQ**self.nrows()
2029
+ m = F[0][1]
2030
+ return decomp_seq([(V, m==1)])
2031
+
2032
+ V = ZZ**self.nrows()
2033
+ v = V.random_element()
2034
+ num_iterates = max([0] + [f.degree() - g.degree() for g, _ in F if g.degree() > 1]) + 1
2035
+
2036
+ S = []
2037
+
2038
+ F.sort()
2039
+ for i in range(len(F)):
2040
+ g, m = F[i]
2041
+
2042
+ if g.degree() == 1:
2043
+ # Just use kernel -- much easier.
2044
+ B = A.__copy__()
2045
+ for k from 0 <= k < A.nrows():
2046
+ B[k,k] += g[0]
2047
+ if m > 1 and not is_diagonalizable:
2048
+ B = B**m
2049
+ B = B.change_ring(QQ)
2050
+ W = B.kernel(algorithm = kernel_algorithm, **kwds)
2051
+ E.append((W, m==1))
2052
+ continue
2053
+
2054
+ # General case, i.e., deg(g) > 1:
2055
+ W = None
2056
+ tries = m
2057
+ while True:
2058
+
2059
+ # Compute the complementary factor of the charpoly.
2060
+ h = f // (g**m)
2061
+ v = h.list()
2062
+
2063
+ while len(S) < tries:
2064
+ t = verbose('%s-spinning %s-th random vector' % (num_iterates, len(S)),
2065
+ level=2, caller_name='rational decomp')
2066
+ S.append(A.iterates(V.random_element(x=-10,y=10), num_iterates))
2067
+ verbose('done spinning', level=2, t=t, caller_name='rational decomp')
2068
+
2069
+ for j in range(0 if W is None else W.nrows() // g.degree(), len(S)):
2070
+ # Compute one element of the kernel of g(A)**m.
2071
+ t = verbose('compute element of kernel of g(A), for g of degree %s' % g.degree(), level=2,
2072
+ caller_name='rational decomp')
2073
+ w = S[j].linear_combination_of_rows(h.list())
2074
+ t = verbose('done computing element of kernel of g(A)', t=t,level=2, caller_name='rational decomp')
2075
+
2076
+ # Get the rest of the kernel.
2077
+ t = verbose('fill out rest of kernel',level=2, caller_name='rational decomp')
2078
+ if W is None:
2079
+ W = A.iterates(w, g.degree())
2080
+ else:
2081
+ W = W.stack(A.iterates(w, g.degree()))
2082
+ t = verbose('finished filling out more of kernel',level=2, t=t, caller_name='rational decomp')
2083
+
2084
+ if W.rank() == m * g.degree():
2085
+ W = W.change_ring(QQ)
2086
+ t = verbose('now computing row space', level=2, caller_name='rational decomp')
2087
+ W.echelonize(algorithm = echelon_algorithm, **kwds)
2088
+ E.append((W.row_space(), m==1))
2089
+ verbose('computed row space', level=2,t=t, caller_name='rational decomp')
2090
+ break
2091
+ else:
2092
+ verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)' % (W.rank(), m*g.degree()),
2093
+ level=2, caller_name='rational decomp')
2094
+ tries += 1
2095
+ if tries > 5*m:
2096
+ raise RuntimeError("likely bug in decomposition")
2097
+ # end if
2098
+ # end while
2099
+ # end for
2100
+ return decomp_seq(E)
2101
+
2102
+ # def simple_decomposition(self, echelon_algorithm='default', **kwds):
2103
+ # """
2104
+ # Returns the decomposition of the free module on which this
2105
+ # matrix A acts from the right (i.e., the action is x goes to x
2106
+ # A), as a direct sum of simple modules.
2107
+
2108
+ # NOTE: self *must* be diagonalizable.
2109
+
2110
+ # INPUT:
2111
+ # self -- a square matrix that is assumed to be diagonalizable
2112
+ # echelon_algorithm -- 'default'
2113
+ # 'multimodular' -- use this if the answers
2114
+ # have small height
2115
+ # **kwds -- passed on to echelon function.
2116
+
2117
+ # IMPORTANT NOTE:
2118
+ # If you expect that the subspaces in the answer are spanned by vectors
2119
+ # with small height coordinates, use algorithm='multimodular' and
2120
+ # height_guess=1; this is potentially much faster than the default.
2121
+ # If you know for a fact the answer will be very small, use
2122
+ # algorithm='multimodular', height_guess=bound on height, proof=False
2123
+
2124
+ # OUTPUT:
2125
+ # Sequence -- list of tuples (V,g), where V is a subspace
2126
+ # and an irreducible polynomial g, which is the
2127
+ # charpoly (=minpoly) of self acting on V.
2128
+ # """
2129
+ # cdef Py_ssize_t k
2130
+
2131
+ # if not self.is_square():
2132
+ # raise ArithmeticError("self must be a square matrix")
2133
+
2134
+ # if self.nrows() == 0:
2135
+ # return decomp_seq([])
2136
+
2137
+ # A, _ = self._clear_denom()
2138
+
2139
+ # f = A.charpoly('x')
2140
+ # E = decomp_seq([])
2141
+
2142
+ # t = verbose('factoring the characteristic polynomial', level=2, caller_name='simple decomp')
2143
+ # F = f.factor()
2144
+ # G = [g for g, _ in F]
2145
+ # minpoly = prod(G)
2146
+ # squarefree_degree = sum([g.degree() for g in G])
2147
+ # verbose('done factoring', t=t, level=2, caller_name='simple decomp')
2148
+
2149
+ # V = ZZ**self.nrows()
2150
+ # v = V.random_element()
2151
+ # num_iterates = max([squarefree_degree - g.degree() for g in G]) + 1
2152
+
2153
+ # S = [ ]
2154
+
2155
+ # F.sort()
2156
+ # for i in range(len(F)):
2157
+ # g, m = F[i]
2158
+
2159
+ # if g.degree() == 1:
2160
+ # # Just use kernel -- much easier.
2161
+ # B = A.__copy__()
2162
+ # for k from 0 <= k < A.nrows():
2163
+ # B[k,k] += g[0]
2164
+ # if m > 1 and not is_diagonalizable:
2165
+ # B = B**m
2166
+ # W = B.change_ring(QQ).kernel()
2167
+ # for b in W.basis():
2168
+ # E.append((W.span(b), g))
2169
+ # continue
2170
+
2171
+ # # General case, i.e., deg(g) > 1:
2172
+ # W = None
2173
+ # while True:
2174
+
2175
+ # # Compute the complementary factor of the charpoly.
2176
+ # h = minpoly // g
2177
+ # v = h.list()
2178
+
2179
+ # while len(S) < m:
2180
+ # t = verbose('%s-spinning %s-th random vector'%(num_iterates, len(S)),
2181
+ # level=2, caller_name='simple decomp')
2182
+ # S.append(A.iterates(V.random_element(x=-10,y=10), num_iterates))
2183
+ # verbose('done spinning', level=2, t=t, caller_name='simple decomp')
2184
+
2185
+ # for j in range(len(S)):
2186
+ # # Compute one element of the kernel of g(A).
2187
+ # t = verbose('compute element of kernel of g(A), for g of degree %s'%g.degree(),level=2,
2188
+ # caller_name='simple decomp')
2189
+ # w = S[j].linear_combination_of_rows(h.list())
2190
+ # t = verbose('done computing element of kernel of g(A)', t=t,level=2, caller_name='simple decomp')
2191
+
2192
+ # # Get the rest of the kernel.
2193
+ # t = verbose('fill out rest of kernel',level=2, caller_name='simple decomp')
2194
+ # if W is None:
2195
+ # W = A.iterates(w, g.degree())
2196
+ # else:
2197
+ # W = W.stack(A.iterates(w, g.degree()))
2198
+ # t = verbose('finished filling out more of kernel',level=2, t=t, caller_name='simple decomp')
2199
+
2200
+ # if W.rank() == m * g.degree():
2201
+ # W = W.change_ring(QQ)
2202
+ # t = verbose('now computing row space', level=2, caller_name='simple decomp')
2203
+ # W.echelonize(algorithm = echelon_algorithm, **kwds)
2204
+ # E.append((W.row_space(), m==1))
2205
+ # verbose('computed row space', level=2,t=t, caller_name='simple decomp')
2206
+ # break
2207
+ # else:
2208
+ # verbose('we have not yet generated all the kernel (rank so far=%s, target rank=%s)'%(
2209
+ # W.rank(), m*g.degree()), level=2, caller_name='simple decomp')
2210
+ # j += 1
2211
+ # if j > 3*m:
2212
+ # raise RuntimeError("likely bug in decomposition")
2213
+ # # end if
2214
+ # #end while
2215
+ # #end for
2216
+ # return E
2217
+
2218
+ def _lift_crt_rr(self, res, mm):
2219
+ from .matrix_rational_linbox import _lift_crt_rr
2220
+ return _lift_crt_rr(self, res, mm)
2221
+
2222
+ def randomize(self, density=1, num_bound=2, den_bound=2,
2223
+ distribution=None, nonzero=False):
2224
+ """
2225
+ Randomize ``density`` proportion of the entries of this matrix, leaving
2226
+ the rest unchanged.
2227
+
2228
+ If ``x`` and ``y`` are given, randomized entries of this matrix have
2229
+ numerators and denominators bounded by ``x`` and ``y`` and have
2230
+ density 1.
2231
+
2232
+ INPUT:
2233
+
2234
+ - ``density`` -- number between 0 and 1 (default: 1)
2235
+
2236
+ - ``num_bound`` -- numerator bound (default: 2)
2237
+
2238
+ - ``den_bound`` -- denominator bound (default: 2)
2239
+
2240
+ - ``distribution`` -- ``None`` or '1/n' (default: ``None``); if '1/n'
2241
+ then ``num_bound``, ``den_bound`` are ignored and numbers are chosen
2242
+ using the GMP function ``mpq_randomize_entry_recip_uniform``
2243
+
2244
+ OUTPUT: none; the matrix is modified in-space
2245
+
2246
+ EXAMPLES:
2247
+
2248
+ The default distribution::
2249
+
2250
+ sage: from collections import defaultdict
2251
+ sage: total_count = 0
2252
+ sage: dic = defaultdict(Integer)
2253
+ sage: def add_samples(distribution=None):
2254
+ ....: global dic, total_count
2255
+ ....: for _ in range(100):
2256
+ ....: A = Matrix(QQ, 2, 4, 0)
2257
+ ....: A.randomize(distribution=distribution)
2258
+ ....: for a in A.list():
2259
+ ....: dic[a] += 1
2260
+ ....: total_count += 1.0
2261
+
2262
+ sage: expected = {-2: 1/9, -1: 3/18, -1/2: 1/18, 0: 3/9,
2263
+ ....: 1/2: 1/18, 1: 3/18, 2: 1/9}
2264
+ sage: add_samples()
2265
+ sage: while not all(abs(dic[a]/total_count - expected[a]) < 0.001 for a in dic):
2266
+ ....: add_samples()
2267
+
2268
+ The distribution ``'1/n'``::
2269
+
2270
+ sage: def mpq_randomize_entry_recip_uniform():
2271
+ ....: r = 2*random() - 1
2272
+ ....: if r == 0: r = 1
2273
+ ....: num = int(4/(5*r))
2274
+ ....: r = random()
2275
+ ....: if r == 0: r = 1
2276
+ ....: den = int(1/random())
2277
+ ....: return Integer(num)/Integer(den)
2278
+
2279
+ sage: total_count = 0
2280
+ sage: dic = defaultdict(Integer)
2281
+ sage: dic2 = defaultdict(Integer)
2282
+ sage: add_samples('1/n')
2283
+ sage: for _ in range(8):
2284
+ ....: dic2[mpq_randomize_entry_recip_uniform()] += 1
2285
+ sage: while not all(abs(dic[a] - dic2[a])/total_count < 0.005 for a in dic):
2286
+ ....: add_samples('1/n')
2287
+ ....: for _ in range(800):
2288
+ ....: dic2[mpq_randomize_entry_recip_uniform()] += 1
2289
+
2290
+ The default can be used to obtain matrices of different rank::
2291
+
2292
+ sage: ranks = [False]*11
2293
+ sage: while not all(ranks):
2294
+ ....: for dens in (0.05, 0.1, 0.2, 0.5):
2295
+ ....: A = Matrix(QQ, 10, 10, 0)
2296
+ ....: A.randomize(dens)
2297
+ ....: ranks[A.rank()] = True
2298
+
2299
+ The default density is `6/9`::
2300
+
2301
+ sage: def add_sample(density, num_rows, num_cols):
2302
+ ....: global density_sum, total_count
2303
+ ....: total_count += 1.0
2304
+ ....: A = Matrix(QQ, num_rows, num_cols, 0)
2305
+ ....: A.randomize(density)
2306
+ ....: density_sum += float(A.density())
2307
+
2308
+ sage: density_sum = 0.0
2309
+ sage: total_count = 0.0
2310
+ sage: expected_density = 6/9
2311
+ sage: add_sample(1.0, 100, 100)
2312
+ sage: while abs(density_sum/total_count - expected_density) > 0.001:
2313
+ ....: add_sample(1.0, 100, 100)
2314
+
2315
+ The modified density depends on the number of columns::
2316
+
2317
+ sage: density_sum = 0.0
2318
+ sage: total_count = 0.0
2319
+ sage: expected_density = 6/9*0.5
2320
+ sage: add_sample(0.5, 100, 2)
2321
+ sage: while abs(density_sum/total_count - expected_density) > 0.001:
2322
+ ....: add_sample(0.5, 100, 2)
2323
+
2324
+ sage: density_sum = 0.0
2325
+ sage: total_count = 0.0
2326
+ sage: expected_density = 6/9*(1.0 - (99/100)^50)
2327
+ sage: expected_density
2328
+ 0.263...
2329
+
2330
+ sage: add_sample(0.5, 100, 100)
2331
+ sage: while abs(density_sum/total_count - expected_density) > 0.001:
2332
+ ....: add_sample(0.5, 100, 100)
2333
+
2334
+ Modifying the bounds for numerator and denominator::
2335
+
2336
+ sage: num_dic = defaultdict(Integer)
2337
+ sage: den_dic = defaultdict(Integer)
2338
+ sage: while not (all(num_dic[i] for i in range(-200, 201))
2339
+ ....: and all(den_dic[i] for i in range(1, 101))):
2340
+ ....: a = matrix(QQ, 2, 4)
2341
+ ....: a.randomize(num_bound=200, den_bound=100)
2342
+ ....: for q in a.list():
2343
+ ....: num_dic[q.numerator()] += 1
2344
+ ....: den_dic[q.denominator()] += 1
2345
+ sage: len(num_dic)
2346
+ 401
2347
+ sage: len(den_dic)
2348
+ 100
2349
+
2350
+ TESTS:
2351
+
2352
+ Check that the option ``nonzero`` is meaningful (:issue:`22970`)::
2353
+
2354
+ sage: a = matrix(QQ, 10, 10, 1)
2355
+ sage: b = a.__copy__()
2356
+ sage: b.randomize(nonzero=True)
2357
+ sage: a == b
2358
+ False
2359
+ sage: any(b[i,j].is_zero() for i in range(10) for j in range(10))
2360
+ False
2361
+
2362
+ Check that :issue:`34103` is fixed::
2363
+
2364
+ sage: a = matrix(QQ, 10, 10, 1)
2365
+ sage: a.randomize(nonzero=True, distribution='1/n')
2366
+ sage: bool(a)
2367
+ True
2368
+ """
2369
+ density = float(density)
2370
+ if density <= 0.0:
2371
+ return
2372
+
2373
+ self.check_mutability()
2374
+ self.clear_cache()
2375
+
2376
+ cdef Integer B, C
2377
+ cdef Py_ssize_t i, j, k, num_per_row
2378
+ cdef randstate rstate
2379
+ cdef mpq_t tmp
2380
+
2381
+ B = Integer(num_bound + 1)
2382
+ C = Integer(den_bound + 1)
2383
+
2384
+ mpq_init(tmp)
2385
+
2386
+ if not nonzero:
2387
+ if density >= 1.0:
2388
+ if distribution == "1/n":
2389
+ sig_on()
2390
+ for i in range(self._nrows):
2391
+ for j in range(self._ncols):
2392
+ mpq_randomize_entry_recip_uniform(tmp)
2393
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, i, j), tmp)
2394
+ sig_off()
2395
+ elif mpz_cmp_si(C.value, 2): # denom is > 1
2396
+ sig_on()
2397
+ for i in range(self._nrows):
2398
+ for j in range(self._ncols):
2399
+ mpq_randomize_entry(tmp, B.value, C.value)
2400
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, i, j), tmp)
2401
+ sig_off()
2402
+ else:
2403
+ sig_on()
2404
+ for i in range(self._nrows):
2405
+ for j in range(self._ncols):
2406
+ mpq_randomize_entry_as_int(tmp, B.value)
2407
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, i, j), tmp)
2408
+ sig_off()
2409
+ else:
2410
+ rstate = current_randstate()
2411
+ num_per_row = int(density * self._ncols)
2412
+ if distribution == "1/n":
2413
+ sig_on()
2414
+ for i in range(self._nrows):
2415
+ for j in range(num_per_row):
2416
+ k = rstate.c_random() % self._ncols
2417
+ mpq_randomize_entry_recip_uniform(tmp)
2418
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, i, k), tmp)
2419
+ sig_off()
2420
+ elif mpz_cmp_si(C.value, 2): # denom is > 1
2421
+ sig_on()
2422
+ for i in range(self._nrows):
2423
+ for j in range(num_per_row):
2424
+ k = rstate.c_random() % self._ncols
2425
+ mpq_randomize_entry(tmp, B.value, C.value)
2426
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, i, k), tmp)
2427
+ sig_off()
2428
+ else:
2429
+ sig_on()
2430
+ for i in range(self._nrows):
2431
+ for j in range(num_per_row):
2432
+ k = rstate.c_random() % self._ncols
2433
+ mpq_randomize_entry_as_int(tmp, B.value)
2434
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, i, k), tmp)
2435
+ sig_off()
2436
+ else:
2437
+ if density >= 1.0:
2438
+ if distribution == "1/n":
2439
+ sig_on()
2440
+ for i in range(self._nrows):
2441
+ for j in range(self._ncols):
2442
+ mpq_randomize_entry_recip_uniform_nonzero(tmp)
2443
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, i, j), tmp)
2444
+ sig_off()
2445
+ elif mpz_cmp_si(C.value, 2): # denom is > 1
2446
+ sig_on()
2447
+ for i in range(self._nrows):
2448
+ for j in range(self._ncols):
2449
+ mpq_randomize_entry_nonzero(tmp, B.value, C.value)
2450
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, i, j), tmp)
2451
+ sig_off()
2452
+ else:
2453
+ sig_on()
2454
+ for i in range(self._nrows):
2455
+ for j in range(self._ncols):
2456
+ mpq_randomize_entry_as_int_nonzero(tmp, B.value)
2457
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, i, j), tmp)
2458
+ sig_off()
2459
+ else:
2460
+ rstate = current_randstate()
2461
+ num_per_row = int(density * self._ncols)
2462
+ if distribution == "1/n":
2463
+ sig_on()
2464
+ for i in range(self._nrows):
2465
+ for j in range(num_per_row):
2466
+ k = rstate.c_random() % self._ncols
2467
+ mpq_randomize_entry_recip_uniform_nonzero(tmp)
2468
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, i, k), tmp)
2469
+ sig_off()
2470
+ elif mpz_cmp_si(C.value, 2): # denom is > 1
2471
+ sig_on()
2472
+ for i in range(self._nrows):
2473
+ for j in range(num_per_row):
2474
+ k = rstate.c_random() % self._ncols
2475
+ mpq_randomize_entry_nonzero(tmp, B.value, C.value)
2476
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, i, k), tmp)
2477
+ sig_off()
2478
+ else:
2479
+ sig_on()
2480
+ for i in range(self._nrows):
2481
+ for j in range(num_per_row):
2482
+ k = rstate.c_random() % self._ncols
2483
+ mpq_randomize_entry_as_int_nonzero(tmp, B.value)
2484
+ fmpq_set_mpq(fmpq_mat_entry(self._matrix, i, k), tmp)
2485
+ sig_off()
2486
+
2487
+ mpq_clear(tmp)
2488
+
2489
+ def rank(self, algorithm=None):
2490
+ """
2491
+ Return the rank of this matrix.
2492
+
2493
+ INPUT:
2494
+
2495
+ - ``algorithm`` -- an optional specification of an algorithm. One of
2496
+
2497
+ - ``None`` -- (default) will use flint
2498
+
2499
+ - ``'flint'`` -- uses the flint library
2500
+
2501
+ - ``'pari'`` -- uses the PARI library
2502
+
2503
+ - ``'integer'`` -- eliminate denominators and calls the rank function
2504
+ on the corresponding integer matrix
2505
+
2506
+ EXAMPLES::
2507
+
2508
+ sage: matrix(QQ,3,[1..9]).rank()
2509
+ 2
2510
+ sage: matrix(QQ,100,[1..100^2]).rank()
2511
+ 2
2512
+
2513
+ TESTS::
2514
+
2515
+ sage: for _ in range(100): # needs sage.libs.pari
2516
+ ....: dim = randint(0, 30)
2517
+ ....: m = random_matrix(QQ, dim, num_bound=2, density=0.5)
2518
+ ....: r_pari = m.rank('pari'); m._clear_cache()
2519
+ ....: r_flint = m.rank('flint'); m._clear_cache()
2520
+ ....: r_int = m.rank('integer'); m._clear_cache()
2521
+ ....: assert r_pari == r_flint == r_int
2522
+ """
2523
+ r = self.fetch('rank')
2524
+ if r is not None:
2525
+ return r
2526
+
2527
+ if algorithm is None:
2528
+ algorithm = "flint"
2529
+
2530
+ if algorithm == "flint":
2531
+ self.echelon_form(algorithm='flint')
2532
+ return self.fetch('rank')
2533
+ elif algorithm == "pari":
2534
+ from .matrix_rational_pari import _rank_pari
2535
+ r = _rank_pari(self)
2536
+ elif algorithm == "integer":
2537
+ A, _ = self._clear_denom()
2538
+ r = A.rank()
2539
+ else:
2540
+ raise ValueError("unknown algorithm %s" % algorithm)
2541
+
2542
+ self.cache('rank', r)
2543
+ return r
2544
+
2545
+ def transpose(self):
2546
+ """
2547
+ Return the transpose of ``self``, without changing ``self``.
2548
+
2549
+ EXAMPLES:
2550
+
2551
+ We create a matrix, compute its transpose, and note that the
2552
+ original matrix is not changed.
2553
+
2554
+ ::
2555
+
2556
+ sage: A = matrix(QQ, 2, 3, range(6))
2557
+ sage: type(A)
2558
+ <class 'sage.matrix.matrix_rational_dense.Matrix_rational_dense'>
2559
+ sage: B = A.transpose()
2560
+ sage: print(B)
2561
+ [0 3]
2562
+ [1 4]
2563
+ [2 5]
2564
+ sage: print(A)
2565
+ [0 1 2]
2566
+ [3 4 5]
2567
+
2568
+ ``.T`` is a convenient shortcut for the transpose::
2569
+
2570
+ sage: print(A.T)
2571
+ [0 3]
2572
+ [1 4]
2573
+ [2 5]
2574
+
2575
+ ::
2576
+
2577
+ sage: A.subdivide(None, 1); A
2578
+ [0|1 2]
2579
+ [3|4 5]
2580
+ sage: A.transpose()
2581
+ [0 3]
2582
+ [---]
2583
+ [1 4]
2584
+ [2 5]
2585
+ """
2586
+ cdef Matrix_rational_dense ans
2587
+ if self._nrows == self._ncols:
2588
+ parent = self._parent
2589
+ else:
2590
+ parent = self._parent.matrix_space(self._ncols, self._nrows)
2591
+ ans = Matrix_rational_dense.__new__(Matrix_rational_dense, parent, None, None, None)
2592
+ sig_on()
2593
+ fmpq_mat_transpose(ans._matrix, self._matrix)
2594
+ sig_off()
2595
+
2596
+ if self._subdivisions is not None:
2597
+ row_divs, col_divs = self.subdivisions()
2598
+ ans.subdivide(col_divs, row_divs)
2599
+ return ans
2600
+
2601
+ def antitranspose(self):
2602
+ """
2603
+ Return the antitranspose of ``self``, without changing ``self``.
2604
+
2605
+ EXAMPLES::
2606
+
2607
+ sage: A = matrix(QQ,2,3,range(6))
2608
+ sage: type(A)
2609
+ <class 'sage.matrix.matrix_rational_dense.Matrix_rational_dense'>
2610
+ sage: A.antitranspose()
2611
+ [5 2]
2612
+ [4 1]
2613
+ [3 0]
2614
+ sage: A
2615
+ [0 1 2]
2616
+ [3 4 5]
2617
+
2618
+ sage: A.subdivide(1,2); A
2619
+ [0 1|2]
2620
+ [---+-]
2621
+ [3 4|5]
2622
+ sage: A.antitranspose()
2623
+ [5|2]
2624
+ [-+-]
2625
+ [4|1]
2626
+ [3|0]
2627
+ """
2628
+ if self._nrows == self._ncols:
2629
+ parent = self._parent
2630
+ else:
2631
+ parent = self._parent.matrix_space(self._ncols, self._nrows)
2632
+
2633
+ cdef Matrix_rational_dense ans
2634
+ ans = Matrix_rational_dense.__new__(Matrix_rational_dense, parent, None, None, None)
2635
+
2636
+ cdef Py_ssize_t i,j
2637
+ cdef Py_ssize_t ri,rj # reversed i and j
2638
+ sig_on()
2639
+ ri = self._nrows
2640
+ for i in range(self._nrows):
2641
+ rj = self._ncols
2642
+ ri = ri - 1
2643
+ for j in range(self._ncols):
2644
+ rj = rj - 1
2645
+ fmpq_set(fmpq_mat_entry(ans._matrix, rj, ri),
2646
+ fmpq_mat_entry(self._matrix, i, j))
2647
+ sig_off()
2648
+
2649
+ if self._subdivisions is not None:
2650
+ row_divs, col_divs = self.subdivisions()
2651
+ ans.subdivide([self._ncols - t for t in reversed(col_divs)],
2652
+ [self._nrows - t for t in reversed(row_divs)])
2653
+ return ans
2654
+
2655
+ def set_row_to_multiple_of_row(self, Py_ssize_t i, Py_ssize_t j, s):
2656
+ """
2657
+ Set row i equal to s times row j.
2658
+
2659
+ EXAMPLES::
2660
+
2661
+ sage: a = matrix(QQ,2,3,range(6)); a
2662
+ [0 1 2]
2663
+ [3 4 5]
2664
+ sage: a.set_row_to_multiple_of_row(1,0,-3)
2665
+ sage: a
2666
+ [ 0 1 2]
2667
+ [ 0 -3 -6]
2668
+ """
2669
+ self.check_row_bounds_and_mutability(i, j)
2670
+ cdef Py_ssize_t k
2671
+ cdef fmpq_t ss
2672
+ fmpq_init(ss)
2673
+ fmpq_set_mpq(ss, (<Rational> Rational(s)).value)
2674
+ for k in range(self._ncols):
2675
+ fmpq_mul(fmpq_mat_entry(self._matrix, i, k),
2676
+ fmpq_mat_entry(self._matrix, j, k),
2677
+ ss)
2678
+ fmpq_clear(ss)
2679
+
2680
+ def _set_row_to_negative_of_row_of_A_using_subset_of_columns(self, Py_ssize_t i, Matrix A,
2681
+ Py_ssize_t r, cols,
2682
+ cols_index=None):
2683
+ """
2684
+ Set row i of ``self`` to -(row r of A), but where we only take the
2685
+ given column positions in that row of A. We do not zero out the
2686
+ other entries of ``self``'s row i either.
2687
+
2688
+ .. NOTE::
2689
+
2690
+ This function exists just because it is useful for modular symbols presentations.
2691
+
2692
+ INPUT:
2693
+
2694
+ - ``i`` -- integer, index into the rows of self
2695
+
2696
+ - ``A`` -- a matrix
2697
+
2698
+ - ``r`` -- integer, index into rows of A
2699
+
2700
+ - ``cols`` -- a *sorted* list of integers
2701
+
2702
+ EXAMPLES::
2703
+
2704
+ sage: a = matrix(QQ,2,3,range(6)); a
2705
+ [0 1 2]
2706
+ [3 4 5]
2707
+ sage: a._set_row_to_negative_of_row_of_A_using_subset_of_columns(0,a,1,[1,2])
2708
+ sage: a
2709
+ [-4 -5 2]
2710
+ [ 3 4 5]
2711
+ """
2712
+ self.check_row_bounds_and_mutability(i,i)
2713
+ cdef Matrix_rational_dense _A
2714
+ if r < 0 or r >= A.nrows():
2715
+ raise IndexError("invalid row")
2716
+ cdef Py_ssize_t l = 0
2717
+
2718
+ if not A.base_ring() == QQ:
2719
+ A = A.change_ring(QQ)
2720
+ if not A.is_dense():
2721
+ A = A.dense_matrix()
2722
+
2723
+ _A = A
2724
+ for k in cols:
2725
+ entry = fmpq_mat_entry(self._matrix, i, l)
2726
+ fmpq_set(entry, fmpq_mat_entry(_A._matrix, r, k))
2727
+ fmpq_neg(entry, entry)
2728
+ l += 1
2729
+
2730
+ def _add_col_j_of_A_to_col_i_of_self(self, Py_ssize_t i,
2731
+ Matrix_rational_dense A, Py_ssize_t j):
2732
+ """
2733
+ Unsafe technical function that very quickly adds the `j`-th column of
2734
+ A to the `i`-th column of ``self``.
2735
+
2736
+ Does not check mutability.
2737
+ """
2738
+ if A._nrows != self._nrows:
2739
+ raise TypeError("nrows of self and A must be the same")
2740
+ cdef Py_ssize_t r
2741
+ for r in range(self._nrows):
2742
+ fmpq_add(fmpq_mat_entry(self._matrix, r, i),
2743
+ fmpq_mat_entry(self._matrix, r, i),
2744
+ fmpq_mat_entry(A._matrix, r, j))
2745
+
2746
+ # ###############################################
2747
+ # Methods using PARI library
2748
+ # ###############################################
2749
+
2750
+ def __pari__(self):
2751
+ """
2752
+ Return pari version of this matrix.
2753
+
2754
+ EXAMPLES::
2755
+
2756
+ sage: matrix(QQ,2,[1/5,-2/3,3/4,4/9]).__pari__() # needs sage.libs.pari
2757
+ [1/5, -2/3; 3/4, 4/9]
2758
+ """
2759
+ from .matrix_rational_pari import _pari
2760
+ return _pari(self)
2761
+
2762
+ def _det_pari(self, int flag=0):
2763
+ """
2764
+ Return the determinant of this matrix computed using pari.
2765
+
2766
+ EXAMPLES::
2767
+
2768
+ sage: matrix(QQ,3,[1..9])._det_pari() # needs sage.libs.pari
2769
+ 0
2770
+ sage: matrix(QQ,3,[1..9])._det_pari(1) # needs sage.libs.pari
2771
+ 0
2772
+ sage: matrix(QQ,3,[0]+[2..9])._det_pari() # needs sage.libs.pari
2773
+ 3
2774
+ """
2775
+ from .matrix_rational_pari import _det_pari
2776
+ return _det_pari(self, flag)
2777
+
2778
+ def _rank_pari(self):
2779
+ """
2780
+ Return the rank of this matrix computed using pari.
2781
+
2782
+ EXAMPLES::
2783
+
2784
+ sage: matrix(QQ,3,[1..9])._rank_pari() # needs sage.libs.pari
2785
+ 2
2786
+ sage: matrix(QQ, 0, 0)._rank_pari() # needs sage.libs.pari
2787
+ 0
2788
+ """
2789
+ from .matrix_rational_pari import _rank_pari
2790
+ return _rank_pari(self)
2791
+
2792
+ def _multiply_pari(self, Matrix_rational_dense right):
2793
+ """
2794
+ Return the product of ``self`` and ``right``, computed using PARI.
2795
+
2796
+ EXAMPLES::
2797
+
2798
+ sage: matrix(QQ,2,[1/5,-2/3,3/4,4/9])._multiply_pari(matrix(QQ,2,[1,2,3,4])) # needs sage.libs.pari
2799
+ [ -9/5 -34/15]
2800
+ [ 25/12 59/18]
2801
+
2802
+ We verify that 0 rows or columns works::
2803
+
2804
+ sage: x = matrix(QQ,2,0); y = matrix(QQ,0,2); x*y
2805
+ [0 0]
2806
+ [0 0]
2807
+ sage: matrix(ZZ, 0, 0) * matrix(QQ, 0, 5)
2808
+ []
2809
+ """
2810
+ from .matrix_rational_pari import _multiply_pari
2811
+ return _multiply_pari(self, right)
2812
+
2813
+ def _invert_pari(self):
2814
+ """
2815
+ Return the inverse of this matrix computed using PARI.
2816
+
2817
+ EXAMPLES::
2818
+
2819
+ sage: matrix(QQ,2,[1,2,3,4])._invert_pari() # needs sage.libs.pari
2820
+ [ -2 1]
2821
+ [ 3/2 -1/2]
2822
+ sage: matrix(QQ,2,[1,2,2,4])._invert_pari() # needs sage.libs.pari
2823
+ Traceback (most recent call last):
2824
+ ...
2825
+ PariError: impossible inverse in ginv: [1, 2; 2, 4]
2826
+ """
2827
+ from .matrix_rational_pari import _invert_pari
2828
+ return _invert_pari(self)
2829
+
2830
+ def row(self, Py_ssize_t i, from_list=False):
2831
+ """
2832
+ Return the `i`-th row of this matrix as a dense vector.
2833
+
2834
+ INPUT:
2835
+
2836
+ - ``i`` -- integer
2837
+
2838
+ - ``from_list`` -- ignored
2839
+
2840
+ EXAMPLES::
2841
+
2842
+ sage: m = matrix(QQ, 2, [1/5, -2/3, 3/4, 4/9])
2843
+ sage: m.row(0)
2844
+ (1/5, -2/3)
2845
+ sage: m.row(1)
2846
+ (3/4, 4/9)
2847
+ sage: m.row(1, from_list=True)
2848
+ (3/4, 4/9)
2849
+ sage: m.row(-2)
2850
+ (1/5, -2/3)
2851
+
2852
+ sage: m.row(2)
2853
+ Traceback (most recent call last):
2854
+ ...
2855
+ IndexError: row index out of range
2856
+ sage: m.row(-3)
2857
+ Traceback (most recent call last):
2858
+ ...
2859
+ IndexError: row index out of range
2860
+ """
2861
+ if i < 0:
2862
+ i = i + self._nrows
2863
+ if i < 0 or i >= self._nrows:
2864
+ raise IndexError("row index out of range")
2865
+
2866
+ cdef Py_ssize_t j
2867
+ parent = self.row_ambient_module()
2868
+ cdef Vector_rational_dense v = Vector_rational_dense.__new__(Vector_rational_dense)
2869
+ v._init(self._ncols, parent)
2870
+ for j in range(self._ncols):
2871
+ fmpq_get_mpq(v._entries[j], fmpq_mat_entry(self._matrix, i, j))
2872
+ return v
2873
+
2874
+ def column(self, Py_ssize_t i, from_list=False):
2875
+ """
2876
+ Return the `i`-th column of this matrix as a dense vector.
2877
+
2878
+ INPUT:
2879
+
2880
+ - ``i`` -- integer
2881
+
2882
+ - ``from_list`` -- ignored
2883
+
2884
+ EXAMPLES::
2885
+
2886
+ sage: m = matrix(QQ, 3, 2, [1/5,-2/3,3/4,4/9,-1,0])
2887
+ sage: m.column(1)
2888
+ (-2/3, 4/9, 0)
2889
+ sage: m.column(1,from_list=True)
2890
+ (-2/3, 4/9, 0)
2891
+ sage: m.column(-1)
2892
+ (-2/3, 4/9, 0)
2893
+ sage: m.column(-2)
2894
+ (1/5, 3/4, -1)
2895
+
2896
+ sage: m.column(2)
2897
+ Traceback (most recent call last):
2898
+ ...
2899
+ IndexError: column index out of range
2900
+ sage: m.column(-3)
2901
+ Traceback (most recent call last):
2902
+ ...
2903
+ IndexError: column index out of range
2904
+ """
2905
+ if i < 0:
2906
+ i += self._ncols
2907
+ if i < 0 or i >= self._ncols:
2908
+ raise IndexError("column index out of range")
2909
+
2910
+ cdef Py_ssize_t j
2911
+ parent = self.column_ambient_module()
2912
+ cdef Vector_rational_dense v = Vector_rational_dense.__new__(Vector_rational_dense)
2913
+ v._init(self._nrows, parent)
2914
+ for j in range(self._nrows):
2915
+ fmpq_get_mpq(v._entries[j], fmpq_mat_entry(self._matrix, j, i))
2916
+ return v
2917
+
2918
+ # ###############################################
2919
+ # LLL
2920
+ # ###############################################
2921
+
2922
+ def BKZ(self, *args, **kwargs):
2923
+ """
2924
+ Return the result of running Block Korkin-Zolotarev reduction on
2925
+ ``self`` interpreted as a lattice.
2926
+
2927
+ The arguments ``*args`` and ``**kwargs`` are passed onto
2928
+ :meth:`sage.matrix.matrix_integer_dense.Matrix_integer_dense.BKZ`,
2929
+ see there for more details.
2930
+
2931
+ EXAMPLES::
2932
+
2933
+ sage: A = Matrix(QQ, 3, 3, [1/n for n in range(1, 10)])
2934
+ sage: A.BKZ() # needs fpylll
2935
+ [ 1/28 -1/40 -1/18]
2936
+ [ 1/28 -1/40 1/18]
2937
+ [-1/14 -1/40 0]
2938
+
2939
+ sage: A = random_matrix(QQ, 10, 10)
2940
+ sage: d = lcm(a.denom() for a in A.list())
2941
+ sage: A.BKZ() == (A * d).change_ring(ZZ).BKZ() / d # needs fpylll
2942
+ True
2943
+ """
2944
+ A, d = self._clear_denom()
2945
+ return A.BKZ(*args, **kwargs) / d
2946
+
2947
+ def LLL(self, *args, **kwargs):
2948
+ """
2949
+ Return an LLL reduced or approximated LLL reduced lattice for
2950
+ ``self`` interpreted as a lattice.
2951
+
2952
+ The arguments ``*args`` and ``**kwargs`` are passed onto
2953
+ :meth:`sage.matrix.matrix_integer_dense.Matrix_integer_dense.LLL`,
2954
+ see there for more details.
2955
+
2956
+ EXAMPLES::
2957
+
2958
+ sage: # needs fpylll
2959
+ sage: A = Matrix(QQ, 3, 3, [1/n for n in range(1, 10)])
2960
+ sage: A.LLL()
2961
+ [ 1/28 -1/40 -1/18]
2962
+ [ 1/28 -1/40 1/18]
2963
+ [ 0 -3/40 0]
2964
+ sage: L, U = A.LLL(transformation=True)
2965
+ sage: U * A == L
2966
+ True
2967
+ sage: A = random_matrix(QQ, 10, 10)
2968
+ sage: d = lcm(a.denom() for a in A.list())
2969
+ sage: A.LLL() == (A * d).change_ring(ZZ).LLL() / d
2970
+ True
2971
+ """
2972
+ A, d = self._clear_denom()
2973
+ if kwargs.get('transformation', False):
2974
+ L, U = A.LLL(*args, **kwargs)
2975
+ return L / d, U
2976
+ return A.LLL(*args, **kwargs) / d
2977
+
2978
+ def is_LLL_reduced(self, delta=None, eta=None):
2979
+ r"""
2980
+ Return ``True`` if this lattice is `(\delta, \eta)`-LLL reduced.
2981
+ For a definition of LLL reduction, see
2982
+ :meth:`sage.matrix.matrix_integer_dense.Matrix_integer_dense.LLL`.
2983
+
2984
+ EXAMPLES::
2985
+
2986
+ sage: # needs fpylll
2987
+ sage: A = random_matrix(QQ, 10, 10)
2988
+ sage: L = A.LLL()
2989
+ sage: A.is_LLL_reduced()
2990
+ False
2991
+ sage: L.is_LLL_reduced()
2992
+ True
2993
+ """
2994
+ A, _ = self._clear_denom()
2995
+ return A.is_LLL_reduced(delta, eta)