passagemath-flint 10.6.1rc10__cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. passagemath_flint-10.6.1rc10.dist-info/METADATA +122 -0
  2. passagemath_flint-10.6.1rc10.dist-info/RECORD +361 -0
  3. passagemath_flint-10.6.1rc10.dist-info/WHEEL +6 -0
  4. passagemath_flint-10.6.1rc10.dist-info/top_level.txt +2 -0
  5. passagemath_flint.libs/libflint-aecb9cc5.so.21.0.0 +0 -0
  6. passagemath_flint.libs/libgf2x-a4cdec90.so.3.0.0 +0 -0
  7. passagemath_flint.libs/libgfortran-8f1e9814.so.5.0.0 +0 -0
  8. passagemath_flint.libs/libgmp-6e109695.so.10.5.0 +0 -0
  9. passagemath_flint.libs/libgsl-cda90e79.so.28.0.0 +0 -0
  10. passagemath_flint.libs/libmpfi-e3c25853.so.0.0.0 +0 -0
  11. passagemath_flint.libs/libmpfr-82690d50.so.6.2.1 +0 -0
  12. passagemath_flint.libs/libntl-74e7d9a3.so.44.0.1 +0 -0
  13. passagemath_flint.libs/libopenblasp-r0-6dcb67f9.3.29.so +0 -0
  14. passagemath_flint.libs/libquadmath-828275a7.so.0.0.0 +0 -0
  15. sage/all__sagemath_flint.py +29 -0
  16. sage/combinat/all__sagemath_flint.py +1 -0
  17. sage/combinat/posets/all__sagemath_flint.py +1 -0
  18. sage/combinat/posets/hasse_cython_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  19. sage/combinat/posets/hasse_cython_flint.pyx +194 -0
  20. sage/data_structures/all__sagemath_flint.py +1 -0
  21. sage/data_structures/bounded_integer_sequences.cpython-312-x86_64-linux-gnu.so +0 -0
  22. sage/data_structures/bounded_integer_sequences.pxd +62 -0
  23. sage/data_structures/bounded_integer_sequences.pyx +1418 -0
  24. sage/graphs/all__sagemath_flint.py +1 -0
  25. sage/graphs/chrompoly.cpython-312-x86_64-linux-gnu.so +0 -0
  26. sage/graphs/chrompoly.pyx +555 -0
  27. sage/graphs/matchpoly.cpython-312-x86_64-linux-gnu.so +0 -0
  28. sage/graphs/matchpoly.pyx +412 -0
  29. sage/libs/all__sagemath_flint.py +17 -0
  30. sage/libs/arb/__init__.py +1 -0
  31. sage/libs/arb/acb.pxd +154 -0
  32. sage/libs/arb/acb_calc.pxd +9 -0
  33. sage/libs/arb/acb_elliptic.pxd +25 -0
  34. sage/libs/arb/acb_hypgeom.pxd +74 -0
  35. sage/libs/arb/acb_mat.pxd +62 -0
  36. sage/libs/arb/acb_modular.pxd +17 -0
  37. sage/libs/arb/acb_poly.pxd +216 -0
  38. sage/libs/arb/arb.pxd +240 -0
  39. sage/libs/arb/arb_fmpz_poly.pxd +21 -0
  40. sage/libs/arb/arb_hypgeom.pxd +83 -0
  41. sage/libs/arb/arb_wrap.h +34 -0
  42. sage/libs/arb/arf.pxd +131 -0
  43. sage/libs/arb/arith.cpython-312-x86_64-linux-gnu.so +0 -0
  44. sage/libs/arb/arith.pyx +87 -0
  45. sage/libs/arb/bernoulli.pxd +6 -0
  46. sage/libs/arb/mag.pxd +77 -0
  47. sage/libs/arb/types.pxd +37 -0
  48. sage/libs/flint/__init__.py +1 -0
  49. sage/libs/flint/acb.pxd +270 -0
  50. sage/libs/flint/acb_calc.pxd +22 -0
  51. sage/libs/flint/acb_dft.pxd +51 -0
  52. sage/libs/flint/acb_dirichlet.pxd +112 -0
  53. sage/libs/flint/acb_elliptic.pxd +42 -0
  54. sage/libs/flint/acb_hypgeom.pxd +169 -0
  55. sage/libs/flint/acb_macros.pxd +9 -0
  56. sage/libs/flint/acb_mat.pxd +136 -0
  57. sage/libs/flint/acb_mat_macros.pxd +10 -0
  58. sage/libs/flint/acb_modular.pxd +62 -0
  59. sage/libs/flint/acb_poly.pxd +251 -0
  60. sage/libs/flint/acb_poly_macros.pxd +8 -0
  61. sage/libs/flint/acb_theta.pxd +124 -0
  62. sage/libs/flint/acf.pxd +32 -0
  63. sage/libs/flint/aprcl.pxd +84 -0
  64. sage/libs/flint/arb.pxd +382 -0
  65. sage/libs/flint/arb_calc.pxd +31 -0
  66. sage/libs/flint/arb_fmpz_poly.pxd +34 -0
  67. sage/libs/flint/arb_fpwrap.pxd +215 -0
  68. sage/libs/flint/arb_hypgeom.pxd +147 -0
  69. sage/libs/flint/arb_macros.pxd +9 -0
  70. sage/libs/flint/arb_mat.pxd +140 -0
  71. sage/libs/flint/arb_mat_macros.pxd +10 -0
  72. sage/libs/flint/arb_poly.pxd +237 -0
  73. sage/libs/flint/arf.pxd +167 -0
  74. sage/libs/flint/arith.cpython-312-x86_64-linux-gnu.so +0 -0
  75. sage/libs/flint/arith.pxd +76 -0
  76. sage/libs/flint/arith.pyx +77 -0
  77. sage/libs/flint/arith_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  78. sage/libs/flint/arith_sage.pyx +308 -0
  79. sage/libs/flint/bernoulli.pxd +28 -0
  80. sage/libs/flint/bool_mat.pxd +52 -0
  81. sage/libs/flint/ca.pxd +203 -0
  82. sage/libs/flint/ca_ext.pxd +34 -0
  83. sage/libs/flint/ca_field.pxd +32 -0
  84. sage/libs/flint/ca_mat.pxd +117 -0
  85. sage/libs/flint/ca_poly.pxd +104 -0
  86. sage/libs/flint/ca_vec.pxd +46 -0
  87. sage/libs/flint/calcium.pxd +27 -0
  88. sage/libs/flint/d_mat.pxd +39 -0
  89. sage/libs/flint/d_vec.pxd +32 -0
  90. sage/libs/flint/dirichlet.pxd +57 -0
  91. sage/libs/flint/dlog.pxd +53 -0
  92. sage/libs/flint/double_extras.pxd +24 -0
  93. sage/libs/flint/double_interval.pxd +36 -0
  94. sage/libs/flint/fexpr.pxd +104 -0
  95. sage/libs/flint/fexpr_builtin.pxd +20 -0
  96. sage/libs/flint/fft.pxd +66 -0
  97. sage/libs/flint/flint.pxd +36 -0
  98. sage/libs/flint/flint_ntl_wrap.h +35 -0
  99. sage/libs/flint/flint_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  100. sage/libs/flint/flint_sage.pyx +163 -0
  101. sage/libs/flint/flint_wrap.h +190 -0
  102. sage/libs/flint/fmpq.pxd +137 -0
  103. sage/libs/flint/fmpq_mat.pxd +105 -0
  104. sage/libs/flint/fmpq_mat_macros.pxd +10 -0
  105. sage/libs/flint/fmpq_mpoly.pxd +165 -0
  106. sage/libs/flint/fmpq_mpoly_factor.pxd +30 -0
  107. sage/libs/flint/fmpq_poly.pxd +241 -0
  108. sage/libs/flint/fmpq_poly_macros.pxd +9 -0
  109. sage/libs/flint/fmpq_poly_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  110. sage/libs/flint/fmpq_poly_sage.pxd +31 -0
  111. sage/libs/flint/fmpq_poly_sage.pyx +48 -0
  112. sage/libs/flint/fmpq_vec.pxd +27 -0
  113. sage/libs/flint/fmpz.pxd +256 -0
  114. sage/libs/flint/fmpz_extras.pxd +32 -0
  115. sage/libs/flint/fmpz_factor.pxd +42 -0
  116. sage/libs/flint/fmpz_factor_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  117. sage/libs/flint/fmpz_factor_sage.pxd +4 -0
  118. sage/libs/flint/fmpz_factor_sage.pyx +29 -0
  119. sage/libs/flint/fmpz_lll.pxd +49 -0
  120. sage/libs/flint/fmpz_macros.pxd +8 -0
  121. sage/libs/flint/fmpz_mat.pxd +184 -0
  122. sage/libs/flint/fmpz_mat_macros.pxd +10 -0
  123. sage/libs/flint/fmpz_mod.pxd +46 -0
  124. sage/libs/flint/fmpz_mod_mat.pxd +71 -0
  125. sage/libs/flint/fmpz_mod_mpoly.pxd +161 -0
  126. sage/libs/flint/fmpz_mod_mpoly_factor.pxd +28 -0
  127. sage/libs/flint/fmpz_mod_poly.pxd +249 -0
  128. sage/libs/flint/fmpz_mod_poly_factor.pxd +46 -0
  129. sage/libs/flint/fmpz_mod_vec.pxd +27 -0
  130. sage/libs/flint/fmpz_mpoly.pxd +224 -0
  131. sage/libs/flint/fmpz_mpoly_factor.pxd +29 -0
  132. sage/libs/flint/fmpz_mpoly_q.pxd +57 -0
  133. sage/libs/flint/fmpz_poly.cpython-312-x86_64-linux-gnu.so +0 -0
  134. sage/libs/flint/fmpz_poly.pxd +407 -0
  135. sage/libs/flint/fmpz_poly.pyx +19 -0
  136. sage/libs/flint/fmpz_poly_factor.pxd +33 -0
  137. sage/libs/flint/fmpz_poly_macros.pxd +8 -0
  138. sage/libs/flint/fmpz_poly_mat.pxd +71 -0
  139. sage/libs/flint/fmpz_poly_q.pxd +55 -0
  140. sage/libs/flint/fmpz_poly_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  141. sage/libs/flint/fmpz_poly_sage.pxd +20 -0
  142. sage/libs/flint/fmpz_poly_sage.pyx +500 -0
  143. sage/libs/flint/fmpz_vec.pxd +80 -0
  144. sage/libs/flint/fmpzi.pxd +52 -0
  145. sage/libs/flint/fq.pxd +97 -0
  146. sage/libs/flint/fq_default.pxd +84 -0
  147. sage/libs/flint/fq_default_mat.pxd +70 -0
  148. sage/libs/flint/fq_default_poly.pxd +97 -0
  149. sage/libs/flint/fq_default_poly_factor.pxd +39 -0
  150. sage/libs/flint/fq_embed.pxd +28 -0
  151. sage/libs/flint/fq_mat.pxd +83 -0
  152. sage/libs/flint/fq_nmod.pxd +95 -0
  153. sage/libs/flint/fq_nmod_embed.pxd +28 -0
  154. sage/libs/flint/fq_nmod_mat.pxd +83 -0
  155. sage/libs/flint/fq_nmod_mpoly.pxd +130 -0
  156. sage/libs/flint/fq_nmod_mpoly_factor.pxd +28 -0
  157. sage/libs/flint/fq_nmod_poly.pxd +202 -0
  158. sage/libs/flint/fq_nmod_poly_factor.pxd +47 -0
  159. sage/libs/flint/fq_nmod_vec.pxd +33 -0
  160. sage/libs/flint/fq_poly.pxd +204 -0
  161. sage/libs/flint/fq_poly_factor.pxd +47 -0
  162. sage/libs/flint/fq_vec.pxd +33 -0
  163. sage/libs/flint/fq_zech.pxd +99 -0
  164. sage/libs/flint/fq_zech_embed.pxd +28 -0
  165. sage/libs/flint/fq_zech_mat.pxd +78 -0
  166. sage/libs/flint/fq_zech_poly.pxd +198 -0
  167. sage/libs/flint/fq_zech_poly_factor.pxd +47 -0
  168. sage/libs/flint/fq_zech_vec.pxd +33 -0
  169. sage/libs/flint/gr.pxd +174 -0
  170. sage/libs/flint/gr_generic.pxd +215 -0
  171. sage/libs/flint/gr_mat.pxd +161 -0
  172. sage/libs/flint/gr_mpoly.pxd +68 -0
  173. sage/libs/flint/gr_poly.pxd +276 -0
  174. sage/libs/flint/gr_special.pxd +237 -0
  175. sage/libs/flint/gr_vec.pxd +120 -0
  176. sage/libs/flint/hypgeom.pxd +24 -0
  177. sage/libs/flint/long_extras.pxd +23 -0
  178. sage/libs/flint/mag.pxd +131 -0
  179. sage/libs/flint/mag_macros.pxd +8 -0
  180. sage/libs/flint/mpf_mat.pxd +36 -0
  181. sage/libs/flint/mpf_vec.pxd +34 -0
  182. sage/libs/flint/mpfr_mat.pxd +27 -0
  183. sage/libs/flint/mpfr_vec.pxd +25 -0
  184. sage/libs/flint/mpn_extras.pxd +41 -0
  185. sage/libs/flint/mpoly.pxd +72 -0
  186. sage/libs/flint/nf.pxd +19 -0
  187. sage/libs/flint/nf_elem.pxd +74 -0
  188. sage/libs/flint/nmod.pxd +35 -0
  189. sage/libs/flint/nmod_mat.pxd +104 -0
  190. sage/libs/flint/nmod_mpoly.pxd +144 -0
  191. sage/libs/flint/nmod_mpoly_factor.pxd +28 -0
  192. sage/libs/flint/nmod_poly.pxd +339 -0
  193. sage/libs/flint/nmod_poly_factor.pxd +44 -0
  194. sage/libs/flint/nmod_poly_linkage.pxi +710 -0
  195. sage/libs/flint/nmod_poly_mat.pxd +76 -0
  196. sage/libs/flint/nmod_vec.pxd +40 -0
  197. sage/libs/flint/ntl_interface.pxd +17 -0
  198. sage/libs/flint/padic.pxd +93 -0
  199. sage/libs/flint/padic_mat.pxd +64 -0
  200. sage/libs/flint/padic_poly.pxd +88 -0
  201. sage/libs/flint/partitions.pxd +23 -0
  202. sage/libs/flint/perm.pxd +26 -0
  203. sage/libs/flint/profiler.pxd +24 -0
  204. sage/libs/flint/qadic.pxd +77 -0
  205. sage/libs/flint/qfb.pxd +44 -0
  206. sage/libs/flint/qqbar.pxd +172 -0
  207. sage/libs/flint/qsieve.cpython-312-x86_64-linux-gnu.so +0 -0
  208. sage/libs/flint/qsieve.pxd +41 -0
  209. sage/libs/flint/qsieve.pyx +21 -0
  210. sage/libs/flint/qsieve_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  211. sage/libs/flint/qsieve_sage.pyx +67 -0
  212. sage/libs/flint/thread_pool.pxd +25 -0
  213. sage/libs/flint/types.pxd +2076 -0
  214. sage/libs/flint/ulong_extras.cpython-312-x86_64-linux-gnu.so +0 -0
  215. sage/libs/flint/ulong_extras.pxd +141 -0
  216. sage/libs/flint/ulong_extras.pyx +21 -0
  217. sage/libs/flint/ulong_extras_sage.cpython-312-x86_64-linux-gnu.so +0 -0
  218. sage/libs/flint/ulong_extras_sage.pyx +21 -0
  219. sage/matrix/all__sagemath_flint.py +1 -0
  220. sage/matrix/change_ring.cpython-312-x86_64-linux-gnu.so +0 -0
  221. sage/matrix/change_ring.pyx +43 -0
  222. sage/matrix/matrix_complex_ball_dense.cpython-312-x86_64-linux-gnu.so +0 -0
  223. sage/matrix/matrix_complex_ball_dense.pxd +14 -0
  224. sage/matrix/matrix_complex_ball_dense.pyx +973 -0
  225. sage/matrix/matrix_cyclo_dense.cpython-312-x86_64-linux-gnu.so +0 -0
  226. sage/matrix/matrix_cyclo_dense.pxd +16 -0
  227. sage/matrix/matrix_cyclo_dense.pyx +1761 -0
  228. sage/matrix/matrix_integer_dense.cpython-312-x86_64-linux-gnu.so +0 -0
  229. sage/matrix/matrix_integer_dense.pxd +32 -0
  230. sage/matrix/matrix_integer_dense.pyx +5801 -0
  231. sage/matrix/matrix_integer_dense_hnf.py +1294 -0
  232. sage/matrix/matrix_integer_dense_saturation.py +346 -0
  233. sage/matrix/matrix_integer_sparse.cpython-312-x86_64-linux-gnu.so +0 -0
  234. sage/matrix/matrix_integer_sparse.pxd +9 -0
  235. sage/matrix/matrix_integer_sparse.pyx +1090 -0
  236. sage/matrix/matrix_rational_dense.cpython-312-x86_64-linux-gnu.so +0 -0
  237. sage/matrix/matrix_rational_dense.pxd +23 -0
  238. sage/matrix/matrix_rational_dense.pyx +2995 -0
  239. sage/matrix/matrix_rational_sparse.cpython-312-x86_64-linux-gnu.so +0 -0
  240. sage/matrix/matrix_rational_sparse.pxd +11 -0
  241. sage/matrix/matrix_rational_sparse.pyx +789 -0
  242. sage/matrix/misc_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  243. sage/matrix/misc_flint.pyx +109 -0
  244. sage/modular/all__sagemath_flint.py +1 -0
  245. sage/modular/modform/all__sagemath_flint.py +1 -0
  246. sage/modular/modform/eis_series_cython.cpython-312-x86_64-linux-gnu.so +0 -0
  247. sage/modular/modform/eis_series_cython.pyx +226 -0
  248. sage/modular/modsym/all__sagemath_flint.py +1 -0
  249. sage/modular/modsym/apply.cpython-312-x86_64-linux-gnu.so +0 -0
  250. sage/modular/modsym/apply.pxd +6 -0
  251. sage/modular/modsym/apply.pyx +113 -0
  252. sage/modular/modsym/heilbronn.cpython-312-x86_64-linux-gnu.so +0 -0
  253. sage/modular/modsym/heilbronn.pyx +966 -0
  254. sage/modular/pollack_stevens/all__sagemath_flint.py +1 -0
  255. sage/modular/pollack_stevens/dist.cpython-312-x86_64-linux-gnu.so +0 -0
  256. sage/modular/pollack_stevens/dist.pxd +38 -0
  257. sage/modular/pollack_stevens/dist.pyx +1439 -0
  258. sage/quivers/algebra.py +691 -0
  259. sage/quivers/algebra_elements.cpython-312-x86_64-linux-gnu.so +0 -0
  260. sage/quivers/algebra_elements.pxd +97 -0
  261. sage/quivers/algebra_elements.pxi +1324 -0
  262. sage/quivers/algebra_elements.pyx +1424 -0
  263. sage/quivers/all.py +1 -0
  264. sage/quivers/ar_quiver.py +917 -0
  265. sage/quivers/homspace.py +640 -0
  266. sage/quivers/morphism.py +1282 -0
  267. sage/quivers/path_semigroup.py +1155 -0
  268. sage/quivers/paths.cpython-312-x86_64-linux-gnu.so +0 -0
  269. sage/quivers/paths.pxd +13 -0
  270. sage/quivers/paths.pyx +809 -0
  271. sage/quivers/representation.py +2975 -0
  272. sage/rings/all__sagemath_flint.py +37 -0
  273. sage/rings/cif.py +4 -0
  274. sage/rings/complex_arb.cpython-312-x86_64-linux-gnu.so +0 -0
  275. sage/rings/complex_arb.pxd +29 -0
  276. sage/rings/complex_arb.pyx +5176 -0
  277. sage/rings/complex_interval.cpython-312-x86_64-linux-gnu.so +0 -0
  278. sage/rings/complex_interval.pxd +30 -0
  279. sage/rings/complex_interval.pyx +2475 -0
  280. sage/rings/complex_interval_field.py +711 -0
  281. sage/rings/convert/all.py +1 -0
  282. sage/rings/convert/mpfi.cpython-312-x86_64-linux-gnu.so +0 -0
  283. sage/rings/convert/mpfi.pxd +6 -0
  284. sage/rings/convert/mpfi.pyx +576 -0
  285. sage/rings/factorint_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  286. sage/rings/factorint_flint.pyx +99 -0
  287. sage/rings/fraction_field_FpT.cpython-312-x86_64-linux-gnu.so +0 -0
  288. sage/rings/fraction_field_FpT.pxd +28 -0
  289. sage/rings/fraction_field_FpT.pyx +2043 -0
  290. sage/rings/imaginary_unit.py +5 -0
  291. sage/rings/monomials.py +73 -0
  292. sage/rings/number_field/S_unit_solver.py +2870 -0
  293. sage/rings/number_field/all__sagemath_flint.py +7 -0
  294. sage/rings/number_field/bdd_height.py +664 -0
  295. sage/rings/number_field/class_group.py +762 -0
  296. sage/rings/number_field/galois_group.py +1307 -0
  297. sage/rings/number_field/homset.py +612 -0
  298. sage/rings/number_field/maps.py +687 -0
  299. sage/rings/number_field/morphism.py +272 -0
  300. sage/rings/number_field/number_field.py +12820 -0
  301. sage/rings/number_field/number_field_element.cpython-312-x86_64-linux-gnu.so +0 -0
  302. sage/rings/number_field/number_field_element.pxd +59 -0
  303. sage/rings/number_field/number_field_element.pyx +5735 -0
  304. sage/rings/number_field/number_field_element_quadratic.cpython-312-x86_64-linux-gnu.so +0 -0
  305. sage/rings/number_field/number_field_element_quadratic.pxd +34 -0
  306. sage/rings/number_field/number_field_element_quadratic.pyx +3185 -0
  307. sage/rings/number_field/number_field_ideal_rel.py +925 -0
  308. sage/rings/number_field/number_field_morphisms.cpython-312-x86_64-linux-gnu.so +0 -0
  309. sage/rings/number_field/number_field_morphisms.pyx +781 -0
  310. sage/rings/number_field/number_field_rel.py +2734 -0
  311. sage/rings/number_field/order.py +2981 -0
  312. sage/rings/number_field/order_ideal.py +804 -0
  313. sage/rings/number_field/selmer_group.py +715 -0
  314. sage/rings/number_field/small_primes_of_degree_one.py +242 -0
  315. sage/rings/number_field/splitting_field.py +606 -0
  316. sage/rings/number_field/structure.py +380 -0
  317. sage/rings/number_field/unit_group.py +721 -0
  318. sage/rings/padics/all__sagemath_flint.py +3 -0
  319. sage/rings/polynomial/all__sagemath_flint.py +1 -0
  320. sage/rings/polynomial/complex_roots.py +312 -0
  321. sage/rings/polynomial/evaluation_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  322. sage/rings/polynomial/evaluation_flint.pxd +7 -0
  323. sage/rings/polynomial/evaluation_flint.pyx +68 -0
  324. sage/rings/polynomial/hilbert.cpython-312-x86_64-linux-gnu.so +0 -0
  325. sage/rings/polynomial/hilbert.pyx +602 -0
  326. sage/rings/polynomial/polynomial_complex_arb.cpython-312-x86_64-linux-gnu.so +0 -0
  327. sage/rings/polynomial/polynomial_complex_arb.pxd +7 -0
  328. sage/rings/polynomial/polynomial_complex_arb.pyx +963 -0
  329. sage/rings/polynomial/polynomial_integer_dense_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  330. sage/rings/polynomial/polynomial_integer_dense_flint.pxd +13 -0
  331. sage/rings/polynomial/polynomial_integer_dense_flint.pyx +1881 -0
  332. sage/rings/polynomial/polynomial_number_field.cpython-312-x86_64-linux-gnu.so +0 -0
  333. sage/rings/polynomial/polynomial_number_field.pyx +345 -0
  334. sage/rings/polynomial/polynomial_rational_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  335. sage/rings/polynomial/polynomial_rational_flint.pxd +20 -0
  336. sage/rings/polynomial/polynomial_rational_flint.pyx +2598 -0
  337. sage/rings/polynomial/polynomial_zmod_flint.cpython-312-x86_64-linux-gnu.so +0 -0
  338. sage/rings/polynomial/polynomial_zmod_flint.pxd +20 -0
  339. sage/rings/polynomial/polynomial_zmod_flint.pyx +1063 -0
  340. sage/rings/polynomial/real_roots.cpython-312-x86_64-linux-gnu.so +0 -0
  341. sage/rings/polynomial/real_roots.pxd +81 -0
  342. sage/rings/polynomial/real_roots.pyx +4704 -0
  343. sage/rings/polynomial/refine_root.cpython-312-x86_64-linux-gnu.so +0 -0
  344. sage/rings/polynomial/refine_root.pyx +142 -0
  345. sage/rings/polynomial/weil/all.py +4 -0
  346. sage/rings/polynomial/weil/power_sums.h +46 -0
  347. sage/rings/polynomial/weil/weil_polynomials.cpython-312-x86_64-linux-gnu.so +0 -0
  348. sage/rings/polynomial/weil/weil_polynomials.pyx +596 -0
  349. sage/rings/qqbar.py +9025 -0
  350. sage/rings/real_arb.cpython-312-x86_64-linux-gnu.so +0 -0
  351. sage/rings/real_arb.pxd +21 -0
  352. sage/rings/real_arb.pyx +4065 -0
  353. sage/rings/real_interval_absolute.cpython-312-x86_64-linux-gnu.so +0 -0
  354. sage/rings/real_interval_absolute.pyx +1073 -0
  355. sage/rings/real_mpfi.cpython-312-x86_64-linux-gnu.so +0 -0
  356. sage/rings/real_mpfi.pyx +5428 -0
  357. sage/schemes/all__sagemath_flint.py +1 -0
  358. sage/schemes/elliptic_curves/all__sagemath_flint.py +1 -0
  359. sage/schemes/elliptic_curves/descent_two_isogeny.cpython-312-x86_64-linux-gnu.so +0 -0
  360. sage/schemes/elliptic_curves/descent_two_isogeny.pyx +1387 -0
  361. sage/schemes/elliptic_curves/descent_two_isogeny_pari.pxd +5 -0
@@ -0,0 +1,1761 @@
1
+ # sage_setup: distribution = sagemath-flint
2
+ # distutils: language = c++
3
+ # distutils: libraries = NTL_LIBRARIES
4
+ # distutils: extra_compile_args = NTL_CFLAGS
5
+ # distutils: include_dirs = NTL_INCDIR
6
+ # distutils: library_dirs = NTL_LIBDIR
7
+ # distutils: extra_link_args = NTL_LIBEXTRA
8
+ # sage.doctest: needs sagemath-linbox
9
+ """
10
+ Matrices over Cyclotomic Fields
11
+
12
+ The underlying matrix for a Matrix_cyclo_dense object is stored as
13
+ follows: given an n x m matrix over a cyclotomic field of degree d, we
14
+ store a d x (nm) matrix over QQ, each column of which corresponds to
15
+ an element of the original matrix. This can be retrieved via the
16
+ _rational_matrix method. Here is an example illustrating this:
17
+
18
+ EXAMPLES::
19
+
20
+ sage: F.<zeta> = CyclotomicField(5)
21
+ sage: M = Matrix(F, 2, 3, [zeta, 3, zeta**4+5, (zeta+1)**4, 0, 1])
22
+ sage: M
23
+ [ zeta 3 -zeta^3 - zeta^2 - zeta + 4]
24
+ [3*zeta^3 + 5*zeta^2 + 3*zeta 0 1]
25
+
26
+ sage: M._rational_matrix()
27
+ [ 0 3 4 0 0 1]
28
+ [ 1 0 -1 3 0 0]
29
+ [ 0 0 -1 5 0 0]
30
+ [ 0 0 -1 3 0 0]
31
+
32
+
33
+ AUTHORS:
34
+ * William Stein
35
+ * Craig Citro
36
+ """
37
+
38
+ #*****************************************************************************
39
+ # Copyright (C) 2008 William Stein <wstein@gmail.com>
40
+ #
41
+ # This program is free software: you can redistribute it and/or modify
42
+ # it under the terms of the GNU General Public License as published by
43
+ # the Free Software Foundation, either version 2 of the License, or
44
+ # (at your option) any later version.
45
+ # https://www.gnu.org/licenses/
46
+ #*****************************************************************************
47
+
48
+ from cysignals.signals cimport sig_on, sig_off
49
+
50
+ include "sage/libs/ntl/decl.pxi"
51
+
52
+ from sage.structure.element cimport Element
53
+ from sage.misc.randstate cimport randstate, current_randstate
54
+ from sage.libs.gmp.randomize cimport *
55
+
56
+ from sage.libs.flint.types cimport fmpz_t
57
+ from sage.libs.flint.fmpz cimport fmpz_init, fmpz_clear, fmpz_set_mpz, fmpz_one, fmpz_get_mpz, fmpz_add, fmpz_mul, fmpz_sub, fmpz_mul_si, fmpz_mul_si, fmpz_mul_si, fmpz_divexact, fmpz_lcm
58
+ from sage.libs.flint.fmpq cimport fmpq_is_zero, fmpq_set_mpq, fmpq_canonicalise
59
+ from sage.libs.flint.fmpq_mat cimport fmpq_mat_entry_num, fmpq_mat_entry_den, fmpq_mat_entry
60
+
61
+ from sage.matrix.args cimport MatrixArgs_init
62
+ from sage.matrix.constructor import matrix
63
+ from sage.matrix.matrix_space import MatrixSpace
64
+ from sage.matrix.matrix cimport Matrix
65
+ from sage.matrix import matrix_dense
66
+ from sage.structure.element cimport Matrix as baseMatrix
67
+
68
+ from sage.arith.misc import binomial
69
+ from sage.rings.rational_field import QQ
70
+ from sage.rings.integer_ring import ZZ
71
+ from sage.rings.real_mpfr import create_RealNumber as RealNumber
72
+ from sage.rings.integer cimport Integer
73
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
74
+ from sage.rings.number_field.number_field_element cimport NumberFieldElement
75
+ from sage.rings.number_field.number_field_element_quadratic cimport NumberFieldElement_quadratic
76
+
77
+ from sage.misc.verbose import verbose
78
+
79
+
80
+ cdef class Matrix_cyclo_dense(Matrix_dense):
81
+ def __cinit__(self):
82
+ """
83
+ EXAMPLES::
84
+
85
+ sage: from sage.matrix.matrix_cyclo_dense import Matrix_cyclo_dense
86
+ sage: A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, MatrixSpace(CyclotomicField(3),2), [0,1,2,3], True, True)
87
+ sage: type(A)
88
+ <class 'sage.matrix.matrix_cyclo_dense.Matrix_cyclo_dense'>
89
+
90
+ Note that the entries of A haven't even been set yet above; that doesn't
91
+ happen until ``__init__`` is called::
92
+
93
+ sage: A[0,0]
94
+ Traceback (most recent call last):
95
+ ...
96
+ ValueError: matrix entries not yet initialized
97
+ """
98
+ self._degree = self._base_ring.degree()
99
+ self._n = int(self._base_ring._n())
100
+
101
+ def __init__(self, parent, entries=None, copy=None, bint coerce=True):
102
+ """
103
+ Initialize a newly created cyclotomic matrix.
104
+
105
+ INPUT:
106
+
107
+ - ``parent`` -- a matrix space over a cyclotomic number field
108
+
109
+ - ``entries`` -- see :func:`matrix`
110
+
111
+ - ``copy`` -- ignored (for backwards compatibility)
112
+
113
+ - ``coerce`` -- if ``False``, assume without checking that the
114
+ entries lie in the base ring
115
+
116
+ EXAMPLES:
117
+
118
+ This function is called implicitly when you create new
119
+ cyclotomic dense matrices::
120
+
121
+ sage: W.<a> = CyclotomicField(100)
122
+ sage: A = matrix(2, 3, [1, 1/a, 1-a,a, -2/3*a, a^19])
123
+ sage: A
124
+ [ 1 -a^39 + a^29 - a^19 + a^9 -a + 1]
125
+ [ a -2/3*a a^19]
126
+ sage: TestSuite(A).run()
127
+
128
+ TESTS::
129
+
130
+ sage: matrix(W, 2, 1, a)
131
+ Traceback (most recent call last):
132
+ ...
133
+ TypeError: nonzero scalar matrix must be square
134
+
135
+ We call __init__ explicitly below::
136
+
137
+ sage: from sage.matrix.matrix_cyclo_dense import Matrix_cyclo_dense
138
+ sage: A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, MatrixSpace(CyclotomicField(3),2), [0,1,2,3], True, True)
139
+ sage: A.__init__(MatrixSpace(CyclotomicField(3),2), [0,1,2,3], True, True)
140
+ sage: A
141
+ [0 1]
142
+ [2 3]
143
+ """
144
+ ma = MatrixArgs_init(parent, entries)
145
+ cdef list L = []
146
+ for x in ma.iter(coerce):
147
+ L += x.list()
148
+
149
+ QQspace = MatrixSpace(QQ, self._nrows * self._ncols, self._degree)
150
+ QQmat = Matrix_rational_dense(QQspace, L, False, False)
151
+ self._matrix = QQmat.transpose()
152
+
153
+ cdef set_unsafe(self, Py_ssize_t i, Py_ssize_t j, value):
154
+ """
155
+ Set the ij-th entry of ``self``.
156
+
157
+ WARNING: This function does no bounds checking whatsoever, as
158
+ the name suggests. It also assumes certain facts about the
159
+ internal representation of cyclotomic fields. This is intended
160
+ for internal use only.
161
+
162
+ EXAMPLES::
163
+
164
+ sage: K.<z> = CyclotomicField(11) ; M = Matrix(K,2,range(4))
165
+ sage: M[0,1] = z ; M
166
+ [0 z]
167
+ [2 3]
168
+
169
+ sage: K.<z> = CyclotomicField(3) ; M = Matrix(K,2,range(4))
170
+ sage: M[1,1] = z+1 ; M
171
+ [ 0 1]
172
+ [ 2 z + 1]
173
+
174
+ TESTS:
175
+
176
+ Since separate code exists for each quadratic field, we need
177
+ doctests for each.::
178
+
179
+ sage: K.<z> = CyclotomicField(4) ; M = Matrix(K,2,range(4))
180
+ sage: M[1,1] = z+1 ; M
181
+ [ 0 1]
182
+ [ 2 z + 1]
183
+ sage: K.<z> = CyclotomicField(6) ; M = Matrix(K,2,range(4))
184
+ sage: M[1,1] = z+1 ; M
185
+ [ 0 1]
186
+ [ 2 z + 1]
187
+ """
188
+ # NEW FAST VERSION -- makes assumptions about how the
189
+ # cyclotomic field is implemented.
190
+ cdef Py_ssize_t k, c
191
+ cdef NumberFieldElement v
192
+ cdef NumberFieldElement_quadratic qv
193
+ cdef mpz_t numer, denom
194
+ cdef fmpz_t ftmp
195
+
196
+ # The i,j entry is the (i * self._ncols + j)'th column.
197
+ c = i * self._ncols + j
198
+
199
+ if self._degree == 2:
200
+ # Must be coded differently, since elements of
201
+ # quadratic number fields are stored differently.
202
+ qv = <NumberFieldElement_quadratic> value
203
+ if self._n == 4:
204
+ fmpz_set_mpz(fmpq_mat_entry_num(self._matrix._matrix, 0, c),
205
+ qv.a)
206
+ fmpz_set_mpz(fmpq_mat_entry_den(self._matrix._matrix, 0, c),
207
+ qv.denom)
208
+ fmpq_canonicalise(fmpq_mat_entry(self._matrix._matrix, 0, c))
209
+
210
+ fmpz_set_mpz(fmpq_mat_entry_num(self._matrix._matrix, 1, c),
211
+ qv.b)
212
+ fmpz_set_mpz(fmpq_mat_entry_den(self._matrix._matrix, 1, c),
213
+ qv.denom)
214
+ fmpq_canonicalise(fmpq_mat_entry(self._matrix._matrix, 1, c))
215
+ elif self._n == 3:
216
+ # mat[0,c] = (x.a + x.b) / x.denom
217
+ fmpz_set_mpz(fmpq_mat_entry_num(self._matrix._matrix, 0, c),
218
+ qv.a)
219
+
220
+ # NOTE: it would be convenient here to have fmpz_add_mpz
221
+ fmpz_init(ftmp)
222
+ fmpz_set_mpz(ftmp, qv.b)
223
+ fmpz_add(fmpq_mat_entry_num(self._matrix._matrix, 0, c),
224
+ fmpq_mat_entry_num(self._matrix._matrix, 0, c),
225
+ ftmp)
226
+ fmpz_clear(ftmp)
227
+
228
+ fmpz_set_mpz(fmpq_mat_entry_den(self._matrix._matrix, 0, c),
229
+ qv.denom)
230
+ fmpq_canonicalise(fmpq_mat_entry(self._matrix._matrix, 0, c))
231
+
232
+ # mat[1,c] = (2 x.b) / x.denom
233
+ fmpz_set_mpz(fmpq_mat_entry_num(self._matrix._matrix, 1, c),
234
+ qv.b)
235
+ fmpz_mul_si(fmpq_mat_entry_num(self._matrix._matrix, 1, c),
236
+ fmpq_mat_entry_num(self._matrix._matrix, 1, c), 2)
237
+ fmpz_set_mpz(fmpq_mat_entry_den(self._matrix._matrix, 1, c),
238
+ qv.denom)
239
+ fmpq_canonicalise(fmpq_mat_entry(self._matrix._matrix, 1, c))
240
+ else: # self._n is 6
241
+ fmpz_set_mpz(fmpq_mat_entry_num(self._matrix._matrix, 0, c),
242
+ qv.a)
243
+
244
+ # NOTE: it would be convenient here to have fmpz_add_mpz
245
+ fmpz_init(ftmp)
246
+ fmpz_set_mpz(ftmp, qv.b)
247
+ fmpz_sub(fmpq_mat_entry_num(self._matrix._matrix, 0, c),
248
+ fmpq_mat_entry_num(self._matrix._matrix, 0, c),
249
+ ftmp)
250
+ fmpz_clear(ftmp)
251
+
252
+ fmpz_set_mpz(fmpq_mat_entry_den(self._matrix._matrix, 0, c),
253
+ qv.denom)
254
+ fmpq_canonicalise(fmpq_mat_entry(self._matrix._matrix, 0, c))
255
+
256
+ fmpz_set_mpz(fmpq_mat_entry_num(self._matrix._matrix, 1, c),
257
+ qv.b)
258
+ fmpz_mul_si(fmpq_mat_entry_num(self._matrix._matrix, 1, c),
259
+ fmpq_mat_entry_num(self._matrix._matrix, 1, c), 2)
260
+ fmpz_set_mpz(fmpq_mat_entry_den(self._matrix._matrix, 1, c),
261
+ qv.denom)
262
+ fmpq_canonicalise(fmpq_mat_entry(self._matrix._matrix, 1, c))
263
+ return
264
+
265
+ v = value
266
+
267
+ mpz_init(numer)
268
+ mpz_init(denom)
269
+
270
+ v._ntl_denom_as_mpz(denom)
271
+ for k in range(self._degree):
272
+ v._ntl_coeff_as_mpz(numer, k)
273
+ fmpz_set_mpz(fmpq_mat_entry_num(self._matrix._matrix, k, c), numer)
274
+ fmpz_set_mpz(fmpq_mat_entry_den(self._matrix._matrix, k, c), denom)
275
+ fmpq_canonicalise(fmpq_mat_entry(self._matrix._matrix, k, c))
276
+
277
+ mpz_clear(numer)
278
+ mpz_clear(denom)
279
+
280
+ cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j):
281
+ """
282
+ Get the ij-th of ``self``.
283
+
284
+ WARNING: As the name suggests, expect segfaults if i,j are out
285
+ of bounds!! This is for internal use only.
286
+
287
+ EXAMPLES::
288
+
289
+ sage: W.<a> = CyclotomicField(5)
290
+ sage: A = matrix(2, 3, [9939208341, 1/a, 1-a,a, -2/3*a, a^19])
291
+
292
+ This implicitly calls get_unsafe::
293
+
294
+ sage: A[0,0]
295
+ 9939208341
296
+
297
+ TESTS:
298
+
299
+ Since separate code exists for each quadratic field, we need
300
+ doctests for each.::
301
+
302
+ sage: K.<z> = CyclotomicField(3) ; M = Matrix(K,2,range(4))
303
+ sage: M[1,1] = z+1 ; M[1,1]
304
+ z + 1
305
+ sage: (M[1,1] - M[0,1])**3
306
+ 1
307
+ sage: K.<z> = CyclotomicField(4) ; M = Matrix(K,2,range(4))
308
+ sage: M[1,1] = z+1 ; M[1,1]
309
+ z + 1
310
+ sage: (M[1,1] - M[0,1])**4
311
+ 1
312
+ sage: K.<z> = CyclotomicField(6) ; M = Matrix(K,2,range(4))
313
+ sage: M[1,1] = z+1 ; M[1,1]
314
+ z + 1
315
+ sage: (M[1,1] - M[0,1])**6
316
+ 1
317
+ """
318
+ cdef Py_ssize_t k, c
319
+ cdef NumberFieldElement x
320
+ cdef NumberFieldElement_quadratic xq
321
+ cdef mpz_t tmp
322
+ cdef fmpz_t denom, ftmp
323
+ cdef ZZ_c coeff
324
+
325
+ if self._matrix is None:
326
+ raise ValueError("matrix entries not yet initialized")
327
+
328
+ c = i * self._ncols + j
329
+ mpz_init(tmp)
330
+
331
+ if self._degree == 2:
332
+ fmpz_init(ftmp)
333
+ xq = self._base_ring(0)
334
+ if self._n == 4:
335
+ fmpz_mul(ftmp, fmpq_mat_entry_num(self._matrix._matrix, 0, c),
336
+ fmpq_mat_entry_den(self._matrix._matrix, 1, c))
337
+ fmpz_get_mpz(xq.a, ftmp)
338
+ fmpz_mul(ftmp, fmpq_mat_entry_num(self._matrix._matrix, 1, c),
339
+ fmpq_mat_entry_den(self._matrix._matrix, 0, c))
340
+ fmpz_get_mpz(xq.b, ftmp)
341
+ fmpz_mul(ftmp, fmpq_mat_entry_den(self._matrix._matrix, 0, c),
342
+ fmpq_mat_entry_den(self._matrix._matrix, 1, c))
343
+ fmpz_get_mpz(xq.denom, ftmp)
344
+
345
+ else: # n is 3 or 6
346
+ fmpz_mul(ftmp, fmpq_mat_entry_num(self._matrix._matrix, 0, c),
347
+ fmpq_mat_entry_den(self._matrix._matrix, 1, c))
348
+ fmpz_mul_si(ftmp, ftmp, 2)
349
+ fmpz_get_mpz(xq.a, ftmp)
350
+ fmpz_mul(ftmp, fmpq_mat_entry_den(self._matrix._matrix, 0, c),
351
+ fmpq_mat_entry_num(self._matrix._matrix, 1, c))
352
+ fmpz_get_mpz(tmp, ftmp)
353
+ if self._n == 3:
354
+ mpz_sub(xq.a, xq.a, tmp)
355
+ else: # n == 6
356
+ mpz_add(xq.a, xq.a, tmp)
357
+
358
+ fmpz_mul(ftmp, fmpq_mat_entry_den(self._matrix._matrix, 0, c),
359
+ fmpq_mat_entry_num(self._matrix._matrix, 1, c))
360
+ fmpz_get_mpz(xq.b, ftmp)
361
+
362
+ fmpz_mul(ftmp, fmpq_mat_entry_den(self._matrix._matrix, 0, c),
363
+ fmpq_mat_entry_den(self._matrix._matrix, 1, c))
364
+ fmpz_get_mpz(xq.denom, ftmp)
365
+ mpz_mul_si(xq.denom, xq.denom, 2)
366
+
367
+ xq._reduce_c_()
368
+ mpz_clear(tmp)
369
+ fmpz_clear(ftmp)
370
+ return xq
371
+
372
+ x = self._base_ring(0)
373
+ fmpz_init(denom)
374
+ fmpz_init(ftmp)
375
+ fmpz_one(denom)
376
+
377
+ # Get the least common multiple of the denominators in
378
+ # this column.
379
+ for k in range(self._degree):
380
+ fmpz_lcm(denom, denom, fmpq_mat_entry_den(self._matrix._matrix, k, c))
381
+
382
+ for k in range(self._degree):
383
+ # set each entry of x to a*denom/b where a/b is the
384
+ # k,c entry of _matrix.
385
+ fmpz_mul(ftmp, fmpq_mat_entry_num(self._matrix._matrix, k, c), denom)
386
+ fmpz_divexact(ftmp, ftmp, fmpq_mat_entry_den(self._matrix._matrix, k, c))
387
+ # Now set k-th entry of x's numerator to tmp
388
+ fmpz_get_mpz(tmp, ftmp)
389
+ mpz_to_ZZ(&coeff, tmp)
390
+ ZZX_SetCoeff(x._numerator, k, coeff)
391
+
392
+ # Set the denominator of x to denom.
393
+ fmpz_get_mpz(tmp, denom)
394
+ mpz_to_ZZ(&x._denominator, tmp)
395
+ fmpz_clear(denom)
396
+ mpz_clear(tmp)
397
+ fmpz_clear(ftmp)
398
+
399
+ return x
400
+
401
+ cdef bint get_is_zero_unsafe(self, Py_ssize_t i, Py_ssize_t j) except -1:
402
+ r"""
403
+ Return 1 if the entry ``(i, j)`` is zero, otherwise 0.
404
+
405
+ EXAMPLES::
406
+
407
+ sage: K.<z> = CyclotomicField(3)
408
+ sage: A = matrix(K, 4, 3, [0, -z, -2, -2*z + 2, 2*z, z, z, 1-z, 2+3*z, z, 1+z, 0])
409
+ sage: A.zero_pattern_matrix() # indirect doctest
410
+ [1 0 0]
411
+ [0 0 0]
412
+ [0 0 0]
413
+ [0 0 1]
414
+ """
415
+ cdef int a
416
+ for a in range(self._degree):
417
+ if not self._matrix.get_is_zero_unsafe(a, j+i*self._ncols):
418
+ return False
419
+ return True
420
+
421
+ def _pickle(self):
422
+ """
423
+ Used for pickling matrices. This function returns the
424
+ underlying data and pickle version.
425
+
426
+ OUTPUT:
427
+
428
+ - data; output of pickle
429
+ - version; integer
430
+
431
+ EXAMPLES::
432
+
433
+ sage: K.<z> = CyclotomicField(3)
434
+ sage: w = matrix(K, 3, 3, [0, -z, -2, -2*z + 2, 2*z, z, z, 1-z, 2+3*z])
435
+ sage: w._pickle()
436
+ (('0 0 -2 2 0 0 0 1 2 0 -1 0 -2 2 1 1 -1 3', 0), 0)
437
+ """
438
+ data = self._matrix._pickle()
439
+ return data, 0
440
+
441
+ def _unpickle(self, data, int version):
442
+ """
443
+ Called when unpickling matrices.
444
+
445
+ INPUT:
446
+
447
+ - ``data`` -- string
448
+ - ``version`` -- integer
449
+
450
+ This modifies ``self``.
451
+
452
+ EXAMPLES::
453
+
454
+ sage: K.<z> = CyclotomicField(3)
455
+ sage: w = matrix(K, 3, 3, [0, -z, -2, -2*z + 2, 2*z, z, z, 1-z, 2+3*z])
456
+ sage: data, version = w._pickle()
457
+ sage: k = w.parent()(0)
458
+ sage: k._unpickle(data, version)
459
+ sage: k == w
460
+ True
461
+ """
462
+ #self.check_mutability()
463
+ if version == 0:
464
+ self._matrix = Matrix_rational_dense(MatrixSpace(QQ, self._degree, self._nrows*self._ncols), None, False, False)
465
+ self._matrix._unpickle(*data) # data is (data, matrix_QQ_version)
466
+ else:
467
+ raise RuntimeError("unknown matrix version (=%s)" % version)
468
+
469
+ ########################################################################
470
+ # LEVEL 2 functionality
471
+ # x * cdef _add_
472
+ # x * cdef _sub_
473
+ # * cdef _mul_
474
+ # x * cdef _lmul_ -- scalar multiplication
475
+ # x * cpdef _richcmp_
476
+ # x * __neg__
477
+ # * __invert__
478
+ # x * __copy__
479
+ # * _multiply_classical
480
+ # * _list -- list of underlying elements (need not be a copy)
481
+ # * _dict -- sparse dictionary of underlying elements (need not be a copy)
482
+ ########################################################################
483
+
484
+ cpdef _add_(self, right):
485
+ """
486
+ Return the sum of two dense cyclotomic matrices.
487
+
488
+ INPUT:
489
+
490
+ - ``self``, ``right`` -- dense cyclotomic matrices with the same
491
+ parents
492
+
493
+ OUTPUT: a dense cyclotomic matrix
494
+
495
+ EXAMPLES::
496
+
497
+ sage: W.<z> = CyclotomicField(5)
498
+ sage: A = matrix(2, 3, [1,z,z^2,z^3,z^4,2/3*z]); B = matrix(2, 3, [-1,2*z,3*z^2,5*z+1,z^4,1/3*z])
499
+ sage: A + B
500
+ [ 0 3*z 4*z^2]
501
+ [ z^3 + 5*z + 1 -2*z^3 - 2*z^2 - 2*z - 2 z]
502
+
503
+ Verify directly that the above output is correct::
504
+
505
+ sage: (A+B).list() == [A.list()[i]+B.list()[i] for i in range(6)]
506
+ True
507
+ """
508
+ cdef Matrix_cyclo_dense A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, self.parent(), None, None, None)
509
+ # Fix the redundancy here.
510
+ A._matrix = self._matrix + (<Matrix_cyclo_dense>right)._matrix
511
+ return A
512
+
513
+ cpdef _sub_(self, right):
514
+ """
515
+ Return the difference of two dense cyclotomic matrices.
516
+
517
+ INPUT:
518
+
519
+ - ``self``, ``right`` -- dense cyclotomic matrices with the same
520
+ parent
521
+
522
+ OUTPUT: a dense cyclotomic matrix
523
+
524
+ EXAMPLES::
525
+
526
+ sage: W.<z> = CyclotomicField(5)
527
+ sage: A = matrix(2, 3, [1,z,z^2,z^3,z^4,2/3*z]); B = matrix(2, 3, [-1,2*z,3*z^2,5*z+1,z^4,1/3*z])
528
+ sage: A - B
529
+ [ 2 -z -2*z^2]
530
+ [z^3 - 5*z - 1 0 1/3*z]
531
+
532
+ Verify directly that the above output is correct::
533
+
534
+ sage: (A-B).list() == [A.list()[i]-B.list()[i] for i in range(6)]
535
+ True
536
+ """
537
+ cdef Matrix_cyclo_dense A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, self.parent(), None, None, None)
538
+ A._matrix = self._matrix - (<Matrix_cyclo_dense>right)._matrix
539
+ return A
540
+
541
+ cpdef _lmul_(self, Element right):
542
+ """
543
+ Multiply a dense cyclotomic matrix by a scalar.
544
+
545
+ INPUT:
546
+
547
+ - ``right`` -- scalar in the base cyclotomic field
548
+
549
+ EXAMPLES::
550
+
551
+ sage: W.<z> = CyclotomicField(5)
552
+ sage: A = matrix(2, 3, [1,z,z^2,z^3,z^4,2/3*z])
553
+ sage: (1 + z/3)*A
554
+ [ 1/3*z + 1 1/3*z^2 + z 1/3*z^3 + z^2]
555
+ [2/3*z^3 - 1/3*z^2 - 1/3*z - 1/3 -z^3 - z^2 - z - 2/3 2/9*z^2 + 2/3*z]
556
+
557
+ Verify directly that the above output is correct::
558
+
559
+ sage: ((1+z/3)*A).list() == [(1+z/3)*x for x in A.list()]
560
+ True
561
+ """
562
+ if right.is_one():
563
+ return self
564
+ elif right.is_zero():
565
+ return self.parent().zero()
566
+
567
+ # Create a new matrix object but with the _matrix attribute not initialized:
568
+ cdef Matrix_cyclo_dense A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense,
569
+ self.parent(), None, None, None)
570
+
571
+ if right.is_rational():
572
+ A._matrix = self._matrix._lmul_(right._rational_())
573
+ else:
574
+ # Multiply by nontrivial element of the cyclotomic number field
575
+ # We do this by finding the matrix of this element, then left
576
+ # multiplying by it. We have to tweak the matrix some to
577
+ # get the right basis, etc.
578
+ T = right.matrix().transpose()
579
+ A._matrix = T * self._matrix
580
+ return A
581
+
582
+ cdef _matrix_times_matrix_(self, baseMatrix right):
583
+ """
584
+ Return the product of two cyclotomic dense matrices.
585
+
586
+ INPUT:
587
+
588
+ - ``self``, ``right`` -- cyclotomic dense matrices with compatible
589
+ parents (same base ring, and compatible dimensions for matrix
590
+ multiplication)
591
+
592
+ OUTPUT: cyclotomic dense matrix
593
+
594
+ ALGORITHM:
595
+
596
+ Use a multimodular algorithm that involves multiplying the two matrices
597
+ modulo split primes.
598
+
599
+ EXAMPLES::
600
+
601
+ sage: W.<z> = CyclotomicField(5)
602
+ sage: A = matrix(3, 3, [1,z,z^2,z^3,z^4,2/3*z,-3*z,z,2+z]); B = matrix(3, 3, [-1,2*z,3*z^2,5*z+1,z^4,1/3*z,2-z,3-z,5-z])
603
+ sage: A*B
604
+ [ -z^3 + 7*z^2 + z - 1 -z^3 + 3*z^2 + 2*z + 1 -z^3 + 25/3*z^2]
605
+ [-2*z^3 - 5/3*z^2 + 1/3*z + 4 -z^3 - 8/3*z^2 - 2 -2/3*z^2 + 10/3*z + 10/3]
606
+ [ 4*z^2 + 4*z + 4 -7*z^2 + z + 7 -9*z^3 - 2/3*z^2 + 3*z + 10]
607
+
608
+ Verify that the answer above is consistent with what the
609
+ generic sparse matrix multiply gives (which is a different
610
+ implementation).::
611
+
612
+ sage: A*B == A.sparse_matrix()*B.sparse_matrix()
613
+ True
614
+
615
+ sage: N1 = Matrix(CyclotomicField(6), 1, [1])
616
+ sage: cf6 = CyclotomicField(6) ; z6 = cf6.0
617
+ sage: N2 = Matrix(CyclotomicField(6), 1, 5, [0,1,z6,-z6,-z6+1])
618
+ sage: N1*N2
619
+ [ 0 1 zeta6 -zeta6 -zeta6 + 1]
620
+ sage: N1 = Matrix(CyclotomicField(6), 1, [-1])
621
+ sage: N1*N2
622
+ [ 0 -1 -zeta6 zeta6 zeta6 - 1]
623
+
624
+ Verify that a degenerate case bug reported at :issue:`5974` is fixed.
625
+
626
+ sage: K.<zeta6>=CyclotomicField(6); matrix(K,1,2) * matrix(K,2,[0, 1, 0, -2*zeta6, 0, 0, 1, -2*zeta6 + 1])
627
+ [0 0 0 0]
628
+
629
+ TESTS:
630
+
631
+ This is from :issue:`8666`::
632
+
633
+ sage: K.<zeta4> = CyclotomicField(4)
634
+ sage: m = matrix(K, [125])
635
+ sage: n = matrix(K, [186])
636
+ sage: m*n
637
+ [23250]
638
+ sage: (-m)*n
639
+ [-23250]
640
+ """
641
+ try:
642
+ from .matrix_cyclo_linbox import _matrix_times_matrix_
643
+ except ImportError:
644
+ return Matrix._matrix_times_matrix_(self, right)
645
+ else:
646
+ return _matrix_times_matrix_(self, right)
647
+
648
+ cdef long _hash_(self) except -1:
649
+ """
650
+ Return hash of an immutable matrix.
651
+
652
+ This raises a :exc:`TypeError` if input matrix is mutable.
653
+
654
+ EXAMPLES:
655
+
656
+ This is called implicitly by the hash function.::
657
+
658
+ sage: W.<z> = CyclotomicField(5)
659
+ sage: A = matrix(W, 2, 2, [1,z,-z,1+z/2])
660
+
661
+ The matrix must be immutable.::
662
+
663
+ sage: hash(A)
664
+ Traceback (most recent call last):
665
+ ...
666
+ TypeError: mutable matrices are unhashable
667
+ sage: A.set_immutable()
668
+
669
+ Yes, this works::
670
+
671
+ sage: hash(A) # random
672
+ 3107179158321342168
673
+
674
+ ::
675
+
676
+ sage: W.<z> = CyclotomicField(5)
677
+ sage: A = matrix(W, 2, 2, [1,2/3*z+z^2,-z,1+z/2])
678
+ sage: hash(A)
679
+ Traceback (most recent call last):
680
+ ...
681
+ TypeError: mutable matrices are unhashable
682
+ sage: A.set_immutable()
683
+ sage: A.__hash__() # random
684
+ 2347601038649299176
685
+ """
686
+ return hash(self._matrix)
687
+
688
+ cpdef _richcmp_(self, right, int op):
689
+ """
690
+ Implement comparison of two cyclotomic matrices with
691
+ identical parents.
692
+
693
+ INPUT:
694
+
695
+ - ``self``, ``right`` -- matrices with same parent
696
+
697
+ OUTPUT: boolean
698
+
699
+ EXAMPLES::
700
+
701
+ sage: W.<z> = CyclotomicField(5)
702
+ sage: A = matrix(W, 2, 2, [1,z,-z,1+z/2])
703
+
704
+ These implicitly call richcmp::
705
+
706
+ sage: A == 5
707
+ False
708
+ sage: A < 100
709
+ True
710
+
711
+ This function is called implicitly when comparisons with matrices
712
+ are done::
713
+
714
+ sage: W.<z> = CyclotomicField(5)
715
+ sage: A = matrix(W, 2, 2, [1,2/3*z+z^2,-z,1+z/2])
716
+ sage: A == A
717
+ True
718
+ sage: A < 2*A
719
+ True
720
+ sage: A >= 2*A
721
+ False
722
+ """
723
+ return self._matrix._richcmp_((<Matrix_cyclo_dense>right)._matrix, op)
724
+
725
+ def __copy__(self):
726
+ """
727
+ Make a copy of this matrix.
728
+
729
+ EXAMPLES:
730
+
731
+ We create a cyclotomic matrix::
732
+
733
+ sage: W.<z> = CyclotomicField(5)
734
+ sage: A = matrix(W, 2, 2, [1,2/3*z+z^2,-z,1+z/2])
735
+
736
+ We make a copy of A::
737
+
738
+ sage: C = A.__copy__()
739
+
740
+ We make another reference to A::
741
+
742
+ sage: B = A
743
+
744
+ Changing this reference changes A itself::
745
+
746
+ sage: B[0,0] = 10
747
+ sage: A[0,0]
748
+ 10
749
+
750
+ Changing the copy does not change A::
751
+
752
+ sage: C[0,0] = 20
753
+ sage: C[0,0]
754
+ 20
755
+ sage: A[0,0]
756
+ 10
757
+ """
758
+ cdef Matrix_cyclo_dense A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, self.parent(), None, None, None)
759
+ A._matrix = self._matrix.__copy__()
760
+ return A
761
+
762
+ def __neg__(self):
763
+ """
764
+ Return the negative of this matrix.
765
+
766
+ OUTPUT: matrix
767
+
768
+ EXAMPLES::
769
+
770
+ sage: W.<z> = CyclotomicField(5)
771
+ sage: A = matrix(W, 2, 2, [1,2/3*z+z^2,-z,1+z/2])
772
+ sage: -A
773
+ [ -1 -z^2 - 2/3*z]
774
+ [ z -1/2*z - 1]
775
+ sage: A.__neg__()
776
+ [ -1 -z^2 - 2/3*z]
777
+ [ z -1/2*z - 1]
778
+ """
779
+ cdef Matrix_cyclo_dense A = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, self.parent(), None, None, None)
780
+ A._matrix = -self._matrix
781
+ return A
782
+
783
+ ########################################################################
784
+ # LEVEL 3 functionality (Optional)
785
+ # * __deepcopy__
786
+ # * __invert__
787
+ # * Matrix windows -- only if you need strassen for that base
788
+ # * Other functions (list them here):
789
+ # * Specialized echelon form
790
+ # * tensor product
791
+ ########################################################################
792
+
793
+ def set_immutable(self):
794
+ """
795
+ Change this matrix so that it is immutable.
796
+
797
+ EXAMPLES::
798
+
799
+ sage: W.<z> = CyclotomicField(5)
800
+ sage: A = matrix(W, 2, 2, [1,2/3*z+z^2,-z,1+z/2])
801
+ sage: A[0,0] = 10
802
+ sage: A.set_immutable()
803
+ sage: A[0,0] = 20
804
+ Traceback (most recent call last):
805
+ ...
806
+ ValueError: matrix is immutable; please change a copy instead (i.e., use copy(M) to change a copy of M).
807
+
808
+ Note that there is no function to set a matrix to be mutable
809
+ again, since such a function would violate the whole point.
810
+ Instead make a copy, which is always mutable by default.::
811
+
812
+ sage: A.set_mutable()
813
+ Traceback (most recent call last):
814
+ ...
815
+ AttributeError: 'sage.matrix.matrix_cyclo_dense.Matrix_cyclo_dense' object has no attribute 'set_mutable'...
816
+ sage: B = A.__copy__()
817
+ sage: B[0,0] = 20
818
+ sage: B[0,0]
819
+ 20
820
+ """
821
+ self._matrix.set_immutable()
822
+ matrix_dense.Matrix_dense.set_immutable(self)
823
+
824
+ def _rational_matrix(self):
825
+ """
826
+ Return the underlying rational matrix corresponding to ``self``.
827
+
828
+ EXAMPLES::
829
+
830
+ sage: Matrix(CyclotomicField(7),4,4,range(16))._rational_matrix()
831
+ [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
832
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
833
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
834
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
835
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
836
+ [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
837
+ sage: Matrix(CyclotomicField(7),4,4,[CyclotomicField(7).gen(0)**i for i in range(16)])._rational_matrix()
838
+ [ 1 0 0 0 0 0 -1 1 0 0 0 0 0 -1 1 0]
839
+ [ 0 1 0 0 0 0 -1 0 1 0 0 0 0 -1 0 1]
840
+ [ 0 0 1 0 0 0 -1 0 0 1 0 0 0 -1 0 0]
841
+ [ 0 0 0 1 0 0 -1 0 0 0 1 0 0 -1 0 0]
842
+ [ 0 0 0 0 1 0 -1 0 0 0 0 1 0 -1 0 0]
843
+ [ 0 0 0 0 0 1 -1 0 0 0 0 0 1 -1 0 0]
844
+ """
845
+ return self._matrix
846
+
847
+ def denominator(self):
848
+ """
849
+ Return the denominator of the entries of this matrix.
850
+
851
+ OUTPUT: integer; the smallest integer `d` so that ``d * self`` has
852
+ entries in the ring of integers
853
+
854
+ EXAMPLES::
855
+
856
+ sage: W.<z> = CyclotomicField(5)
857
+ sage: A = matrix(W, 2, 2, [-2/7,2/3*z+z^2,-z,1+z/19]); A
858
+ [ -2/7 z^2 + 2/3*z]
859
+ [ -z 1/19*z + 1]
860
+ sage: d = A.denominator(); d
861
+ 399
862
+ """
863
+ return self._matrix.denominator()
864
+
865
+ def coefficient_bound(self):
866
+ r"""
867
+ Return an upper bound for the (complex) absolute values of all
868
+ entries of ``self`` with respect to all embeddings.
869
+
870
+ Use ``self.height()`` for a sharper bound.
871
+
872
+ This is computed using just the Cauchy-Schwarz inequality, i.e.,
873
+ we use the fact that ::
874
+
875
+ \left| \sum_i a_i\zeta^i \right| \leq \sum_i |a_i|,
876
+
877
+ as `|\zeta| = 1`.
878
+
879
+ EXAMPLES::
880
+
881
+ sage: W.<z> = CyclotomicField(5)
882
+ sage: A = matrix(W, 2, 2, [1+z, 0, 9*z+7, -3 + 4*z]); A
883
+ [ z + 1 0]
884
+ [9*z + 7 4*z - 3]
885
+ sage: A.coefficient_bound()
886
+ 16
887
+
888
+ The above bound is just `9 + 7`, coming from the lower left entry.
889
+ A better bound would be the following::
890
+
891
+ sage: (A[1,0]).abs()
892
+ 12.997543663...
893
+ """
894
+ cdef Py_ssize_t i, j
895
+
896
+ bound = 0
897
+ for i from 0 <= i < self._matrix._ncols:
898
+
899
+ n = 0
900
+ for j from 0 <= j < self._matrix._nrows:
901
+ n += self._matrix[j, i].abs()
902
+ if bound < n:
903
+ bound = n
904
+
905
+ return bound
906
+
907
+ def height(self):
908
+ r"""
909
+ Return the height of ``self``.
910
+
911
+ If we let `a_{ij}` be the `i,j` entry of self, then we define
912
+ the height of ``self`` to be
913
+
914
+ `\max_v \max_{i,j} |a_{ij}|_v`,
915
+
916
+ where `v` runs over all complex embeddings of ``self.base_ring()``.
917
+
918
+ EXAMPLES::
919
+
920
+ sage: W.<z> = CyclotomicField(5)
921
+ sage: A = matrix(W, 2, 2, [1+z, 0, 9*z+7, -3 + 4*z]); A
922
+ [ z + 1 0]
923
+ [9*z + 7 4*z - 3]
924
+ sage: A.height()
925
+ 12.997543663...
926
+ sage: (A[1,0]).abs()
927
+ 12.997543663...
928
+ """
929
+ cdef Py_ssize_t i, j
930
+
931
+ emb = self._base_ring.complex_embeddings()
932
+
933
+ ht = 0
934
+ for i from 0 <= i < self._nrows:
935
+ for j from 0 <= j < self._ncols:
936
+ t = max([ x.norm().sqrt() for x in [ f(self.get_unsafe(i,j)) for f in emb ] ])
937
+ if t > ht:
938
+ ht = t
939
+
940
+ return ht
941
+
942
+ cdef _randomize_rational_column_unsafe(Matrix_cyclo_dense self,
943
+ Py_ssize_t col, mpz_t nump1, mpz_t denp1, distribution=None):
944
+ """
945
+ Randomizes all entries in column ``col``. This is a helper method
946
+ used in the implementation of dense matrices over cyclotomic fields.
947
+
948
+ INPUT:
949
+
950
+ - ``col`` -- integer indicating the column; must be coercible to
951
+ ``int``, and this must lie between 0 (inclusive) and
952
+ ``self._ncols`` (exclusive), since no bounds-checking is performed
953
+ - ``nump1`` -- integer; numerator bound plus one
954
+ - ``denp1`` -- integer; denominator bound plus one
955
+ - ``distribution`` -- ``None`` or '1/n' (default: ``None``); if '1/n'
956
+ then ``num_bound``, ``den_bound`` are ignored and numbers are chosen
957
+ using the GMP function ``mpq_randomize_entry_recip_uniform``
958
+ - ``nonzero`` -- boolean (default: ``False``); whether the new entries
959
+ are forced to be nonzero
960
+
961
+ OUTPUT: none, the matrix is modified in-space
962
+
963
+ WARNING:
964
+
965
+ This method is quite unsafe. It's called from the method
966
+ ``randomize``, but probably shouldn't be called from another method
967
+ without first carefully reading the source code!
968
+
969
+ TESTS:
970
+
971
+ The following doctests are all indirect::
972
+
973
+ sage: MS = MatrixSpace(CyclotomicField(10), 4, 4)
974
+ sage: A = MS.random_element(); A # random
975
+ [ -2*zeta10^3 + 2*zeta10^2 - zeta10 zeta10^3 + 2*zeta10^2 - zeta10 + 1 0 -2*zeta10^3 + zeta10^2 - 2*zeta10 + 2]
976
+ [ 0 -zeta10^3 + 2*zeta10^2 - zeta10 -zeta10^3 + 1 zeta10^3 + zeta10]
977
+ [ 1/2*zeta10^2 -2*zeta10^2 + 2 -1/2*zeta10^3 + 1/2*zeta10^2 + 2 2*zeta10^3 - zeta10^2 - 2]
978
+ [ 1 zeta10^2 + 2 2*zeta10^2 2*zeta10 - 2]
979
+ sage: A.parent() is MS
980
+ True
981
+
982
+ ::
983
+
984
+ sage: B = MS.random_element(density=0.5)
985
+ sage: all(a in (-2, -1, -1/2, 0, 1/2, 1, 2) for a in B._rational_matrix().list())
986
+ True
987
+ sage: while set(B._rational_matrix().list()) != set((-2, -1, -1/2, 0, 1/2, 1, 2)):
988
+ ....: B = MS.random_element(density=0.5)
989
+
990
+ ::
991
+
992
+ sage: C = MS.random_element(density=0.5, num_bound=20, den_bound=20)
993
+ sage: all(abs(a.denominator()) <= 20 and abs(a.numerator()) <= 20 for a in C._rational_matrix().list())
994
+ True
995
+ sage: while not (any(abs(a.denominator()) == 20 for a in C._rational_matrix().list())
996
+ ....: and any(abs(a.numerator()) == 20 for a in C._rational_matrix().list())):
997
+ ....: C = MS.random_element(density=0.5, num_bound=20, den_bound=20)
998
+ """
999
+ cdef Py_ssize_t i
1000
+ cdef Matrix_rational_dense mat = self._matrix
1001
+ cdef mpq_t tmp
1002
+
1003
+ sig_on()
1004
+ mpq_init(tmp)
1005
+ if distribution == "1/n":
1006
+ for i in range(mat._nrows):
1007
+ mpq_randomize_entry_recip_uniform(tmp)
1008
+ fmpq_set_mpq(fmpq_mat_entry(mat._matrix, i, col), tmp)
1009
+ elif mpz_cmp_si(denp1, 2): # denom is > 1
1010
+ for i in range(mat._nrows):
1011
+ mpq_randomize_entry(tmp, nump1, denp1)
1012
+ fmpq_set_mpq(fmpq_mat_entry(mat._matrix, i, col), tmp)
1013
+ else:
1014
+ for i in range(mat._nrows):
1015
+ mpq_randomize_entry_as_int(tmp, nump1)
1016
+ fmpq_set_mpq(fmpq_mat_entry(mat._matrix, i, col), tmp)
1017
+ mpq_clear(tmp)
1018
+ sig_off()
1019
+
1020
+ def randomize(self, density=1, num_bound=2, den_bound=2,
1021
+ distribution=None, nonzero=False, *args, **kwds):
1022
+ r"""
1023
+ Randomize the entries of ``self``.
1024
+
1025
+ Choose rational numbers according to ``distribution``, whose
1026
+ numerators are bounded by ``num_bound`` and whose denominators are
1027
+ bounded by ``den_bound``.
1028
+
1029
+ EXAMPLES::
1030
+
1031
+ sage: A = Matrix(CyclotomicField(5),2,2,range(4)) ; A
1032
+ [0 1]
1033
+ [2 3]
1034
+ sage: A.randomize()
1035
+ sage: A # random output
1036
+ [ 1/2*zeta5^2 + zeta5 1/2]
1037
+ [ -zeta5^2 + 2*zeta5 -2*zeta5^3 + 2*zeta5^2 + 2]
1038
+ """
1039
+ # Problem 1:
1040
+ # We cannot simply call the ``randomize`` code in ``matrix2.pyx`` on
1041
+ # the underlying matrix, since this is a d x (mn) matrix, where d is
1042
+ # the degree of the field extension, which leads to an overly dense
1043
+ # matrix.
1044
+ #
1045
+ # Problem 2:
1046
+ # We cannot simply copy the code from ``matrix2.pyx``, since the
1047
+ # ``random_element`` method for cyclotomic fields does not support
1048
+ # the arguments ``num_bound`` and ``den_bound``, which are support by
1049
+ # the rational field.
1050
+ #
1051
+ # Proposed solution:
1052
+ # Randomly select a proportion of ``density`` of the elements in the
1053
+ # matrix over the cyclotomic field, that is, this many columns in the
1054
+ # underlying rational matrix. Then, for each element in that column,
1055
+ # randomize it to a rational number, applying the arguments
1056
+ # ``num_bound`` and ``den_bound``.
1057
+
1058
+ density = float(density)
1059
+ if density <= 0:
1060
+ return
1061
+ if density > 1:
1062
+ density = 1
1063
+
1064
+ self.check_mutability()
1065
+ self.clear_cache()
1066
+
1067
+ cdef Py_ssize_t col, i, k, num
1068
+ cdef randstate rstate = current_randstate()
1069
+ cdef Integer B, C
1070
+ cdef bint col_is_zero
1071
+
1072
+ B = Integer(num_bound+1)
1073
+ C = Integer(den_bound+1)
1074
+
1075
+ if nonzero:
1076
+ if density >= 1:
1077
+ for col in range(self._matrix._ncols):
1078
+ col_is_zero = True
1079
+ while col_is_zero:
1080
+ self._randomize_rational_column_unsafe(col, B.value,
1081
+ C.value, distribution)
1082
+ # Check whether the new column is nonzero
1083
+ for i in range(self._degree):
1084
+ if not fmpq_is_zero(fmpq_mat_entry(self._matrix._matrix, i, col)):
1085
+ col_is_zero = False
1086
+ break
1087
+ else:
1088
+ num = int(self._nrows * self._ncols * density)
1089
+ for k in range(num):
1090
+ col = rstate.c_random() % self._matrix._ncols
1091
+ col_is_zero = True
1092
+ while col_is_zero:
1093
+ self._randomize_rational_column_unsafe(col, B.value,
1094
+ C.value, distribution)
1095
+ # Check whether the new column is nonzero
1096
+ for i in range(self._degree):
1097
+ if not fmpq_is_zero(fmpq_mat_entry(self._matrix._matrix, i, col)):
1098
+ col_is_zero = False
1099
+ break
1100
+ else:
1101
+ if density >= 1:
1102
+ for col in range(self._matrix._ncols):
1103
+ self._randomize_rational_column_unsafe(col, B.value,
1104
+ C.value, distribution)
1105
+ else:
1106
+ num = int(self._nrows * self._ncols * density)
1107
+ for k in range(num):
1108
+ col = rstate.c_random() % self._matrix._ncols
1109
+ self._randomize_rational_column_unsafe(col, B.value,
1110
+ C.value, distribution)
1111
+
1112
+ def _charpoly_bound(self):
1113
+ """
1114
+ Determine a bound for the coefficients of the characteristic
1115
+ polynomial of ``self``.
1116
+
1117
+ We use the bound in Lemma 2.2 of:
1118
+
1119
+ Dumas, J-G. "Bounds on the coefficients of characteristic
1120
+ and minimal polynomials." J. Inequal. Pure Appl. Math. 8
1121
+ (2007), no. 2.
1122
+
1123
+ This bound only applies for ``self._nrows >= 4``, so in all
1124
+ smaller cases, we just use a naive bound.
1125
+
1126
+ EXAMPLES::
1127
+
1128
+ sage: A = Matrix(CyclotomicField(7),3,3,range(9))
1129
+ sage: A._charpoly_bound()
1130
+ 2048
1131
+ sage: A.charpoly()
1132
+ x^3 - 12*x^2 - 18*x
1133
+
1134
+ An example from the above paper, where the bound is sharp::
1135
+
1136
+ sage: B = Matrix(CyclotomicField(7), 5,5, [1,1,1,1,1,1,1,-1,-1,-1,1,-1,1,-1,-1,1,-1,-1,1,-1,1,-1,-1,-1,1])
1137
+ sage: B._charpoly_bound()
1138
+ 80
1139
+ sage: B.charpoly()
1140
+ x^5 - 5*x^4 + 40*x^2 - 80*x + 48
1141
+ """
1142
+ cdef Py_ssize_t i
1143
+
1144
+ # should we even bother with this check, or just say in
1145
+ # the docstring that we assume it's square?
1146
+ if self._nrows != self._ncols:
1147
+ raise ArithmeticError("self must be a square matrix")
1148
+
1149
+ if self.is_zero():
1150
+ return 1
1151
+
1152
+ B = self.coefficient_bound()
1153
+
1154
+ # TODO: should charpoly just hardcode the return value for
1155
+ # self.nrows() < 4?
1156
+
1157
+ # this bound is only valid for n >= 4, use naive bounds
1158
+ # in other cases.
1159
+ if self._nrows <= 3:
1160
+ return max(1, 3*B, 6*B**2, 4*B**3)
1161
+
1162
+ # This is 2*e^(1-(2(7\gamma-4))/(13(3-2\gamma))), where \gamma
1163
+ # is Euler's constant.
1164
+ delta = RealNumber('5.418236')
1165
+ # This is an approximation to 1/2. :)
1166
+ half = RealNumber('0.5')
1167
+
1168
+ D = (((1+2*delta*self._nrows*(B**2)).sqrt()-1)/(delta*B**2)).ceil()
1169
+
1170
+ # TODO: we don't check anything about overflows anywhere here;
1171
+ # should we?
1172
+
1173
+ # i = 0 case
1174
+ M = ((self._nrows * B**2)**(self._nrows * half)).ceil()
1175
+
1176
+ for i from 1 <= i < D:
1177
+ val = binomial(self._nrows, i) * \
1178
+ (((self._nrows-i)*B**2)**((self._nrows-i)*half)).ceil()
1179
+ if val > M:
1180
+ M = val
1181
+
1182
+ return M
1183
+
1184
+ def charpoly(self, var='x', algorithm='multimodular', proof=None):
1185
+ r"""
1186
+ Return the characteristic polynomial of self, as a polynomial
1187
+ over the base ring.
1188
+
1189
+ INPUT:
1190
+
1191
+ - ``algorithm`` -- options:
1192
+
1193
+ - ``'multimodular'`` (default): reduce modulo primes, compute
1194
+ charpoly mod p, and lift (very fast)
1195
+ - ``'pari'``: use pari (quite slow; comparable to Magma v2.14 though)
1196
+ - ``'hessenberg'``: put matrix in Hessenberg form (double dog slow)
1197
+
1198
+ - ``proof`` -- boolean (default: ``None``); proof flag determined by
1199
+ global linalg proof
1200
+
1201
+ OUTPUT: polynomial
1202
+
1203
+ EXAMPLES::
1204
+
1205
+ sage: K.<z> = CyclotomicField(5)
1206
+ sage: a = matrix(K, 3, [1,z,1+z^2, z/3,1,2,3,z^2,1-z])
1207
+ sage: f = a.charpoly(); f
1208
+ x^3 + (z - 3)*x^2 + (-16/3*z^2 - 2*z)*x - 2/3*z^3 + 16/3*z^2 - 5*z + 5/3
1209
+ sage: f(a)
1210
+ [0 0 0]
1211
+ [0 0 0]
1212
+ [0 0 0]
1213
+ sage: a.charpoly(algorithm='pari')
1214
+ x^3 + (z - 3)*x^2 + (-16/3*z^2 - 2*z)*x - 2/3*z^3 + 16/3*z^2 - 5*z + 5/3
1215
+ sage: a.charpoly(algorithm='hessenberg')
1216
+ x^3 + (z - 3)*x^2 + (-16/3*z^2 - 2*z)*x - 2/3*z^3 + 16/3*z^2 - 5*z + 5/3
1217
+
1218
+ sage: Matrix(K, 1, [0]).charpoly()
1219
+ x
1220
+ sage: Matrix(K, 1, [5]).charpoly(var='y')
1221
+ y - 5
1222
+
1223
+ sage: Matrix(CyclotomicField(13),3).charpoly()
1224
+ x^3
1225
+ sage: Matrix(CyclotomicField(13),3).charpoly()[2].parent()
1226
+ Cyclotomic Field of order 13 and degree 12
1227
+
1228
+ TESTS::
1229
+
1230
+ sage: Matrix(CyclotomicField(10),0).charpoly()
1231
+ 1
1232
+ """
1233
+ key = 'charpoly-%s-%s' % (algorithm, proof)
1234
+ f = self.fetch(key)
1235
+ if f is not None:
1236
+ return f.change_variable_name(var)
1237
+
1238
+ if self.nrows() != self.ncols():
1239
+ raise TypeError("self must be square")
1240
+
1241
+ if self.is_zero():
1242
+ R = PolynomialRing(self.base_ring(), name=var)
1243
+ f = R.gen(0)**self.nrows()
1244
+ self.cache(key, f)
1245
+ return f
1246
+
1247
+ if self.nrows() == 1:
1248
+ R = PolynomialRing(self.base_ring(), name=var)
1249
+ f = R.gen(0) - self[0,0]
1250
+ self.cache(key, f)
1251
+ return f
1252
+
1253
+ if algorithm == 'multimodular':
1254
+ f = self._charpoly_multimodular(var, proof=proof)
1255
+ elif algorithm == 'pari':
1256
+ paripoly = self.__pari__().charpoly()
1257
+ f = self.base_ring()[var](paripoly)
1258
+ elif algorithm == 'hessenberg':
1259
+ f = self._charpoly_hessenberg(var)
1260
+ else:
1261
+ raise ValueError("unknown algorithm '%s'" % algorithm)
1262
+ self.cache(key, f)
1263
+ return f
1264
+
1265
+ def _charpoly_mod(self, p):
1266
+ """
1267
+ Return the characteristic polynomial of self*denom modulo all
1268
+ primes over `p`.
1269
+
1270
+ This is used internally by the multimodular charpoly algorithm.
1271
+
1272
+ INPUT:
1273
+
1274
+ - ``p`` -- a prime that splits completely
1275
+
1276
+ OUTPUT: matrix over GF(p) whose columns correspond to the entries
1277
+ of all the characteristic polynomials of the reduction of ``self``
1278
+ modulo all the primes over `p`
1279
+
1280
+ EXAMPLES::
1281
+
1282
+ sage: W.<z> = CyclotomicField(5)
1283
+ sage: A = matrix(W, 2, 2, [1+z, 0, 9*z+7, -3 + 4*z]); A
1284
+ [ z + 1 0]
1285
+ [9*z + 7 4*z - 3]
1286
+ sage: A._charpoly_mod(11)
1287
+ [8 2 1]
1288
+ [1 6 0]
1289
+ [4 0 0]
1290
+ [0 0 0]
1291
+ """
1292
+ tm = verbose("Computing characteristic polynomial of cyclotomic matrix modulo %s." % p)
1293
+ # Reduce self modulo all primes over p
1294
+ R, _ = self._reductions(p)
1295
+ # Compute the characteristic polynomial of each reduced matrix
1296
+ F = [A.charpoly('x') for A in R]
1297
+ # Put the characteristic polynomials together as the rows of a mod-p matrix
1298
+ k = R[0].base_ring()
1299
+ S = matrix(k, len(F), self.nrows() + 1, [f.list() for f in F])
1300
+ # multiply by inverse of reduction matrix to lift
1301
+ _, L = self._reduction_matrix(p)
1302
+ X = L * S
1303
+ # Now the columns of the matrix X define the entries of the
1304
+ # charpoly modulo p.
1305
+ verbose("Finished computing charpoly mod %s." % p, tm)
1306
+ return X
1307
+
1308
+ def _charpoly_multimodular(self, var='x', proof=None):
1309
+ """
1310
+ Compute the characteristic polynomial of ``self`` using a
1311
+ multimodular algorithm.
1312
+
1313
+ INPUT:
1314
+
1315
+ - ``proof`` -- boolean (default: global flag); if ``False``, compute
1316
+ using primes `p_i` until the lift modulo all primes up to `p_i` is
1317
+ the same as the lift modulo all primes up to `p_{i+3}` or the bound
1318
+ is reached
1319
+
1320
+ EXAMPLES::
1321
+
1322
+ sage: K.<z> = CyclotomicField(3)
1323
+ sage: A = matrix(3, [-z, 2*z + 1, 1/2*z + 2, 1, -1/2, 2*z + 2, -2*z - 2, -2*z - 2, 2*z - 1])
1324
+ sage: A._charpoly_multimodular()
1325
+ x^3 + (-z + 3/2)*x^2 + (17/2*z + 9/2)*x - 9/2*z - 23/2
1326
+ sage: A._charpoly_multimodular('T')
1327
+ T^3 + (-z + 3/2)*T^2 + (17/2*z + 9/2)*T - 9/2*z - 23/2
1328
+ sage: A._charpoly_multimodular('T', proof=False)
1329
+ T^3 + (-z + 3/2)*T^2 + (17/2*z + 9/2)*T - 9/2*z - 23/2
1330
+
1331
+ TESTS:
1332
+
1333
+ We test a degenerate case::
1334
+
1335
+ sage: A = matrix(CyclotomicField(1),2,[1,2,3,4]); A.charpoly()
1336
+ x^2 - 5*x - 2
1337
+ """
1338
+ from .matrix_cyclo_linbox import _charpoly_multimodular
1339
+ return _charpoly_multimodular(self, var, proof)
1340
+
1341
+ def _reductions(self, p):
1342
+ """
1343
+ Compute the reductions modulo all primes over p of denom*self,
1344
+ where denom is the denominator of ``self``.
1345
+
1346
+ INPUT:
1347
+
1348
+ - ``p`` -- a prime that splits completely in the base cyclotomic field
1349
+
1350
+ OUTPUT:
1351
+
1352
+ - ``list`` -- of r distinct matrices modulo p, where r is
1353
+ the degree of the cyclotomic base field
1354
+ - ``denom`` -- integer
1355
+
1356
+ EXAMPLES::
1357
+
1358
+ sage: K.<z> = CyclotomicField(3)
1359
+ sage: w = matrix(K, 2, 3, [0, -z/5, -2/3, -2*z + 2, 2*z, z])
1360
+ sage: R, d = w._reductions(7)
1361
+ sage: R[0]
1362
+ [0 2 4]
1363
+ [1 1 4]
1364
+ sage: R[1]
1365
+ [0 1 4]
1366
+ [5 4 2]
1367
+ sage: d
1368
+ 15
1369
+ """
1370
+ # Get matrix that defines the linear reduction maps modulo
1371
+ # each prime of the base ring over p.
1372
+ T, _ = self._reduction_matrix(p)
1373
+ # Clear denominator and get matrix over the integers suitable
1374
+ # for reduction.
1375
+ A, denom = self._matrix._clear_denom()
1376
+ # Actually reduce the matrix over the integers modulo the
1377
+ # prime p.
1378
+ B = A._mod_int(p)
1379
+ # Now multiply, which computes from B all the reductions of
1380
+ # self*denom modulo each of the primes over p.
1381
+ R = T * B
1382
+ # Finally compute the actual reductions by extracting them
1383
+ # from R (note that the rows of R define the reductions).
1384
+ ans = R._matrices_from_rows(self._nrows, self._ncols)
1385
+ return ans, denom
1386
+
1387
+ def _reduction_matrix(self, p):
1388
+ """
1389
+ INPUT:
1390
+
1391
+ - ``p`` -- a prime that splits completely in the base field
1392
+
1393
+ OUTPUT:
1394
+
1395
+ - Matrix over GF(p) whose action from the left gives the map from O_K
1396
+ to GF(p) x ... x GF(p) given by reducing modulo all the primes over p
1397
+ - inverse of this matrix
1398
+
1399
+ EXAMPLES::
1400
+
1401
+ sage: K.<z> = CyclotomicField(3)
1402
+ sage: w = matrix(K, 2, 3, [0, -z/5, -2/3, -2*z + 2, 2*z, z])
1403
+ sage: A, B = w._reduction_matrix(7)
1404
+ sage: A
1405
+ [1 4]
1406
+ [1 2]
1407
+ sage: B
1408
+ [6 2]
1409
+ [4 3]
1410
+
1411
+ The reduction matrix is used to calculate the reductions mod primes
1412
+ above p. ::
1413
+
1414
+ sage: K.<z> = CyclotomicField(5)
1415
+ sage: A = matrix(K, 2, 2, [1, z, z^2+1, 5*z^3]); A
1416
+ [ 1 z]
1417
+ [z^2 + 1 5*z^3]
1418
+ sage: T, S = A._reduction_matrix(11)
1419
+ sage: T * A._rational_matrix().change_ring(GF(11))
1420
+ [ 1 9 5 4]
1421
+ [ 1 5 4 9]
1422
+ [ 1 4 6 1]
1423
+ [ 1 3 10 3]
1424
+
1425
+ The rows of this product are the (flattened) matrices mod each prime above p::
1426
+
1427
+ sage: roots = [r for r, e in K.defining_polynomial().change_ring(GF(11)).roots()]; roots
1428
+ [9, 5, 4, 3]
1429
+ sage: [r^2+1 for r in roots]
1430
+ [5, 4, 6, 10]
1431
+ sage: [5*r^3 for r in roots]
1432
+ [4, 9, 1, 3]
1433
+
1434
+ The reduction matrix is cached::
1435
+
1436
+ sage: w._reduction_matrix(7) is w._reduction_matrix(7)
1437
+ True
1438
+ """
1439
+ cache = self.fetch('reduction_matrices')
1440
+ if cache is None:
1441
+ cache = {}
1442
+ self.cache('reduction_matrices', cache)
1443
+ try:
1444
+ return cache[p]
1445
+ except KeyError:
1446
+ pass
1447
+ K = self.base_ring()
1448
+ phi = K.defining_polynomial()
1449
+ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
1450
+ from sage.matrix.constructor import matrix
1451
+ F = GF(p)
1452
+ aa = [a for a, _ in phi.change_ring(F).roots()]
1453
+ n = K.degree()
1454
+ if len(aa) != n:
1455
+ raise ValueError("the prime p (=%s) must split completely but doesn't" % p)
1456
+ T = matrix(F, n)
1457
+ for i in range(n):
1458
+ a = aa[i]
1459
+ b = 1
1460
+ for j in range(n):
1461
+ T[i,j] = b
1462
+ b *= a
1463
+ T.set_immutable()
1464
+ ans = (T, T**(-1))
1465
+ cache[p] = ans
1466
+ return ans
1467
+
1468
+ def echelon_form(self, algorithm=None, height_guess=None):
1469
+ """
1470
+ Find the echelon form of ``self``, using the specified algorithm.
1471
+
1472
+ The result is cached for each algorithm separately.
1473
+
1474
+ EXAMPLES::
1475
+
1476
+ sage: W.<z> = CyclotomicField(3)
1477
+ sage: A = matrix(W, 2, 3, [1+z, 2/3, 9*z+7, -3 + 4*z, z, -7*z]); A
1478
+ [ z + 1 2/3 9*z + 7]
1479
+ [4*z - 3 z -7*z]
1480
+ sage: A.echelon_form()
1481
+ [ 1 0 -192/97*z - 361/97]
1482
+ [ 0 1 1851/97*z + 1272/97]
1483
+ sage: A.echelon_form(algorithm='classical')
1484
+ [ 1 0 -192/97*z - 361/97]
1485
+ [ 0 1 1851/97*z + 1272/97]
1486
+
1487
+ We verify that the result is cached and that the caches are separate::
1488
+
1489
+ sage: A.echelon_form() is A.echelon_form()
1490
+ True
1491
+ sage: A.echelon_form() is A.echelon_form(algorithm='classical')
1492
+ False
1493
+
1494
+ TESTS::
1495
+
1496
+ sage: W.<z> = CyclotomicField(13)
1497
+ sage: A = Matrix(W, 2,3, [10^30*(1-z)^13, 1, 2, 3, 4, z])
1498
+ sage: B = Matrix(W, 2,3, [(1-z)^13, 1, 2, 3, 4, z])
1499
+ sage: A.echelon_form() == A.echelon_form('classical') # long time (4s on sage.math, 2011)
1500
+ True
1501
+ sage: B.echelon_form() == B.echelon_form('classical')
1502
+ True
1503
+
1504
+ A degenerate case with the degree 1 cyclotomic field::
1505
+
1506
+ sage: A = matrix(CyclotomicField(1),2,3,[1,2,3,4,5,6])
1507
+ sage: A.echelon_form()
1508
+ [ 1 0 -1]
1509
+ [ 0 1 2]
1510
+
1511
+ A case that checks the bug in :issue:`3500`::
1512
+
1513
+ sage: cf4 = CyclotomicField(4) ; z4 = cf4.0
1514
+ sage: A = Matrix(cf4, 1, 2, [-z4, 1])
1515
+ sage: A.echelon_form()
1516
+ [ 1 zeta4]
1517
+
1518
+ Verify that the matrix on :issue:`10281` works::
1519
+
1520
+ sage: K.<rho> = CyclotomicField(106)
1521
+ sage: coeffs = [(18603/107*rho^51 - 11583/107*rho^50 - 19907/107*rho^49 - 13588/107*rho^48 - 8722/107*rho^47 + 2857/107*rho^46 - 19279/107*rho^45 - 16666/107*rho^44 - 11327/107*rho^43 + 3802/107*rho^42 + 18998/107*rho^41 - 10798/107*rho^40 + 16210/107*rho^39 - 13768/107*rho^38 + 15063/107*rho^37 - 14433/107*rho^36 - 19434/107*rho^35 - 12606/107*rho^34 + 3786/107*rho^33 - 17996/107*rho^32 + 12341/107*rho^31 - 15656/107*rho^30 - 19092/107*rho^29 + 8382/107*rho^28 - 18147/107*rho^27 + 14024/107*rho^26 + 18751/107*rho^25 - 8301/107*rho^24 - 20112/107*rho^23 - 14483/107*rho^22 + 4715/107*rho^21 + 20065/107*rho^20 + 15293/107*rho^19 + 10072/107*rho^18 + 4775/107*rho^17 - 953/107*rho^16 - 19782/107*rho^15 - 16020/107*rho^14 + 5633/107*rho^13 - 17618/107*rho^12 - 18187/107*rho^11 + 7492/107*rho^10 + 19165/107*rho^9 - 9988/107*rho^8 - 20042/107*rho^7 + 10109/107*rho^6 - 17677/107*rho^5 - 17723/107*rho^4 - 12489/107*rho^3 - 6321/107*rho^2 - 4082/107*rho - 1378/107, 1, 4*rho + 1), (0, 1, rho + 4)]
1522
+ sage: m = matrix(2, coeffs)
1523
+ sage: a = m.echelon_form(algorithm='classical')
1524
+ sage: b = m.echelon_form(algorithm='multimodular') # long time (5s on sage.math, 2012)
1525
+ sage: a == b # long time (depends on previous)
1526
+ True
1527
+ """
1528
+ key = 'echelon_form-%s' % algorithm
1529
+ E = self.fetch(key)
1530
+ if E is not None:
1531
+ return E
1532
+
1533
+ if self._nrows == 0:
1534
+ E = self.__copy__()
1535
+ self.cache(key, E)
1536
+ self.cache('pivots', ())
1537
+ return E
1538
+
1539
+ if algorithm is None:
1540
+ try:
1541
+ from .matrix_cyclo_linbox import _echelon_form_multimodular
1542
+ except ImportError:
1543
+ algorithm = 'classical'
1544
+ else:
1545
+ algorithm = 'multimodular'
1546
+
1547
+ if algorithm == 'multimodular':
1548
+ E = self._echelon_form_multimodular(height_guess=height_guess)
1549
+ elif algorithm == 'classical':
1550
+ E = (self*self.denominator())._echelon_classical()
1551
+ else:
1552
+ raise ValueError("unknown algorithm '%s'" % algorithm)
1553
+
1554
+ self.cache(key, E)
1555
+ return E
1556
+
1557
+ def _echelon_form_multimodular(self, num_primes=10, height_guess=None):
1558
+ """
1559
+ Use a multimodular algorithm to find the echelon form of ``self``.
1560
+
1561
+ INPUT:
1562
+
1563
+ - ``num_primes`` -- number of primes to work modulo
1564
+
1565
+ - ``height_guess`` -- guess for the height of the echelon form of self
1566
+
1567
+ OUTPUT: matrix in reduced row echelon form
1568
+
1569
+ EXAMPLES::
1570
+
1571
+ sage: W.<z> = CyclotomicField(3)
1572
+ sage: A = matrix(W, 2, 3, [1+z, 2/3, 9*z+7, -3 + 4*z, z, -7*z]); A
1573
+ [ z + 1 2/3 9*z + 7]
1574
+ [4*z - 3 z -7*z]
1575
+ sage: A._echelon_form_multimodular(10)
1576
+ [ 1 0 -192/97*z - 361/97]
1577
+ [ 0 1 1851/97*z + 1272/97]
1578
+
1579
+ TESTS:
1580
+
1581
+ We test a degenerate case::
1582
+
1583
+ sage: A = matrix(CyclotomicField(5),0); A
1584
+ []
1585
+ sage: A._echelon_form_multimodular(10)
1586
+ []
1587
+ sage: A.pivots()
1588
+ ()
1589
+
1590
+ sage: A = matrix(CyclotomicField(13), 2, 3, [5, 1, 2, 46307, 46307*4, 46307])
1591
+ sage: A._echelon_form_multimodular()
1592
+ [ 1 0 7/19]
1593
+ [ 0 1 3/19]
1594
+ """
1595
+ from .matrix_cyclo_linbox import _echelon_form_multimodular
1596
+ return _echelon_form_multimodular(self, num_primes, height_guess)
1597
+
1598
+ def _echelon_form_one_prime(self, p):
1599
+ """
1600
+ Find the echelon form of ``self`` mod the primes dividing p. Return
1601
+ the rational matrix representing this lift. If the pivots of the
1602
+ reductions mod the primes over p are different, then no such lift
1603
+ exists, and we raise a :exc:`ValueError`. If this happens, then the
1604
+ denominator of the echelon form of ``self`` is divisible by p. (Note
1605
+ that the converse need not be true.)
1606
+
1607
+ INPUT:
1608
+
1609
+ - ``p`` -- a prime that splits completely in the cyclotomic base field
1610
+
1611
+ OUTPUT: tuple of
1612
+
1613
+ - ``matrix`` -- Lift via CRT of the echelon forms of ``self`` modulo
1614
+ each of the primes over p.
1615
+ - ``tuple`` -- the tuple of pivots for the echelon form of ``self`` mod the
1616
+ primes dividing p
1617
+
1618
+ EXAMPLES::
1619
+
1620
+ sage: W.<z> = CyclotomicField(3)
1621
+ sage: A = matrix(W, 2, 3, [1+z, 2/3, 9*z+7, -3 + 4*z, z, -7*z]); A
1622
+ [ z + 1 2/3 9*z + 7]
1623
+ [4*z - 3 z -7*z]
1624
+ sage: A._echelon_form_one_prime(7)
1625
+ (
1626
+ [1 0 4 0 1 2]
1627
+ [0 0 3 0 0 4], (0, 1)
1628
+ )
1629
+ sage: Matrix(W,2,3,[2*z+3,0,1,0,1,0])._echelon_form_one_prime(7)
1630
+ Traceback (most recent call last):
1631
+ ...
1632
+ ValueError: echelon form mod 7 not defined
1633
+ """
1634
+ cdef Py_ssize_t i
1635
+
1636
+ # Initialize variables
1637
+ ls, _ = self._reductions(p)
1638
+
1639
+ # Find our first echelon form, and the associated list
1640
+ # of pivots
1641
+ ech_ls = [ls[0].echelon_form()]
1642
+ pivot_ls = ech_ls[0].pivots()
1643
+ # If we've found the identity matrix, we're all done.
1644
+ if self._nrows == self._ncols == len(pivot_ls):
1645
+ return (self.parent().identity_matrix(), range(self._nrows))
1646
+
1647
+ # For each reduction of self (i.e. for each prime of
1648
+ # self.base_ring() over p), compute the echelon form, and
1649
+ # keep track of all reductions which have the largest
1650
+ # number of pivots seen so far.
1651
+ for i from 1 <= i < len(ls):
1652
+ ech = ls[i].echelon_form()
1653
+
1654
+ # This should only occur when p divides the denominator
1655
+ # of the echelon form of self.
1656
+ if ech.pivots() != pivot_ls:
1657
+ raise ValueError("echelon form mod %s not defined" % p)
1658
+
1659
+ ech_ls.append(ech)
1660
+
1661
+ # Now, just lift back to ZZ and return it.
1662
+
1663
+ # TODO: coercion going on here
1664
+ reduction = matrix(ZZ, len(ech_ls), self._nrows * self._ncols,
1665
+ [ [y.lift() for y in E.list()] for E in ech_ls])
1666
+
1667
+ # TODO: more coercion happening here
1668
+ _, Finv = self._reduction_matrix(p)
1669
+
1670
+ lifted_matrix = Finv * reduction
1671
+
1672
+ return (lifted_matrix, pivot_ls)
1673
+
1674
+ def tensor_product(self, A, subdivide=True):
1675
+ r"""
1676
+ Return the tensor product of two matrices.
1677
+
1678
+ INPUT:
1679
+
1680
+ - ``A`` -- a matrix
1681
+ - ``subdivide`` -- boolean (default: ``True``); whether or not to return
1682
+ natural subdivisions with the matrix
1683
+
1684
+ OUTPUT:
1685
+
1686
+ Replace each element of ``self`` by a copy of ``A``, but first
1687
+ create a scalar multiple of ``A`` by the element it replaces.
1688
+ So if ``self`` is an `m\times n` matrix and ``A`` is a
1689
+ `p\times q` matrix, then the tensor product is an `mp\times nq`
1690
+ matrix. By default, the matrix will be subdivided into
1691
+ submatrices of size `p\times q`.
1692
+
1693
+ EXAMPLES::
1694
+
1695
+ sage: C = CyclotomicField(12)
1696
+ sage: M = matrix.random(C, 3, 3)
1697
+ sage: N = matrix.random(C, 50, 50)
1698
+ sage: M.tensor_product(M) == super(type(M), M).tensor_product(M)
1699
+ True
1700
+ sage: N = matrix.random(C, 15, 20)
1701
+ sage: M.tensor_product(N) == super(type(M), M).tensor_product(N)
1702
+ True
1703
+
1704
+ TESTS::
1705
+
1706
+ sage: Mp = matrix.random(C, 2,3)
1707
+ sage: Np = matrix.random(C, 4,5)
1708
+ sage: subdiv = super(type(Mp),Mp).tensor_product(Np).subdivisions()
1709
+ sage: Mp.tensor_product(Np).subdivisions() == subdiv
1710
+ True
1711
+
1712
+ Check that `m \times 0` and `0 \times m` matrices work
1713
+ (:issue:`22769`)::
1714
+
1715
+ sage: m1 = matrix(C, 1, 0, [])
1716
+ sage: m2 = matrix(C, 2, 2, [1, 2, 3, 4])
1717
+ sage: m1.tensor_product(m2).dimensions()
1718
+ (2, 0)
1719
+ sage: m2.tensor_product(m1).dimensions()
1720
+ (2, 0)
1721
+ sage: m3 = matrix(C, 0, 3, [])
1722
+ sage: m3.tensor_product(m2).dimensions()
1723
+ (0, 6)
1724
+ sage: m2.tensor_product(m3).dimensions()
1725
+ (0, 6)
1726
+ """
1727
+ if not isinstance(A, Matrix):
1728
+ raise TypeError('tensor product requires a second matrix, not {0}'.format(A))
1729
+
1730
+ if A.base_ring() is not self.base_ring():
1731
+ return super(Matrix_cyclo_dense, self).tensor_product(A, subdivide)
1732
+
1733
+ cdef Matrix_cyclo_dense M
1734
+ l = []
1735
+ R = self.base_ring()
1736
+ X = R._generator_matrix()
1737
+ d = self._degree
1738
+ MS = MatrixSpace(QQ, d, d)
1739
+ for c in self._matrix.columns():
1740
+ v = c.list()
1741
+ for n in range(d-1):
1742
+ c = c * X
1743
+ v += c.list()
1744
+ rmul = MS([v[d*i+j] for j in range(d) for i in range(d)]) # We take the transpose
1745
+ l.append(rmul * A._rational_matrix())
1746
+
1747
+ nr = self.nrows()
1748
+ nc = self.ncols()
1749
+ Anr = A.nrows()
1750
+ Anc = A.ncols()
1751
+ P = MatrixSpace(R, nr*Anr, nc*Anc)
1752
+ M = Matrix_cyclo_dense.__new__(Matrix_cyclo_dense, P,
1753
+ None, None, None)
1754
+ MS = MatrixSpace(QQ, d, P.nrows()*P.ncols())
1755
+ ret = [[l[mr*nc+mc][i,r*Anc+c] for mr in range(nr) for r in range(Anr)
1756
+ for mc in range(nc) for c in range(Anc)]
1757
+ for i in range(d)]
1758
+ M._matrix = MS(ret)
1759
+ if subdivide:
1760
+ M.subdivide([Anr*i for i in range(1,nr)], [Anc*i for i in range(1,nc)])
1761
+ return M