passagemath-flint 10.6.47__cp313-cp313-macosx_13_0_arm64.whl

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