passagemath-modules 10.6.31rc3__cp314-cp314-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.

Potentially problematic release.


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

Files changed (807) hide show
  1. passagemath_modules-10.6.31rc3.dist-info/METADATA +281 -0
  2. passagemath_modules-10.6.31rc3.dist-info/RECORD +807 -0
  3. passagemath_modules-10.6.31rc3.dist-info/WHEEL +6 -0
  4. passagemath_modules-10.6.31rc3.dist-info/top_level.txt +2 -0
  5. passagemath_modules.libs/libgfortran-83c28eba.so.5.0.0 +0 -0
  6. passagemath_modules.libs/libgmp-6e109695.so.10.5.0 +0 -0
  7. passagemath_modules.libs/libgsl-cda90e79.so.28.0.0 +0 -0
  8. passagemath_modules.libs/libmpc-7f678fcf.so.3.3.1 +0 -0
  9. passagemath_modules.libs/libmpfr-82690d50.so.6.2.1 +0 -0
  10. passagemath_modules.libs/libopenblasp-r0-6dcb67f9.3.29.so +0 -0
  11. passagemath_modules.libs/libquadmath-2284e583.so.0.0.0 +0 -0
  12. sage/algebras/all__sagemath_modules.py +20 -0
  13. sage/algebras/catalog.py +148 -0
  14. sage/algebras/clifford_algebra.py +3107 -0
  15. sage/algebras/clifford_algebra_element.cpython-314-x86_64-linux-gnu.so +0 -0
  16. sage/algebras/clifford_algebra_element.pxd +16 -0
  17. sage/algebras/clifford_algebra_element.pyx +997 -0
  18. sage/algebras/commutative_dga.py +4252 -0
  19. sage/algebras/exterior_algebra_groebner.cpython-314-x86_64-linux-gnu.so +0 -0
  20. sage/algebras/exterior_algebra_groebner.pxd +55 -0
  21. sage/algebras/exterior_algebra_groebner.pyx +727 -0
  22. sage/algebras/finite_dimensional_algebras/all.py +2 -0
  23. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +1029 -0
  24. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.cpython-314-x86_64-linux-gnu.so +0 -0
  25. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd +12 -0
  26. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +706 -0
  27. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py +196 -0
  28. sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +255 -0
  29. sage/algebras/finite_gca.py +528 -0
  30. sage/algebras/group_algebra.py +232 -0
  31. sage/algebras/lie_algebras/abelian.py +197 -0
  32. sage/algebras/lie_algebras/affine_lie_algebra.py +1213 -0
  33. sage/algebras/lie_algebras/all.py +25 -0
  34. sage/algebras/lie_algebras/all__sagemath_modules.py +1 -0
  35. sage/algebras/lie_algebras/bch.py +177 -0
  36. sage/algebras/lie_algebras/bgg_dual_module.py +1184 -0
  37. sage/algebras/lie_algebras/bgg_resolution.py +232 -0
  38. sage/algebras/lie_algebras/center_uea.py +767 -0
  39. sage/algebras/lie_algebras/classical_lie_algebra.py +2516 -0
  40. sage/algebras/lie_algebras/examples.py +683 -0
  41. sage/algebras/lie_algebras/free_lie_algebra.py +973 -0
  42. sage/algebras/lie_algebras/heisenberg.py +820 -0
  43. sage/algebras/lie_algebras/lie_algebra.py +1562 -0
  44. sage/algebras/lie_algebras/lie_algebra_element.cpython-314-x86_64-linux-gnu.so +0 -0
  45. sage/algebras/lie_algebras/lie_algebra_element.pxd +68 -0
  46. sage/algebras/lie_algebras/lie_algebra_element.pyx +2122 -0
  47. sage/algebras/lie_algebras/morphism.py +661 -0
  48. sage/algebras/lie_algebras/nilpotent_lie_algebra.py +457 -0
  49. sage/algebras/lie_algebras/onsager.py +1324 -0
  50. sage/algebras/lie_algebras/poincare_birkhoff_witt.py +816 -0
  51. sage/algebras/lie_algebras/quotient.py +462 -0
  52. sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py +355 -0
  53. sage/algebras/lie_algebras/representation.py +1040 -0
  54. sage/algebras/lie_algebras/structure_coefficients.py +459 -0
  55. sage/algebras/lie_algebras/subalgebra.py +967 -0
  56. sage/algebras/lie_algebras/symplectic_derivation.py +289 -0
  57. sage/algebras/lie_algebras/verma_module.py +1630 -0
  58. sage/algebras/lie_algebras/virasoro.py +1186 -0
  59. sage/algebras/octonion_algebra.cpython-314-x86_64-linux-gnu.so +0 -0
  60. sage/algebras/octonion_algebra.pxd +20 -0
  61. sage/algebras/octonion_algebra.pyx +987 -0
  62. sage/algebras/orlik_solomon.py +907 -0
  63. sage/algebras/orlik_terao.py +779 -0
  64. sage/algebras/steenrod/all.py +7 -0
  65. sage/algebras/steenrod/steenrod_algebra.py +4258 -0
  66. sage/algebras/steenrod/steenrod_algebra_bases.py +1179 -0
  67. sage/algebras/steenrod/steenrod_algebra_misc.py +1167 -0
  68. sage/algebras/steenrod/steenrod_algebra_mult.py +954 -0
  69. sage/algebras/weyl_algebra.py +1126 -0
  70. sage/all__sagemath_modules.py +62 -0
  71. sage/calculus/all__sagemath_modules.py +19 -0
  72. sage/calculus/expr.py +205 -0
  73. sage/calculus/integration.cpython-314-x86_64-linux-gnu.so +0 -0
  74. sage/calculus/integration.pyx +698 -0
  75. sage/calculus/interpolation.cpython-314-x86_64-linux-gnu.so +0 -0
  76. sage/calculus/interpolation.pxd +13 -0
  77. sage/calculus/interpolation.pyx +387 -0
  78. sage/calculus/interpolators.cpython-314-x86_64-linux-gnu.so +0 -0
  79. sage/calculus/interpolators.pyx +326 -0
  80. sage/calculus/ode.cpython-314-x86_64-linux-gnu.so +0 -0
  81. sage/calculus/ode.pxd +5 -0
  82. sage/calculus/ode.pyx +610 -0
  83. sage/calculus/riemann.cpython-314-x86_64-linux-gnu.so +0 -0
  84. sage/calculus/riemann.pyx +1521 -0
  85. sage/calculus/test_sympy.py +201 -0
  86. sage/calculus/transforms/all.py +7 -0
  87. sage/calculus/transforms/dft.py +844 -0
  88. sage/calculus/transforms/dwt.cpython-314-x86_64-linux-gnu.so +0 -0
  89. sage/calculus/transforms/dwt.pxd +7 -0
  90. sage/calculus/transforms/dwt.pyx +160 -0
  91. sage/calculus/transforms/fft.cpython-314-x86_64-linux-gnu.so +0 -0
  92. sage/calculus/transforms/fft.pxd +12 -0
  93. sage/calculus/transforms/fft.pyx +487 -0
  94. sage/calculus/wester.py +662 -0
  95. sage/coding/abstract_code.py +1108 -0
  96. sage/coding/ag_code.py +868 -0
  97. sage/coding/ag_code_decoders.cpython-314-x86_64-linux-gnu.so +0 -0
  98. sage/coding/ag_code_decoders.pyx +2639 -0
  99. sage/coding/all.py +15 -0
  100. sage/coding/bch_code.py +494 -0
  101. sage/coding/binary_code.cpython-314-x86_64-linux-gnu.so +0 -0
  102. sage/coding/binary_code.pxd +124 -0
  103. sage/coding/binary_code.pyx +4139 -0
  104. sage/coding/bounds_catalog.py +43 -0
  105. sage/coding/channel.py +819 -0
  106. sage/coding/channels_catalog.py +29 -0
  107. sage/coding/code_bounds.py +755 -0
  108. sage/coding/code_constructions.py +804 -0
  109. sage/coding/codes_catalog.py +111 -0
  110. sage/coding/cyclic_code.py +1329 -0
  111. sage/coding/databases.py +316 -0
  112. sage/coding/decoder.py +373 -0
  113. sage/coding/decoders_catalog.py +88 -0
  114. sage/coding/delsarte_bounds.py +709 -0
  115. sage/coding/encoder.py +390 -0
  116. sage/coding/encoders_catalog.py +64 -0
  117. sage/coding/extended_code.py +468 -0
  118. sage/coding/gabidulin_code.py +1058 -0
  119. sage/coding/golay_code.py +404 -0
  120. sage/coding/goppa_code.py +441 -0
  121. sage/coding/grs_code.py +2371 -0
  122. sage/coding/guava.py +107 -0
  123. sage/coding/guruswami_sudan/all.py +1 -0
  124. sage/coding/guruswami_sudan/gs_decoder.py +897 -0
  125. sage/coding/guruswami_sudan/interpolation.py +409 -0
  126. sage/coding/guruswami_sudan/utils.py +176 -0
  127. sage/coding/hamming_code.py +176 -0
  128. sage/coding/information_set_decoder.py +1032 -0
  129. sage/coding/kasami_codes.cpython-314-x86_64-linux-gnu.so +0 -0
  130. sage/coding/kasami_codes.pyx +351 -0
  131. sage/coding/linear_code.py +3067 -0
  132. sage/coding/linear_code_no_metric.py +1354 -0
  133. sage/coding/linear_rank_metric.py +961 -0
  134. sage/coding/parity_check_code.py +353 -0
  135. sage/coding/punctured_code.py +719 -0
  136. sage/coding/reed_muller_code.py +999 -0
  137. sage/coding/self_dual_codes.py +942 -0
  138. sage/coding/source_coding/all.py +2 -0
  139. sage/coding/source_coding/huffman.py +553 -0
  140. sage/coding/subfield_subcode.py +423 -0
  141. sage/coding/two_weight_db.py +399 -0
  142. sage/combinat/all__sagemath_modules.py +7 -0
  143. sage/combinat/cartesian_product.py +347 -0
  144. sage/combinat/family.py +11 -0
  145. sage/combinat/free_module.py +1977 -0
  146. sage/combinat/root_system/all.py +147 -0
  147. sage/combinat/root_system/ambient_space.py +527 -0
  148. sage/combinat/root_system/associahedron.py +471 -0
  149. sage/combinat/root_system/braid_move_calculator.py +143 -0
  150. sage/combinat/root_system/braid_orbit.cpython-314-x86_64-linux-gnu.so +0 -0
  151. sage/combinat/root_system/braid_orbit.pyx +144 -0
  152. sage/combinat/root_system/branching_rules.py +2301 -0
  153. sage/combinat/root_system/cartan_matrix.py +1245 -0
  154. sage/combinat/root_system/cartan_type.py +3069 -0
  155. sage/combinat/root_system/coxeter_group.py +162 -0
  156. sage/combinat/root_system/coxeter_matrix.py +1261 -0
  157. sage/combinat/root_system/coxeter_type.py +681 -0
  158. sage/combinat/root_system/dynkin_diagram.py +900 -0
  159. sage/combinat/root_system/extended_affine_weyl_group.py +2993 -0
  160. sage/combinat/root_system/fundamental_group.py +795 -0
  161. sage/combinat/root_system/hecke_algebra_representation.py +1203 -0
  162. sage/combinat/root_system/integrable_representations.py +1227 -0
  163. sage/combinat/root_system/non_symmetric_macdonald_polynomials.py +1965 -0
  164. sage/combinat/root_system/pieri_factors.py +1147 -0
  165. sage/combinat/root_system/plot.py +1615 -0
  166. sage/combinat/root_system/root_lattice_realization_algebras.py +1214 -0
  167. sage/combinat/root_system/root_lattice_realizations.py +4628 -0
  168. sage/combinat/root_system/root_space.py +487 -0
  169. sage/combinat/root_system/root_system.py +882 -0
  170. sage/combinat/root_system/type_A.py +348 -0
  171. sage/combinat/root_system/type_A_affine.py +227 -0
  172. sage/combinat/root_system/type_A_infinity.py +241 -0
  173. sage/combinat/root_system/type_B.py +347 -0
  174. sage/combinat/root_system/type_BC_affine.py +287 -0
  175. sage/combinat/root_system/type_B_affine.py +216 -0
  176. sage/combinat/root_system/type_C.py +317 -0
  177. sage/combinat/root_system/type_C_affine.py +188 -0
  178. sage/combinat/root_system/type_D.py +357 -0
  179. sage/combinat/root_system/type_D_affine.py +208 -0
  180. sage/combinat/root_system/type_E.py +641 -0
  181. sage/combinat/root_system/type_E_affine.py +231 -0
  182. sage/combinat/root_system/type_F.py +387 -0
  183. sage/combinat/root_system/type_F_affine.py +137 -0
  184. sage/combinat/root_system/type_G.py +293 -0
  185. sage/combinat/root_system/type_G_affine.py +132 -0
  186. sage/combinat/root_system/type_H.py +105 -0
  187. sage/combinat/root_system/type_I.py +110 -0
  188. sage/combinat/root_system/type_Q.py +150 -0
  189. sage/combinat/root_system/type_affine.py +509 -0
  190. sage/combinat/root_system/type_dual.py +704 -0
  191. sage/combinat/root_system/type_folded.py +301 -0
  192. sage/combinat/root_system/type_marked.py +748 -0
  193. sage/combinat/root_system/type_reducible.py +601 -0
  194. sage/combinat/root_system/type_relabel.py +730 -0
  195. sage/combinat/root_system/type_super_A.py +837 -0
  196. sage/combinat/root_system/weight_lattice_realizations.py +1188 -0
  197. sage/combinat/root_system/weight_space.py +639 -0
  198. sage/combinat/root_system/weyl_characters.py +2238 -0
  199. sage/crypto/__init__.py +4 -0
  200. sage/crypto/all.py +28 -0
  201. sage/crypto/block_cipher/all.py +7 -0
  202. sage/crypto/block_cipher/des.py +1065 -0
  203. sage/crypto/block_cipher/miniaes.py +2171 -0
  204. sage/crypto/block_cipher/present.py +909 -0
  205. sage/crypto/block_cipher/sdes.py +1527 -0
  206. sage/crypto/boolean_function.cpython-314-x86_64-linux-gnu.so +0 -0
  207. sage/crypto/boolean_function.pxd +10 -0
  208. sage/crypto/boolean_function.pyx +1487 -0
  209. sage/crypto/cipher.py +78 -0
  210. sage/crypto/classical.py +3668 -0
  211. sage/crypto/classical_cipher.py +569 -0
  212. sage/crypto/cryptosystem.py +387 -0
  213. sage/crypto/key_exchange/all.py +7 -0
  214. sage/crypto/key_exchange/catalog.py +24 -0
  215. sage/crypto/key_exchange/diffie_hellman.py +323 -0
  216. sage/crypto/key_exchange/key_exchange_scheme.py +107 -0
  217. sage/crypto/lattice.py +312 -0
  218. sage/crypto/lfsr.py +295 -0
  219. sage/crypto/lwe.py +840 -0
  220. sage/crypto/mq/__init__.py +4 -0
  221. sage/crypto/mq/mpolynomialsystemgenerator.py +204 -0
  222. sage/crypto/mq/rijndael_gf.py +2345 -0
  223. sage/crypto/mq/sbox.py +7 -0
  224. sage/crypto/mq/sr.py +3344 -0
  225. sage/crypto/public_key/all.py +5 -0
  226. sage/crypto/public_key/blum_goldwasser.py +776 -0
  227. sage/crypto/sbox.cpython-314-x86_64-linux-gnu.so +0 -0
  228. sage/crypto/sbox.pyx +2090 -0
  229. sage/crypto/sboxes.py +2090 -0
  230. sage/crypto/stream.py +390 -0
  231. sage/crypto/stream_cipher.py +297 -0
  232. sage/crypto/util.py +519 -0
  233. sage/ext/all__sagemath_modules.py +1 -0
  234. sage/ext/interpreters/__init__.py +1 -0
  235. sage/ext/interpreters/all__sagemath_modules.py +2 -0
  236. sage/ext/interpreters/wrapper_cc.cpython-314-x86_64-linux-gnu.so +0 -0
  237. sage/ext/interpreters/wrapper_cc.pxd +30 -0
  238. sage/ext/interpreters/wrapper_cc.pyx +252 -0
  239. sage/ext/interpreters/wrapper_cdf.cpython-314-x86_64-linux-gnu.so +0 -0
  240. sage/ext/interpreters/wrapper_cdf.pxd +26 -0
  241. sage/ext/interpreters/wrapper_cdf.pyx +245 -0
  242. sage/ext/interpreters/wrapper_rdf.cpython-314-x86_64-linux-gnu.so +0 -0
  243. sage/ext/interpreters/wrapper_rdf.pxd +23 -0
  244. sage/ext/interpreters/wrapper_rdf.pyx +221 -0
  245. sage/ext/interpreters/wrapper_rr.cpython-314-x86_64-linux-gnu.so +0 -0
  246. sage/ext/interpreters/wrapper_rr.pxd +28 -0
  247. sage/ext/interpreters/wrapper_rr.pyx +335 -0
  248. sage/geometry/all__sagemath_modules.py +5 -0
  249. sage/geometry/toric_lattice.py +1745 -0
  250. sage/geometry/toric_lattice_element.cpython-314-x86_64-linux-gnu.so +0 -0
  251. sage/geometry/toric_lattice_element.pyx +432 -0
  252. sage/groups/abelian_gps/abelian_group.py +1925 -0
  253. sage/groups/abelian_gps/abelian_group_element.py +164 -0
  254. sage/groups/abelian_gps/all__sagemath_modules.py +5 -0
  255. sage/groups/abelian_gps/dual_abelian_group.py +421 -0
  256. sage/groups/abelian_gps/dual_abelian_group_element.py +179 -0
  257. sage/groups/abelian_gps/element_base.py +341 -0
  258. sage/groups/abelian_gps/values.py +488 -0
  259. sage/groups/additive_abelian/additive_abelian_group.py +476 -0
  260. sage/groups/additive_abelian/additive_abelian_wrapper.py +857 -0
  261. sage/groups/additive_abelian/all.py +4 -0
  262. sage/groups/additive_abelian/qmodnz.py +231 -0
  263. sage/groups/additive_abelian/qmodnz_element.py +349 -0
  264. sage/groups/affine_gps/affine_group.py +535 -0
  265. sage/groups/affine_gps/all.py +1 -0
  266. sage/groups/affine_gps/catalog.py +17 -0
  267. sage/groups/affine_gps/euclidean_group.py +246 -0
  268. sage/groups/affine_gps/group_element.py +562 -0
  269. sage/groups/all__sagemath_modules.py +12 -0
  270. sage/groups/galois_group.py +479 -0
  271. sage/groups/matrix_gps/all.py +4 -0
  272. sage/groups/matrix_gps/all__sagemath_modules.py +13 -0
  273. sage/groups/matrix_gps/catalog.py +26 -0
  274. sage/groups/matrix_gps/coxeter_group.py +927 -0
  275. sage/groups/matrix_gps/finitely_generated.py +487 -0
  276. sage/groups/matrix_gps/group_element.cpython-314-x86_64-linux-gnu.so +0 -0
  277. sage/groups/matrix_gps/group_element.pxd +11 -0
  278. sage/groups/matrix_gps/group_element.pyx +431 -0
  279. sage/groups/matrix_gps/linear.py +440 -0
  280. sage/groups/matrix_gps/matrix_group.py +617 -0
  281. sage/groups/matrix_gps/named_group.py +296 -0
  282. sage/groups/matrix_gps/orthogonal.py +544 -0
  283. sage/groups/matrix_gps/symplectic.py +251 -0
  284. sage/groups/matrix_gps/unitary.py +436 -0
  285. sage/groups/misc_gps/all__sagemath_modules.py +1 -0
  286. sage/groups/misc_gps/argument_groups.py +1905 -0
  287. sage/groups/misc_gps/imaginary_groups.py +479 -0
  288. sage/groups/perm_gps/all__sagemath_modules.py +1 -0
  289. sage/groups/perm_gps/partn_ref/all__sagemath_modules.py +1 -0
  290. sage/groups/perm_gps/partn_ref/refinement_binary.cpython-314-x86_64-linux-gnu.so +0 -0
  291. sage/groups/perm_gps/partn_ref/refinement_binary.pxd +41 -0
  292. sage/groups/perm_gps/partn_ref/refinement_binary.pyx +1167 -0
  293. sage/groups/perm_gps/partn_ref/refinement_matrices.cpython-314-x86_64-linux-gnu.so +0 -0
  294. sage/groups/perm_gps/partn_ref/refinement_matrices.pxd +31 -0
  295. sage/groups/perm_gps/partn_ref/refinement_matrices.pyx +385 -0
  296. sage/homology/algebraic_topological_model.py +595 -0
  297. sage/homology/all.py +2 -0
  298. sage/homology/all__sagemath_modules.py +8 -0
  299. sage/homology/chain_complex.py +2148 -0
  300. sage/homology/chain_complex_homspace.py +165 -0
  301. sage/homology/chain_complex_morphism.py +629 -0
  302. sage/homology/chain_homotopy.py +604 -0
  303. sage/homology/chains.py +653 -0
  304. sage/homology/free_resolution.py +923 -0
  305. sage/homology/graded_resolution.py +567 -0
  306. sage/homology/hochschild_complex.py +756 -0
  307. sage/homology/homology_group.py +188 -0
  308. sage/homology/homology_morphism.py +422 -0
  309. sage/homology/homology_vector_space_with_basis.py +1454 -0
  310. sage/homology/koszul_complex.py +169 -0
  311. sage/homology/matrix_utils.py +205 -0
  312. sage/libs/all__sagemath_modules.py +1 -0
  313. sage/libs/gsl/__init__.py +1 -0
  314. sage/libs/gsl/airy.pxd +56 -0
  315. sage/libs/gsl/all.pxd +66 -0
  316. sage/libs/gsl/array.cpython-314-x86_64-linux-gnu.so +0 -0
  317. sage/libs/gsl/array.pxd +5 -0
  318. sage/libs/gsl/array.pyx +102 -0
  319. sage/libs/gsl/bessel.pxd +208 -0
  320. sage/libs/gsl/blas.pxd +116 -0
  321. sage/libs/gsl/blas_types.pxd +34 -0
  322. sage/libs/gsl/block.pxd +52 -0
  323. sage/libs/gsl/chebyshev.pxd +37 -0
  324. sage/libs/gsl/clausen.pxd +12 -0
  325. sage/libs/gsl/combination.pxd +47 -0
  326. sage/libs/gsl/complex.pxd +151 -0
  327. sage/libs/gsl/coulomb.pxd +30 -0
  328. sage/libs/gsl/coupling.pxd +21 -0
  329. sage/libs/gsl/dawson.pxd +12 -0
  330. sage/libs/gsl/debye.pxd +24 -0
  331. sage/libs/gsl/dilog.pxd +14 -0
  332. sage/libs/gsl/eigen.pxd +46 -0
  333. sage/libs/gsl/elementary.pxd +12 -0
  334. sage/libs/gsl/ellint.pxd +48 -0
  335. sage/libs/gsl/elljac.pxd +8 -0
  336. sage/libs/gsl/erf.pxd +32 -0
  337. sage/libs/gsl/errno.pxd +26 -0
  338. sage/libs/gsl/exp.pxd +44 -0
  339. sage/libs/gsl/expint.pxd +44 -0
  340. sage/libs/gsl/fermi_dirac.pxd +44 -0
  341. sage/libs/gsl/fft.pxd +121 -0
  342. sage/libs/gsl/fit.pxd +50 -0
  343. sage/libs/gsl/gamma.pxd +94 -0
  344. sage/libs/gsl/gegenbauer.pxd +26 -0
  345. sage/libs/gsl/histogram.pxd +176 -0
  346. sage/libs/gsl/hyperg.pxd +52 -0
  347. sage/libs/gsl/integration.pxd +69 -0
  348. sage/libs/gsl/interp.pxd +109 -0
  349. sage/libs/gsl/laguerre.pxd +24 -0
  350. sage/libs/gsl/lambert.pxd +16 -0
  351. sage/libs/gsl/legendre.pxd +90 -0
  352. sage/libs/gsl/linalg.pxd +185 -0
  353. sage/libs/gsl/log.pxd +26 -0
  354. sage/libs/gsl/math.pxd +43 -0
  355. sage/libs/gsl/matrix.pxd +143 -0
  356. sage/libs/gsl/matrix_complex.pxd +130 -0
  357. sage/libs/gsl/min.pxd +67 -0
  358. sage/libs/gsl/monte.pxd +56 -0
  359. sage/libs/gsl/ntuple.pxd +32 -0
  360. sage/libs/gsl/odeiv.pxd +70 -0
  361. sage/libs/gsl/permutation.pxd +78 -0
  362. sage/libs/gsl/poly.pxd +40 -0
  363. sage/libs/gsl/pow_int.pxd +12 -0
  364. sage/libs/gsl/psi.pxd +28 -0
  365. sage/libs/gsl/qrng.pxd +29 -0
  366. sage/libs/gsl/random.pxd +257 -0
  367. sage/libs/gsl/rng.pxd +100 -0
  368. sage/libs/gsl/roots.pxd +72 -0
  369. sage/libs/gsl/sort.pxd +36 -0
  370. sage/libs/gsl/statistics.pxd +59 -0
  371. sage/libs/gsl/sum.pxd +55 -0
  372. sage/libs/gsl/synchrotron.pxd +16 -0
  373. sage/libs/gsl/transport.pxd +24 -0
  374. sage/libs/gsl/trig.pxd +58 -0
  375. sage/libs/gsl/types.pxd +137 -0
  376. sage/libs/gsl/vector.pxd +101 -0
  377. sage/libs/gsl/vector_complex.pxd +83 -0
  378. sage/libs/gsl/wavelet.pxd +49 -0
  379. sage/libs/gsl/zeta.pxd +28 -0
  380. sage/libs/mpc/__init__.pxd +114 -0
  381. sage/libs/mpc/types.pxd +28 -0
  382. sage/libs/mpfr/__init__.pxd +299 -0
  383. sage/libs/mpfr/types.pxd +26 -0
  384. sage/libs/mpmath/__init__.py +1 -0
  385. sage/libs/mpmath/all.py +27 -0
  386. sage/libs/mpmath/all__sagemath_modules.py +1 -0
  387. sage/libs/mpmath/utils.cpython-314-x86_64-linux-gnu.so +0 -0
  388. sage/libs/mpmath/utils.pxd +4 -0
  389. sage/libs/mpmath/utils.pyx +319 -0
  390. sage/matrix/action.cpython-314-x86_64-linux-gnu.so +0 -0
  391. sage/matrix/action.pxd +26 -0
  392. sage/matrix/action.pyx +596 -0
  393. sage/matrix/all.py +9 -0
  394. sage/matrix/args.cpython-314-x86_64-linux-gnu.so +0 -0
  395. sage/matrix/args.pxd +144 -0
  396. sage/matrix/args.pyx +1668 -0
  397. sage/matrix/benchmark.py +1258 -0
  398. sage/matrix/berlekamp_massey.py +95 -0
  399. sage/matrix/compute_J_ideal.py +926 -0
  400. sage/matrix/constructor.cpython-314-x86_64-linux-gnu.so +0 -0
  401. sage/matrix/constructor.pyx +750 -0
  402. sage/matrix/docs.py +430 -0
  403. sage/matrix/echelon_matrix.cpython-314-x86_64-linux-gnu.so +0 -0
  404. sage/matrix/echelon_matrix.pyx +155 -0
  405. sage/matrix/matrix.pxd +2 -0
  406. sage/matrix/matrix0.cpython-314-x86_64-linux-gnu.so +0 -0
  407. sage/matrix/matrix0.pxd +68 -0
  408. sage/matrix/matrix0.pyx +6324 -0
  409. sage/matrix/matrix1.cpython-314-x86_64-linux-gnu.so +0 -0
  410. sage/matrix/matrix1.pxd +8 -0
  411. sage/matrix/matrix1.pyx +2851 -0
  412. sage/matrix/matrix2.cpython-314-x86_64-linux-gnu.so +0 -0
  413. sage/matrix/matrix2.pxd +25 -0
  414. sage/matrix/matrix2.pyx +20181 -0
  415. sage/matrix/matrix_cdv.cpython-314-x86_64-linux-gnu.so +0 -0
  416. sage/matrix/matrix_cdv.pxd +4 -0
  417. sage/matrix/matrix_cdv.pyx +93 -0
  418. sage/matrix/matrix_complex_double_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  419. sage/matrix/matrix_complex_double_dense.pxd +5 -0
  420. sage/matrix/matrix_complex_double_dense.pyx +98 -0
  421. sage/matrix/matrix_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  422. sage/matrix/matrix_dense.pxd +5 -0
  423. sage/matrix/matrix_dense.pyx +343 -0
  424. sage/matrix/matrix_domain_dense.pxd +5 -0
  425. sage/matrix/matrix_domain_sparse.pxd +5 -0
  426. sage/matrix/matrix_double_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  427. sage/matrix/matrix_double_dense.pxd +7 -0
  428. sage/matrix/matrix_double_dense.pyx +3906 -0
  429. sage/matrix/matrix_double_sparse.cpython-314-x86_64-linux-gnu.so +0 -0
  430. sage/matrix/matrix_double_sparse.pxd +6 -0
  431. sage/matrix/matrix_double_sparse.pyx +248 -0
  432. sage/matrix/matrix_generic_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  433. sage/matrix/matrix_generic_dense.pxd +7 -0
  434. sage/matrix/matrix_generic_dense.pyx +354 -0
  435. sage/matrix/matrix_generic_sparse.cpython-314-x86_64-linux-gnu.so +0 -0
  436. sage/matrix/matrix_generic_sparse.pxd +7 -0
  437. sage/matrix/matrix_generic_sparse.pyx +461 -0
  438. sage/matrix/matrix_laurent_mpolynomial_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  439. sage/matrix/matrix_laurent_mpolynomial_dense.pxd +5 -0
  440. sage/matrix/matrix_laurent_mpolynomial_dense.pyx +115 -0
  441. sage/matrix/matrix_misc.py +313 -0
  442. sage/matrix/matrix_numpy_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  443. sage/matrix/matrix_numpy_dense.pxd +14 -0
  444. sage/matrix/matrix_numpy_dense.pyx +450 -0
  445. sage/matrix/matrix_numpy_integer_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  446. sage/matrix/matrix_numpy_integer_dense.pxd +7 -0
  447. sage/matrix/matrix_numpy_integer_dense.pyx +59 -0
  448. sage/matrix/matrix_polynomial_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  449. sage/matrix/matrix_polynomial_dense.pxd +5 -0
  450. sage/matrix/matrix_polynomial_dense.pyx +5341 -0
  451. sage/matrix/matrix_real_double_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  452. sage/matrix/matrix_real_double_dense.pxd +7 -0
  453. sage/matrix/matrix_real_double_dense.pyx +122 -0
  454. sage/matrix/matrix_space.py +2848 -0
  455. sage/matrix/matrix_sparse.cpython-314-x86_64-linux-gnu.so +0 -0
  456. sage/matrix/matrix_sparse.pxd +5 -0
  457. sage/matrix/matrix_sparse.pyx +1222 -0
  458. sage/matrix/matrix_window.cpython-314-x86_64-linux-gnu.so +0 -0
  459. sage/matrix/matrix_window.pxd +37 -0
  460. sage/matrix/matrix_window.pyx +242 -0
  461. sage/matrix/misc_mpfr.cpython-314-x86_64-linux-gnu.so +0 -0
  462. sage/matrix/misc_mpfr.pyx +80 -0
  463. sage/matrix/operation_table.py +1182 -0
  464. sage/matrix/special.py +3666 -0
  465. sage/matrix/strassen.cpython-314-x86_64-linux-gnu.so +0 -0
  466. sage/matrix/strassen.pyx +851 -0
  467. sage/matrix/symplectic_basis.py +541 -0
  468. sage/matrix/template.pxd +6 -0
  469. sage/matrix/tests.py +71 -0
  470. sage/matroids/advanced.py +77 -0
  471. sage/matroids/all.py +13 -0
  472. sage/matroids/basis_exchange_matroid.cpython-314-x86_64-linux-gnu.so +0 -0
  473. sage/matroids/basis_exchange_matroid.pxd +96 -0
  474. sage/matroids/basis_exchange_matroid.pyx +2344 -0
  475. sage/matroids/basis_matroid.cpython-314-x86_64-linux-gnu.so +0 -0
  476. sage/matroids/basis_matroid.pxd +45 -0
  477. sage/matroids/basis_matroid.pyx +1217 -0
  478. sage/matroids/catalog.py +44 -0
  479. sage/matroids/chow_ring.py +473 -0
  480. sage/matroids/chow_ring_ideal.py +849 -0
  481. sage/matroids/circuit_closures_matroid.cpython-314-x86_64-linux-gnu.so +0 -0
  482. sage/matroids/circuit_closures_matroid.pxd +16 -0
  483. sage/matroids/circuit_closures_matroid.pyx +559 -0
  484. sage/matroids/circuits_matroid.cpython-314-x86_64-linux-gnu.so +0 -0
  485. sage/matroids/circuits_matroid.pxd +38 -0
  486. sage/matroids/circuits_matroid.pyx +947 -0
  487. sage/matroids/constructor.py +1086 -0
  488. sage/matroids/database_collections.py +365 -0
  489. sage/matroids/database_matroids.py +5338 -0
  490. sage/matroids/dual_matroid.py +583 -0
  491. sage/matroids/extension.cpython-314-x86_64-linux-gnu.so +0 -0
  492. sage/matroids/extension.pxd +34 -0
  493. sage/matroids/extension.pyx +519 -0
  494. sage/matroids/flats_matroid.cpython-314-x86_64-linux-gnu.so +0 -0
  495. sage/matroids/flats_matroid.pxd +28 -0
  496. sage/matroids/flats_matroid.pyx +715 -0
  497. sage/matroids/gammoid.py +600 -0
  498. sage/matroids/graphic_matroid.cpython-314-x86_64-linux-gnu.so +0 -0
  499. sage/matroids/graphic_matroid.pxd +39 -0
  500. sage/matroids/graphic_matroid.pyx +2024 -0
  501. sage/matroids/lean_matrix.cpython-314-x86_64-linux-gnu.so +0 -0
  502. sage/matroids/lean_matrix.pxd +126 -0
  503. sage/matroids/lean_matrix.pyx +3667 -0
  504. sage/matroids/linear_matroid.cpython-314-x86_64-linux-gnu.so +0 -0
  505. sage/matroids/linear_matroid.pxd +180 -0
  506. sage/matroids/linear_matroid.pyx +6649 -0
  507. sage/matroids/matroid.cpython-314-x86_64-linux-gnu.so +0 -0
  508. sage/matroids/matroid.pxd +243 -0
  509. sage/matroids/matroid.pyx +8759 -0
  510. sage/matroids/matroids_catalog.py +190 -0
  511. sage/matroids/matroids_plot_helpers.py +890 -0
  512. sage/matroids/minor_matroid.py +480 -0
  513. sage/matroids/minorfix.h +9 -0
  514. sage/matroids/named_matroids.py +5 -0
  515. sage/matroids/rank_matroid.py +268 -0
  516. sage/matroids/set_system.cpython-314-x86_64-linux-gnu.so +0 -0
  517. sage/matroids/set_system.pxd +38 -0
  518. sage/matroids/set_system.pyx +800 -0
  519. sage/matroids/transversal_matroid.cpython-314-x86_64-linux-gnu.so +0 -0
  520. sage/matroids/transversal_matroid.pxd +14 -0
  521. sage/matroids/transversal_matroid.pyx +893 -0
  522. sage/matroids/union_matroid.cpython-314-x86_64-linux-gnu.so +0 -0
  523. sage/matroids/union_matroid.pxd +20 -0
  524. sage/matroids/union_matroid.pyx +331 -0
  525. sage/matroids/unpickling.cpython-314-x86_64-linux-gnu.so +0 -0
  526. sage/matroids/unpickling.pyx +843 -0
  527. sage/matroids/utilities.py +809 -0
  528. sage/misc/all__sagemath_modules.py +20 -0
  529. sage/misc/c3.cpython-314-x86_64-linux-gnu.so +0 -0
  530. sage/misc/c3.pyx +238 -0
  531. sage/misc/compat.py +87 -0
  532. sage/misc/element_with_label.py +173 -0
  533. sage/misc/func_persist.py +79 -0
  534. sage/misc/pickle_old.cpython-314-x86_64-linux-gnu.so +0 -0
  535. sage/misc/pickle_old.pyx +19 -0
  536. sage/misc/proof.py +7 -0
  537. sage/misc/replace_dot_all.py +472 -0
  538. sage/misc/sagedoc_conf.py +168 -0
  539. sage/misc/sphinxify.py +167 -0
  540. sage/misc/test_class_pickling.py +85 -0
  541. sage/modules/all.py +42 -0
  542. sage/modules/complex_double_vector.py +25 -0
  543. sage/modules/diamond_cutting.py +380 -0
  544. sage/modules/fg_pid/all.py +1 -0
  545. sage/modules/fg_pid/fgp_element.py +456 -0
  546. sage/modules/fg_pid/fgp_module.py +2091 -0
  547. sage/modules/fg_pid/fgp_morphism.py +550 -0
  548. sage/modules/filtered_vector_space.py +1271 -0
  549. sage/modules/finite_submodule_iter.cpython-314-x86_64-linux-gnu.so +0 -0
  550. sage/modules/finite_submodule_iter.pxd +27 -0
  551. sage/modules/finite_submodule_iter.pyx +452 -0
  552. sage/modules/fp_graded/all.py +1 -0
  553. sage/modules/fp_graded/element.py +346 -0
  554. sage/modules/fp_graded/free_element.py +298 -0
  555. sage/modules/fp_graded/free_homspace.py +53 -0
  556. sage/modules/fp_graded/free_module.py +1060 -0
  557. sage/modules/fp_graded/free_morphism.py +217 -0
  558. sage/modules/fp_graded/homspace.py +563 -0
  559. sage/modules/fp_graded/module.py +1340 -0
  560. sage/modules/fp_graded/morphism.py +1990 -0
  561. sage/modules/fp_graded/steenrod/all.py +1 -0
  562. sage/modules/fp_graded/steenrod/homspace.py +65 -0
  563. sage/modules/fp_graded/steenrod/module.py +477 -0
  564. sage/modules/fp_graded/steenrod/morphism.py +404 -0
  565. sage/modules/fp_graded/steenrod/profile.py +241 -0
  566. sage/modules/free_module.py +8447 -0
  567. sage/modules/free_module_element.cpython-314-x86_64-linux-gnu.so +0 -0
  568. sage/modules/free_module_element.pxd +22 -0
  569. sage/modules/free_module_element.pyx +5445 -0
  570. sage/modules/free_module_homspace.py +369 -0
  571. sage/modules/free_module_integer.py +896 -0
  572. sage/modules/free_module_morphism.py +823 -0
  573. sage/modules/free_module_pseudohomspace.py +352 -0
  574. sage/modules/free_module_pseudomorphism.py +578 -0
  575. sage/modules/free_quadratic_module.py +1706 -0
  576. sage/modules/free_quadratic_module_integer_symmetric.py +1790 -0
  577. sage/modules/matrix_morphism.py +1745 -0
  578. sage/modules/misc.py +103 -0
  579. sage/modules/module_functors.py +192 -0
  580. sage/modules/multi_filtered_vector_space.py +719 -0
  581. sage/modules/ore_module.py +2208 -0
  582. sage/modules/ore_module_element.py +178 -0
  583. sage/modules/ore_module_homspace.py +147 -0
  584. sage/modules/ore_module_morphism.py +968 -0
  585. sage/modules/quotient_module.py +699 -0
  586. sage/modules/real_double_vector.py +22 -0
  587. sage/modules/submodule.py +255 -0
  588. sage/modules/tensor_operations.py +567 -0
  589. sage/modules/torsion_quadratic_module.py +1352 -0
  590. sage/modules/tutorial_free_modules.py +248 -0
  591. sage/modules/vector_complex_double_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  592. sage/modules/vector_complex_double_dense.pxd +6 -0
  593. sage/modules/vector_complex_double_dense.pyx +117 -0
  594. sage/modules/vector_double_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  595. sage/modules/vector_double_dense.pxd +6 -0
  596. sage/modules/vector_double_dense.pyx +604 -0
  597. sage/modules/vector_integer_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  598. sage/modules/vector_integer_dense.pxd +15 -0
  599. sage/modules/vector_integer_dense.pyx +361 -0
  600. sage/modules/vector_integer_sparse.cpython-314-x86_64-linux-gnu.so +0 -0
  601. sage/modules/vector_integer_sparse.pxd +29 -0
  602. sage/modules/vector_integer_sparse.pyx +406 -0
  603. sage/modules/vector_modn_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  604. sage/modules/vector_modn_dense.pxd +12 -0
  605. sage/modules/vector_modn_dense.pyx +394 -0
  606. sage/modules/vector_modn_sparse.cpython-314-x86_64-linux-gnu.so +0 -0
  607. sage/modules/vector_modn_sparse.pxd +21 -0
  608. sage/modules/vector_modn_sparse.pyx +298 -0
  609. sage/modules/vector_numpy_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  610. sage/modules/vector_numpy_dense.pxd +15 -0
  611. sage/modules/vector_numpy_dense.pyx +304 -0
  612. sage/modules/vector_numpy_integer_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  613. sage/modules/vector_numpy_integer_dense.pxd +7 -0
  614. sage/modules/vector_numpy_integer_dense.pyx +54 -0
  615. sage/modules/vector_rational_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  616. sage/modules/vector_rational_dense.pxd +15 -0
  617. sage/modules/vector_rational_dense.pyx +387 -0
  618. sage/modules/vector_rational_sparse.cpython-314-x86_64-linux-gnu.so +0 -0
  619. sage/modules/vector_rational_sparse.pxd +30 -0
  620. sage/modules/vector_rational_sparse.pyx +413 -0
  621. sage/modules/vector_real_double_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  622. sage/modules/vector_real_double_dense.pxd +6 -0
  623. sage/modules/vector_real_double_dense.pyx +126 -0
  624. sage/modules/vector_space_homspace.py +430 -0
  625. sage/modules/vector_space_morphism.py +989 -0
  626. sage/modules/with_basis/all.py +15 -0
  627. sage/modules/with_basis/cell_module.py +494 -0
  628. sage/modules/with_basis/indexed_element.cpython-314-x86_64-linux-gnu.so +0 -0
  629. sage/modules/with_basis/indexed_element.pxd +13 -0
  630. sage/modules/with_basis/indexed_element.pyx +1058 -0
  631. sage/modules/with_basis/invariant.py +1075 -0
  632. sage/modules/with_basis/morphism.py +1636 -0
  633. sage/modules/with_basis/representation.py +2939 -0
  634. sage/modules/with_basis/subquotient.py +685 -0
  635. sage/numerical/all__sagemath_modules.py +6 -0
  636. sage/numerical/gauss_legendre.cpython-314-x86_64-linux-gnu.so +0 -0
  637. sage/numerical/gauss_legendre.pyx +381 -0
  638. sage/numerical/optimize.py +910 -0
  639. sage/probability/all.py +10 -0
  640. sage/probability/probability_distribution.cpython-314-x86_64-linux-gnu.so +0 -0
  641. sage/probability/probability_distribution.pyx +1242 -0
  642. sage/probability/random_variable.py +411 -0
  643. sage/quadratic_forms/all.py +4 -0
  644. sage/quadratic_forms/all__sagemath_modules.py +15 -0
  645. sage/quadratic_forms/binary_qf.py +2042 -0
  646. sage/quadratic_forms/bqf_class_group.py +748 -0
  647. sage/quadratic_forms/constructions.py +93 -0
  648. sage/quadratic_forms/count_local_2.cpython-314-x86_64-linux-gnu.so +0 -0
  649. sage/quadratic_forms/count_local_2.pyx +365 -0
  650. sage/quadratic_forms/extras.py +195 -0
  651. sage/quadratic_forms/quadratic_form.py +1753 -0
  652. sage/quadratic_forms/quadratic_form__count_local_2.py +221 -0
  653. sage/quadratic_forms/quadratic_form__equivalence_testing.py +708 -0
  654. sage/quadratic_forms/quadratic_form__evaluate.cpython-314-x86_64-linux-gnu.so +0 -0
  655. sage/quadratic_forms/quadratic_form__evaluate.pyx +139 -0
  656. sage/quadratic_forms/quadratic_form__local_density_congruence.py +977 -0
  657. sage/quadratic_forms/quadratic_form__local_field_invariants.py +1072 -0
  658. sage/quadratic_forms/quadratic_form__neighbors.py +424 -0
  659. sage/quadratic_forms/quadratic_form__reduction_theory.py +488 -0
  660. sage/quadratic_forms/quadratic_form__split_local_covering.py +416 -0
  661. sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +657 -0
  662. sage/quadratic_forms/quadratic_form__theta.py +352 -0
  663. sage/quadratic_forms/quadratic_form__variable_substitutions.py +370 -0
  664. sage/quadratic_forms/random_quadraticform.py +209 -0
  665. sage/quadratic_forms/ternary.cpython-314-x86_64-linux-gnu.so +0 -0
  666. sage/quadratic_forms/ternary.pyx +1154 -0
  667. sage/quadratic_forms/ternary_qf.py +2027 -0
  668. sage/rings/all__sagemath_modules.py +28 -0
  669. sage/rings/asymptotic/all__sagemath_modules.py +1 -0
  670. sage/rings/asymptotic/misc.py +1252 -0
  671. sage/rings/cc.py +4 -0
  672. sage/rings/cfinite_sequence.py +1306 -0
  673. sage/rings/complex_conversion.cpython-314-x86_64-linux-gnu.so +0 -0
  674. sage/rings/complex_conversion.pxd +8 -0
  675. sage/rings/complex_conversion.pyx +23 -0
  676. sage/rings/complex_double.cpython-314-x86_64-linux-gnu.so +0 -0
  677. sage/rings/complex_double.pxd +21 -0
  678. sage/rings/complex_double.pyx +2654 -0
  679. sage/rings/complex_mpc.cpython-314-x86_64-linux-gnu.so +0 -0
  680. sage/rings/complex_mpc.pxd +21 -0
  681. sage/rings/complex_mpc.pyx +2576 -0
  682. sage/rings/complex_mpfr.cpython-314-x86_64-linux-gnu.so +0 -0
  683. sage/rings/complex_mpfr.pxd +18 -0
  684. sage/rings/complex_mpfr.pyx +3602 -0
  685. sage/rings/derivation.py +2334 -0
  686. sage/rings/finite_rings/all__sagemath_modules.py +1 -0
  687. sage/rings/finite_rings/maps_finite_field.py +191 -0
  688. sage/rings/function_field/all__sagemath_modules.py +8 -0
  689. sage/rings/function_field/derivations.py +102 -0
  690. sage/rings/function_field/derivations_rational.py +132 -0
  691. sage/rings/function_field/differential.py +853 -0
  692. sage/rings/function_field/divisor.py +1107 -0
  693. sage/rings/function_field/drinfeld_modules/action.py +199 -0
  694. sage/rings/function_field/drinfeld_modules/all.py +1 -0
  695. sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py +673 -0
  696. sage/rings/function_field/drinfeld_modules/drinfeld_module.py +2087 -0
  697. sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +1131 -0
  698. sage/rings/function_field/drinfeld_modules/homset.py +420 -0
  699. sage/rings/function_field/drinfeld_modules/morphism.py +820 -0
  700. sage/rings/function_field/hermite_form_polynomial.cpython-314-x86_64-linux-gnu.so +0 -0
  701. sage/rings/function_field/hermite_form_polynomial.pyx +188 -0
  702. sage/rings/function_field/khuri_makdisi.cpython-314-x86_64-linux-gnu.so +0 -0
  703. sage/rings/function_field/khuri_makdisi.pyx +935 -0
  704. sage/rings/invariants/all.py +4 -0
  705. sage/rings/invariants/invariant_theory.py +4597 -0
  706. sage/rings/invariants/reconstruction.py +395 -0
  707. sage/rings/polynomial/all__sagemath_modules.py +17 -0
  708. sage/rings/polynomial/integer_valued_polynomials.py +1230 -0
  709. sage/rings/polynomial/laurent_polynomial_mpair.cpython-314-x86_64-linux-gnu.so +0 -0
  710. sage/rings/polynomial/laurent_polynomial_mpair.pxd +15 -0
  711. sage/rings/polynomial/laurent_polynomial_mpair.pyx +2023 -0
  712. sage/rings/polynomial/ore_function_element.py +952 -0
  713. sage/rings/polynomial/ore_function_field.py +1028 -0
  714. sage/rings/polynomial/ore_polynomial_element.cpython-314-x86_64-linux-gnu.so +0 -0
  715. sage/rings/polynomial/ore_polynomial_element.pxd +48 -0
  716. sage/rings/polynomial/ore_polynomial_element.pyx +3145 -0
  717. sage/rings/polynomial/ore_polynomial_ring.py +1334 -0
  718. sage/rings/polynomial/polynomial_real_mpfr_dense.cpython-314-x86_64-linux-gnu.so +0 -0
  719. sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +788 -0
  720. sage/rings/polynomial/q_integer_valued_polynomials.py +1264 -0
  721. sage/rings/polynomial/skew_polynomial_element.cpython-314-x86_64-linux-gnu.so +0 -0
  722. sage/rings/polynomial/skew_polynomial_element.pxd +9 -0
  723. sage/rings/polynomial/skew_polynomial_element.pyx +684 -0
  724. sage/rings/polynomial/skew_polynomial_finite_field.cpython-314-x86_64-linux-gnu.so +0 -0
  725. sage/rings/polynomial/skew_polynomial_finite_field.pxd +19 -0
  726. sage/rings/polynomial/skew_polynomial_finite_field.pyx +1093 -0
  727. sage/rings/polynomial/skew_polynomial_finite_order.cpython-314-x86_64-linux-gnu.so +0 -0
  728. sage/rings/polynomial/skew_polynomial_finite_order.pxd +10 -0
  729. sage/rings/polynomial/skew_polynomial_finite_order.pyx +567 -0
  730. sage/rings/polynomial/skew_polynomial_ring.py +908 -0
  731. sage/rings/real_double_element_gsl.cpython-314-x86_64-linux-gnu.so +0 -0
  732. sage/rings/real_double_element_gsl.pxd +8 -0
  733. sage/rings/real_double_element_gsl.pyx +794 -0
  734. sage/rings/real_field.py +58 -0
  735. sage/rings/real_mpfr.cpython-314-x86_64-linux-gnu.so +0 -0
  736. sage/rings/real_mpfr.pxd +29 -0
  737. sage/rings/real_mpfr.pyx +6122 -0
  738. sage/rings/ring_extension.cpython-314-x86_64-linux-gnu.so +0 -0
  739. sage/rings/ring_extension.pxd +42 -0
  740. sage/rings/ring_extension.pyx +2779 -0
  741. sage/rings/ring_extension_conversion.cpython-314-x86_64-linux-gnu.so +0 -0
  742. sage/rings/ring_extension_conversion.pxd +16 -0
  743. sage/rings/ring_extension_conversion.pyx +462 -0
  744. sage/rings/ring_extension_element.cpython-314-x86_64-linux-gnu.so +0 -0
  745. sage/rings/ring_extension_element.pxd +21 -0
  746. sage/rings/ring_extension_element.pyx +1635 -0
  747. sage/rings/ring_extension_homset.py +64 -0
  748. sage/rings/ring_extension_morphism.cpython-314-x86_64-linux-gnu.so +0 -0
  749. sage/rings/ring_extension_morphism.pxd +35 -0
  750. sage/rings/ring_extension_morphism.pyx +920 -0
  751. sage/schemes/all__sagemath_modules.py +1 -0
  752. sage/schemes/projective/all__sagemath_modules.py +1 -0
  753. sage/schemes/projective/coherent_sheaf.py +300 -0
  754. sage/schemes/projective/cohomology.py +510 -0
  755. sage/stats/all.py +15 -0
  756. sage/stats/basic_stats.py +489 -0
  757. sage/stats/distributions/all.py +7 -0
  758. sage/stats/distributions/catalog.py +34 -0
  759. sage/stats/distributions/dgs.h +50 -0
  760. sage/stats/distributions/dgs.pxd +111 -0
  761. sage/stats/distributions/dgs_bern.h +400 -0
  762. sage/stats/distributions/dgs_gauss.h +614 -0
  763. sage/stats/distributions/dgs_misc.h +104 -0
  764. sage/stats/distributions/discrete_gaussian_integer.cpython-314-x86_64-linux-gnu.so +0 -0
  765. sage/stats/distributions/discrete_gaussian_integer.pxd +14 -0
  766. sage/stats/distributions/discrete_gaussian_integer.pyx +498 -0
  767. sage/stats/distributions/discrete_gaussian_lattice.py +908 -0
  768. sage/stats/distributions/discrete_gaussian_polynomial.py +141 -0
  769. sage/stats/hmm/all.py +15 -0
  770. sage/stats/hmm/chmm.cpython-314-x86_64-linux-gnu.so +0 -0
  771. sage/stats/hmm/chmm.pyx +1595 -0
  772. sage/stats/hmm/distributions.cpython-314-x86_64-linux-gnu.so +0 -0
  773. sage/stats/hmm/distributions.pxd +29 -0
  774. sage/stats/hmm/distributions.pyx +531 -0
  775. sage/stats/hmm/hmm.cpython-314-x86_64-linux-gnu.so +0 -0
  776. sage/stats/hmm/hmm.pxd +17 -0
  777. sage/stats/hmm/hmm.pyx +1388 -0
  778. sage/stats/hmm/util.cpython-314-x86_64-linux-gnu.so +0 -0
  779. sage/stats/hmm/util.pxd +7 -0
  780. sage/stats/hmm/util.pyx +165 -0
  781. sage/stats/intlist.cpython-314-x86_64-linux-gnu.so +0 -0
  782. sage/stats/intlist.pxd +14 -0
  783. sage/stats/intlist.pyx +588 -0
  784. sage/stats/r.py +49 -0
  785. sage/stats/time_series.cpython-314-x86_64-linux-gnu.so +0 -0
  786. sage/stats/time_series.pxd +6 -0
  787. sage/stats/time_series.pyx +2546 -0
  788. sage/tensor/all.py +2 -0
  789. sage/tensor/modules/all.py +8 -0
  790. sage/tensor/modules/alternating_contr_tensor.py +761 -0
  791. sage/tensor/modules/comp.py +5598 -0
  792. sage/tensor/modules/ext_pow_free_module.py +824 -0
  793. sage/tensor/modules/finite_rank_free_module.py +3589 -0
  794. sage/tensor/modules/format_utilities.py +333 -0
  795. sage/tensor/modules/free_module_alt_form.py +858 -0
  796. sage/tensor/modules/free_module_automorphism.py +1207 -0
  797. sage/tensor/modules/free_module_basis.py +1074 -0
  798. sage/tensor/modules/free_module_element.py +284 -0
  799. sage/tensor/modules/free_module_homset.py +652 -0
  800. sage/tensor/modules/free_module_linear_group.py +564 -0
  801. sage/tensor/modules/free_module_morphism.py +1581 -0
  802. sage/tensor/modules/free_module_tensor.py +3289 -0
  803. sage/tensor/modules/reflexive_module.py +386 -0
  804. sage/tensor/modules/tensor_free_module.py +780 -0
  805. sage/tensor/modules/tensor_free_submodule.py +538 -0
  806. sage/tensor/modules/tensor_free_submodule_basis.py +140 -0
  807. sage/tensor/modules/tensor_with_indices.py +1043 -0
@@ -0,0 +1,3667 @@
1
+ # sage_setup: distribution = sagemath-modules
2
+ # sage.doctest: optional - sage.rings.finite_rings
3
+ """
4
+ Lean matrices
5
+
6
+ Internal data structures for the ``LinearMatroid`` class and some subclasses.
7
+ Note that many of the methods are ``cdef``, and therefore only available from
8
+ Cython code.
9
+
10
+ .. warning::
11
+
12
+ Intended for internal use by the ``LinearMatroid`` classes only. End users
13
+ should work with Sage matrices instead. Methods that are used outside
14
+ lean_matrix.pyx and have no equivalent in Sage's ``Matrix`` have been
15
+ flagged in the code, as well as where they are used, by ``# Not a Sage
16
+ matrix operation`` or ``# Deprecated Sage matrix operation``.
17
+
18
+ AUTHORS:
19
+
20
+ - Rudi Pendavingh, Stefan van Zwam (2013-04-01): initial version
21
+ """
22
+ # ****************************************************************************
23
+ # Copyright (C) 2013 Rudi Pendavingh <rudi.pendavingh@gmail.com>
24
+ # Copyright (C) 2013 Stefan van Zwam <stefanvanzwam@gmail.com>
25
+ #
26
+ #
27
+ # Distributed under the terms of the GNU General Public License (GPL)
28
+ # as published by the Free Software Foundation; either version 2 of
29
+ # the License, or (at your option) any later version.
30
+ # https://www.gnu.org/licenses/
31
+ # ****************************************************************************
32
+
33
+ from libc.string cimport memcpy, memset
34
+ from cpython.object cimport Py_EQ, Py_NE
35
+ from cysignals.memory cimport sig_malloc, sig_realloc, sig_free
36
+ from cysignals.signals cimport sig_on, sig_off
37
+
38
+ from sage.data_structures.bitset_base cimport *
39
+ from sage.matrix.constructor import matrix
40
+ from sage.matrix.matrix2 cimport Matrix
41
+ from sage.rings.integer_ring import ZZ
42
+ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
43
+ from sage.rings.rational_field import QQ
44
+ from sage.rings.integer cimport Integer
45
+ from sage.rings.rational cimport Rational
46
+ from sage.libs.gmp.mpq cimport *
47
+
48
+
49
+ cdef class LeanMatrix:
50
+ """
51
+ Lean matrices
52
+
53
+ Sage's matrix classes are powerful, versatile, and often very fast. However, their performance with regard to pivoting
54
+ (pretty much the only task performed on them within the context of matroids) leaves something to be desired. The LeanMatrix
55
+ classes provide the LinearMatroid classes with a custom, light-weight data structure to store and manipulate matrices.
56
+
57
+ This is the abstract base class. Most methods are not implemented; this is only to fix the interface.
58
+
59
+ .. NOTE::
60
+
61
+ This class is intended for internal use by the LinearMatroid class only. Hence it does not derive from ``SageObject``.
62
+ If ``A`` is a LeanMatrix instance, and you need access from other parts of Sage, use ``Matrix(A)`` instead.
63
+
64
+ EXAMPLES::
65
+
66
+ sage: M = Matroid(ring=GF(5), matrix=[[1, 0, 1, 1, 1], [0, 1, 1, 2, 3]]) # indirect doctest
67
+ sage: M.is_isomorphic(matroids.Uniform(2, 5))
68
+ True
69
+ """
70
+ def __init__(self, long m, long n, M=None):
71
+ """
72
+ Initialize a lean matrix; see class documentation for more info.
73
+
74
+ EXAMPLES::
75
+
76
+ sage: from sage.matroids.lean_matrix import LeanMatrix
77
+ sage: A = LeanMatrix(3, 4)
78
+ sage: A.ncols()
79
+ 4
80
+ """
81
+ self._nrows = m
82
+ self._ncols = n
83
+
84
+ def __repr__(self):
85
+ """
86
+ Return a string representation.
87
+
88
+ EXAMPLES::
89
+
90
+ sage: from sage.matroids.lean_matrix import LeanMatrix
91
+ sage: A = LeanMatrix(3, 4)
92
+ sage: repr(A)
93
+ 'LeanMatrix instance with 3 rows and 4 columns'
94
+ """
95
+ return "LeanMatrix instance with " + str(self._nrows) + " rows and " + str(self._ncols) + " columns"
96
+
97
+ def _matrix_(self):
98
+ """
99
+ Return a matrix version.
100
+
101
+ EXAMPLES::
102
+
103
+ sage: from sage.matroids.lean_matrix import GenericMatrix
104
+ sage: A = Matrix(GF(5), [[1, 0, 1, 1, 1], [0, 1, 1, 2, 3]])
105
+ sage: A == GenericMatrix(2, 5, A)._matrix_()
106
+ True
107
+ """
108
+ cdef long r, c
109
+ M = matrix(self.base_ring(), self._nrows, self._ncols)
110
+ for r in range(self._nrows):
111
+ for c in range(self._ncols):
112
+ M[r, c] = self.get_unsafe(r, c)
113
+ return M
114
+
115
+ cdef LeanMatrix copy(self): # Deprecated Sage matrix operation
116
+ """
117
+ Make a copy of ``self``.
118
+ """
119
+ cdef LeanMatrix A = type(self)(self.nrows(), self.ncols(), self)
120
+ return A
121
+
122
+ cdef int resize(self, long k) except -1: # Not a Sage matrix operation
123
+ """
124
+ Change number of rows of ``self`` to ``k``. Preserves data.
125
+ """
126
+ raise NotImplementedError
127
+
128
+ cdef LeanMatrix stack(self, LeanMatrix M):
129
+ """
130
+ Stack ``self`` on top of ``M``. Assumes ``self`` and ``M`` are of same
131
+ type, and compatible dimensions.
132
+ """
133
+ cdef LeanMatrix A
134
+ cdef long i, j
135
+ cdef long sr = self.nrows()
136
+ A = type(self)(sr + M.nrows(), self.ncols())
137
+ for i in range(sr):
138
+ for j in range(self.ncols()):
139
+ A.set_unsafe(i, j, self.get_unsafe(i, j))
140
+ for i in range(M.nrows()):
141
+ for j in range(M.ncols()):
142
+ A.set_unsafe(i + sr, j, M.get_unsafe(i, j))
143
+ return A
144
+
145
+ cdef LeanMatrix augment(self, LeanMatrix M):
146
+ """
147
+ Concatenates ``self`` with ``M``, placing ``M`` to the right of
148
+ ``self``. Assumes ``self`` and ``M`` are of same type, and compatible
149
+ dimensions.
150
+ """
151
+ cdef LeanMatrix A
152
+ cdef long i, j
153
+ cdef long sc = self.ncols()
154
+ A = type(self)(self.nrows(), sc + M.ncols())
155
+ for i in range(self.nrows()):
156
+ for j in range(sc):
157
+ A.set_unsafe(i, j, self.get_unsafe(i, j))
158
+ for j in range(M.ncols()):
159
+ A.set_unsafe(i, j + sc, M.get_unsafe(i, j))
160
+ return A
161
+
162
+ cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation
163
+ """
164
+ Return the matrix obtained by prepending an identity matrix. Special
165
+ case of ``augment``.
166
+ """
167
+ cdef long i, j
168
+ cdef LeanMatrix A = type(self)(self.nrows(), self.ncols() + self.nrows())
169
+ for i in range(self.nrows()):
170
+ A.set_unsafe(i, i, self.base_ring().one())
171
+ for j in range(self.ncols()):
172
+ A.set_unsafe(i, self.nrows() + j, self.get_unsafe(i, j))
173
+ return A
174
+
175
+ cpdef long ncols(self) except -1:
176
+ """
177
+ Return the number of columns.
178
+
179
+ EXAMPLES::
180
+
181
+ sage: from sage.matroids.lean_matrix import LeanMatrix
182
+ sage: A = LeanMatrix(3, 4)
183
+ sage: A.ncols()
184
+ 4
185
+ """
186
+ return self._ncols
187
+
188
+ cpdef long nrows(self) except -1:
189
+ """
190
+ Return the number of rows.
191
+
192
+ EXAMPLES::
193
+
194
+ sage: from sage.matroids.lean_matrix import LeanMatrix
195
+ sage: A = LeanMatrix(3, 4)
196
+ sage: A.nrows()
197
+ 3
198
+ """
199
+ return self._nrows
200
+
201
+ cpdef base_ring(self):
202
+ """
203
+ Return the base ring.
204
+
205
+ EXAMPLES::
206
+
207
+ sage: from sage.matroids.lean_matrix import LeanMatrix
208
+ sage: A = LeanMatrix(3, 4)
209
+ sage: A.base_ring()
210
+ Traceback (most recent call last):
211
+ ...
212
+ NotImplementedError: subclasses need to implement this
213
+ """
214
+ raise NotImplementedError("subclasses need to implement this")
215
+
216
+ cpdef characteristic(self):
217
+ """
218
+ Return the characteristic of ``self.base_ring()``.
219
+
220
+ EXAMPLES::
221
+
222
+ sage: from sage.matroids.lean_matrix import GenericMatrix
223
+ sage: A = GenericMatrix(3, 4, ring=GF(5))
224
+ sage: A.characteristic()
225
+ 5
226
+ """
227
+ return self.base_ring().characteristic()
228
+
229
+ cdef get_unsafe(self, long r, long c):
230
+ """
231
+ Return the value in row ``r``, column ``c``.
232
+ """
233
+ raise NotImplementedError
234
+
235
+ cdef int set_unsafe(self, long r, long c, x) except -1:
236
+ """
237
+ Set the value in row ``r``, column ``c`` to ``x``.
238
+ """
239
+ raise NotImplementedError
240
+
241
+ cdef bint is_nonzero(self, long r, long c) except -2: # Not a Sage matrix operation
242
+ """
243
+ Check if value in row ``r``, column ``c`` equals ``0``.
244
+ """
245
+ return self.get_unsafe(r, c) != 0
246
+
247
+ cdef int add_multiple_of_row_c(self, long x, long y, s, bint col_start) except -1:
248
+ """
249
+ Add ``s`` times row ``y`` to row ``x``. Argument ``col_start`` is
250
+ ignored.
251
+ """
252
+ cdef long i
253
+ if s is None:
254
+ for i in range(self._ncols):
255
+ self.set_unsafe(x, i, self.get_unsafe(x, i) + self.get_unsafe(y, i))
256
+ else:
257
+ for i in range(self._ncols):
258
+ self.set_unsafe(x, i, self.get_unsafe(x, i) + s * self.get_unsafe(y, i))
259
+ return 0
260
+
261
+ cdef int swap_rows_c(self, long x, long y) except -1:
262
+ """
263
+ Swap rows ``x`` and ``y``.
264
+ """
265
+ cdef long i
266
+ for i in range(self._ncols):
267
+ tmp = self.get_unsafe(x, i)
268
+ self.set_unsafe(x, i, self.get_unsafe(y, i))
269
+ self.set_unsafe(y, i, tmp)
270
+ return 0
271
+
272
+ cdef int rescale_row_c(self, long x, s, bint col_start) except -1:
273
+ """
274
+ Scale row ``x`` by ``s``. Argument ``col_start`` is for Sage
275
+ compatibility, and is ignored.
276
+ """
277
+ cdef long i
278
+ for i in range(self._ncols):
279
+ self.set_unsafe(x, i, s * self.get_unsafe(x, i))
280
+ return 0
281
+
282
+ cdef int rescale_column_c(self, long y, s, bint start_row) except -1:
283
+ """
284
+ Scale column ``y`` by ``s``. Argument ``start_row`` is for Sage
285
+ compatibility, and ignored.
286
+ """
287
+ cdef long j
288
+ for j in range(self._nrows):
289
+ self.set_unsafe(j, y, self.get_unsafe(j, y) * s)
290
+ return 0
291
+
292
+ cdef int pivot(self, long x, long y) except -1: # Not a Sage matrix operation
293
+ """
294
+ Row-reduce to make column ``y`` have a ``1`` in row ``x`` and zeroes
295
+ elsewhere.
296
+
297
+ Assumption (not checked): the entry in row ``x``, column ``y`` is
298
+ nonzero to start with.
299
+
300
+ .. NOTE::
301
+
302
+ This is different from what matroid theorists tend to call a
303
+ pivot, as it does not involve a column exchange!
304
+ """
305
+ cdef long i
306
+ self.rescale_row_c(x, self.get_unsafe(x, y) ** (-1), 0)
307
+ for i in range(self._nrows):
308
+ s = self.get_unsafe(i, y)
309
+ if s and i != x:
310
+ self.add_multiple_of_row_c(i, x, -s, 0)
311
+ return 0
312
+
313
+ cdef list gauss_jordan_reduce(self, columns): # Not a Sage matrix operation
314
+ """
315
+ Row-reduce so the lexicographically first basis indexes an identity
316
+ submatrix.
317
+ """
318
+ cdef long r = 0
319
+ cdef list P = []
320
+ cdef long c, p, row
321
+ cdef bint is_pivot
322
+ for c in columns:
323
+ is_pivot = False
324
+ for row from r <= row < self._nrows:
325
+ if self.is_nonzero(row, c):
326
+ is_pivot = True
327
+ p = row
328
+ break
329
+ if is_pivot:
330
+ self.swap_rows_c(p, r)
331
+ self.pivot(r, c)
332
+ P.append(c)
333
+ r += 1
334
+ if r == self._nrows:
335
+ break
336
+ return P
337
+
338
+ cdef list nonzero_positions_in_row(self, long r):
339
+ """
340
+ Get coordinates of nonzero entries of row ``r``.
341
+ """
342
+ return [i for i in range(self._ncols) if self.is_nonzero(r, i)]
343
+
344
+ cdef LeanMatrix transpose(self):
345
+ """
346
+ Return the transpose of the matrix.
347
+ """
348
+ cdef LeanMatrix A = type(self)(self.ncols(), self.nrows())
349
+ cdef long i, j
350
+ for i in range(self.nrows()):
351
+ for j in range(self.ncols()):
352
+ A.set_unsafe(j, i, self.get_unsafe(i, j))
353
+ return A
354
+
355
+ cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other):
356
+ """
357
+ Multiply two matrices. Assumes ``self`` and ``M`` are of same type,
358
+ and compatible dimensions.
359
+ """
360
+ cdef LeanMatrix A = type(self)(self.nrows(), other.ncols())
361
+ cdef long i, j, k
362
+ for i in range(self.nrows()):
363
+ for j in range(other.ncols()):
364
+ for k in range(self.ncols()):
365
+ A.set_unsafe(i, j, self.get_unsafe(i, k) * other.get_unsafe(k, j))
366
+ return A
367
+
368
+ cdef LeanMatrix matrix_from_rows_and_columns(self, rows, columns):
369
+ """
370
+ Return submatrix indexed by indicated rows and columns.
371
+ """
372
+ cdef long r, c
373
+ cdef LeanMatrix A = type(self)(len(rows), len(columns), ring=self.base_ring())
374
+ for r in range(len(rows)):
375
+ for c in range(len(columns)):
376
+ A.set_unsafe(r, c, self.get_unsafe(rows[r], columns[c]))
377
+ return A
378
+
379
+ def __mul__(left, right):
380
+ """
381
+ Multiply two matrices, or multiply a matrix with a constant from the
382
+ base ring.
383
+
384
+ Only works if both matrices are of the same type, or if the constant
385
+ is the first operand and can be coerced into the base ring.
386
+
387
+ EXAMPLES::
388
+
389
+ sage: from sage.matroids.lean_matrix import *
390
+ sage: A = GenericMatrix(2, 2, Matrix(GF(2), [[1, 0], [1, 1]]))
391
+ sage: B = GenericMatrix(3, 2, Matrix(GF(2), [[1, 0], [1, 0], [1, 0]]))
392
+ sage: B * A
393
+ LeanMatrix instance with 3 rows and 2 columns over Finite Field of size 2
394
+ """
395
+ cdef long i
396
+ cdef LeanMatrix A
397
+ if isinstance(left, LeanMatrix):
398
+ if type(left) is type(right):
399
+ return (<LeanMatrix>left)._matrix_times_matrix_(right)
400
+ else:
401
+ return NotImplemented
402
+ if left not in (<LeanMatrix>right).base_ring():
403
+ try:
404
+ left = (<LeanMatrix>right).base_ring()(left)
405
+ except (TypeError, NotImplemented, ValueError):
406
+ return NotImplemented
407
+ A = (<LeanMatrix>right).copy()
408
+ for i in range(A.nrows()):
409
+ A.rescale_row_c(i, left, 0)
410
+ return A
411
+
412
+ def __neg__(self):
413
+ """
414
+ Return a matrix ``B`` such that ``self + B`` is the all-zero matrix.
415
+
416
+ Note that the `` + `` operator is currently not supported.
417
+
418
+ EXAMPLES::
419
+
420
+ sage: from sage.matroids.lean_matrix import *
421
+ sage: A = GenericMatrix(2, 2, Matrix(GF(3), [[1, 0], [0, 1]]))
422
+ sage: C = -A
423
+ sage: -C == A
424
+ True
425
+ """
426
+ cdef long i
427
+ cdef LeanMatrix A = self.copy()
428
+ x = self.base_ring()(-1)
429
+ for i in range(A.nrows()):
430
+ A.rescale_row_c(i, x, 0)
431
+ return A
432
+
433
+ def __richcmp__(left, right, op):
434
+ """
435
+ Compare two matrices.
436
+
437
+ EXAMPLES::
438
+
439
+ sage: from sage.matroids.lean_matrix import *
440
+ sage: A = GenericMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]]))
441
+ sage: B = GenericMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]]))
442
+ sage: C = GenericMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]]))
443
+ sage: D = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]]))
444
+ sage: E = GenericMatrix(2, 3, Matrix(GF(2), [[1, 0, 0], [0, 1, 0]]))
445
+ sage: A == B # indirect doctest
446
+ True
447
+ sage: A != C # indirect doctest
448
+ True
449
+ sage: A == D # indirect doctest
450
+ False
451
+ sage: E == A
452
+ False
453
+ """
454
+ cdef long i, j
455
+ if op not in [Py_EQ, Py_NE]:
456
+ return NotImplemented
457
+ if not isinstance(left, LeanMatrix) or not isinstance(right, LeanMatrix):
458
+ return NotImplemented
459
+ if type(left) is not type(right):
460
+ return NotImplemented
461
+ if op == Py_EQ:
462
+ res = True
463
+ if op == Py_NE:
464
+ res = False
465
+ # res gets inverted if matroids are deemed different.
466
+ if left.nrows() != right.nrows():
467
+ return not res
468
+ if left.ncols() != right.ncols():
469
+ return not res
470
+ for i in range(left.nrows()):
471
+ for j in range(left.ncols()):
472
+ if (<LeanMatrix>left).get_unsafe(i, j) != (<LeanMatrix>right).get_unsafe(i, j):
473
+ return not res
474
+ return res
475
+
476
+ # In Cythonized classes, use ``__richcmp__()`` instead of ``__eq__()``, ``__ne__()``.
477
+
478
+ # Copying, loading, saving:
479
+
480
+ def __reduce__(self):
481
+ """
482
+ Save the object.
483
+
484
+ EXAMPLES::
485
+
486
+ sage: from sage.matroids.lean_matrix import *
487
+ sage: A = LeanMatrix(2, 5)
488
+ sage: A == loads(dumps(A)) # indirect doctest
489
+ Traceback (most recent call last):
490
+ ...
491
+ NotImplementedError: subclasses need to implement this
492
+ """
493
+ raise NotImplementedError("subclasses need to implement this")
494
+
495
+ cdef shifting_all(self, P_rows, P_cols, Q_rows, Q_cols, int m):
496
+ r"""
497
+ Given a partial matrix `M`. If the submatrix `M` using rows
498
+ ``P_rows`` columns ``P_cols`` and submatrix using rows ``Q_rows``
499
+ columns ``Q_cols`` can be extended to an ``m``-separator, then it
500
+ returns ``True, E``, where `E` is an ``m``-separator. Otherwise it
501
+ returns ``False, None``.
502
+
503
+ ``P_rows`` and ``Q_rows`` must be disjoint subsets of row indices.
504
+ ``P_cols`` and ``Q_cols`` must be disjoint subsets of column indices.
505
+
506
+ Internal version does not verify the above properties hold.
507
+
508
+ INPUT:
509
+
510
+ - ``P_rows`` -- list of row indices of the first submatrix
511
+ - ``P_cols`` -- list of column indices of the first submatrix
512
+ - ``Q_rows`` -- list of row indices of the second submatrix
513
+ - ``Q_cols`` -- list of column indices of the second submatrix
514
+ - ``m`` -- separation size
515
+
516
+ OUTPUT:
517
+
518
+ - ``False, None`` -- if the input submatrices does not induce an
519
+ ``m``-separator
520
+ - ``True, E`` -- if there exists an ``m``-separator ``E``
521
+ """
522
+ for z in range(self.ncols()):
523
+ if z in P_cols+Q_cols:
524
+ continue
525
+ sol, cert = self.shifting(P_rows, P_cols, Q_rows, Q_cols, z, None, m)
526
+ if sol:
527
+ return True, cert
528
+ sol, cert = self.shifting(Q_rows, Q_cols, P_rows, P_cols, None, z, m)
529
+ if sol:
530
+ return True, cert
531
+ sol, cert = self.shifting(P_rows, P_cols, Q_rows, Q_cols, None, z, m)
532
+ if sol:
533
+ return True, cert
534
+ sol, cert = self.shifting(Q_rows, Q_cols, P_rows, P_cols, z, None, m)
535
+ if sol:
536
+ return True, cert
537
+ return False, None
538
+
539
+ cdef shifting(self, U_1, V_2, U_2, V_1, z2, z1, int m):
540
+ r"""
541
+ Let `E_1` be the submatrix using rows `U_1` and columns `V_2` with
542
+ optional column `z2` attached.
543
+ Let `E_2` be the submatrix using rows `U_2` and columns `V_1` with
544
+ optional column `z1` attached.
545
+ If `E_1` and `E_2` can be extended to an ``m``-separator, then it
546
+ returns ``True, E``, where `E` is an ``m``-separator. Otherwise it
547
+ returns ``False, None``.
548
+
549
+ `U_1` and `U_2` must be disjoint subsets of row indices.
550
+ `V_1` and `V_2` must be disjoint subsets of column indices.
551
+
552
+ Internal version does not verify the above properties hold.
553
+
554
+ INPUT:
555
+
556
+ - ``U_1`` -- list of row indices of the first submatrix
557
+ - ``V_2`` -- list of column indices of the first submatrix
558
+ - ``U_2`` -- list of row indices of the second submatrix
559
+ - ``V_1`` -- list of column indices of the second submatrix
560
+ - ``z2`` -- start by add an additional column with index `z2` to `V_2`
561
+ - ``z1`` -- start by add an additional column with index `z1` to `V_1`
562
+ - ``m`` -- separation size
563
+
564
+ OUTPUT:
565
+
566
+ - ``False, None`` -- if the input submatrices does not induce an
567
+ ``m``-separator
568
+ - ``True, (X,Y)`` -- row indices `X` and column indices `Y` defines an
569
+ ``m``-separator
570
+ """
571
+ # make copy because of destructive updates
572
+ cdef list X_1 = list(U_1)
573
+ cdef list X_2 = list(U_2)
574
+ cdef list Y_1 = []
575
+ cdef list Y_2 = []
576
+ if z1 is not None:
577
+ Y_1 = list(V_1) + [z1]
578
+ Y_2 = list(V_2)
579
+ else:
580
+ Y_1 = list(V_1)
581
+ Y_2 = list(V_2) + [z2]
582
+
583
+ cdef int lX_2 = len(X_2)
584
+ cdef int lY_2 = len(Y_2)
585
+
586
+ if len(X_1) + len(Y_1) < m:
587
+ return False, None
588
+
589
+ cdef set X=set(range(self.nrows()))
590
+ cdef set Y=set(range(self.ncols()))
591
+
592
+ cdef set X_3 = X-set(X_1+X_2)
593
+ cdef set Y_3 = Y-set(Y_1+Y_2)
594
+
595
+ cdef list lU_2 = sorted(list(U_2))
596
+ cdef list lV_2 = sorted(list(V_2))
597
+ cdef dict rU = dict(zip(lU_2, range(len(U_2))))
598
+ cdef dict rV = dict(zip(lV_2, range(len(V_2))))
599
+
600
+ # find a unique representation of every column in U_1xY_3 using columns in U_1xV_2
601
+ B = self.matrix_from_rows_and_columns(list(U_1), range(len(Y)))
602
+ B.gauss_jordan_reduce(lV_2)
603
+ # find a unique representation of every rows in X_3xV_1 using rows in U_2xV_1
604
+ BT = self.matrix_from_rows_and_columns(range(len(X)),
605
+ list(V_1)).transpose()
606
+ BT.gauss_jordan_reduce(lU_2)
607
+
608
+ cdef set X_p = set(X_1)
609
+ cdef set Y_p = set(Y_1)
610
+ while True:
611
+ # rowshifts
612
+ X_p_new = set()
613
+ for x in set(X_3):
614
+ for y in Y_p:
615
+ if sum([BT.get_unsafe(rU[u], x) * self.get_unsafe(u, y)
616
+ for u in U_2]) != self.get_unsafe(x, y):
617
+ X_1.append(x)
618
+ X_3.remove(x)
619
+ X_p_new.add(x)
620
+ break
621
+ # colshifts
622
+ Y_p_new = set()
623
+ for y in set(Y_3):
624
+ for x in X_p:
625
+ if sum([B.get_unsafe(rV[v], y) * self.get_unsafe(x, v)
626
+ for v in V_2]) != self.get_unsafe(x, y):
627
+ Y_1.append(y)
628
+ Y_3.remove(y)
629
+ Y_p_new.add(y)
630
+ break
631
+ X_p = X_p_new
632
+ Y_p = Y_p_new
633
+ if (not X_p_new and not Y_p_new):
634
+ break
635
+
636
+ # size of S_2
637
+ X_2 = list(X-set(X_1))
638
+ Y_2 = list(Y-set(Y_1))
639
+ if len(X_2)+len(Y_2) < m:
640
+ return False, None
641
+ if (lX_2==len(X_2) and lY_2==len(Y_2)):
642
+ return False, None
643
+ return True, (X_1, Y_1)
644
+
645
+ cdef class GenericMatrix(LeanMatrix):
646
+ """
647
+ Matrix over arbitrary Sage ring.
648
+
649
+ INPUT:
650
+
651
+ - ``nrows`` -- number of rows
652
+ - ``ncols`` -- number of columns
653
+ - ``M`` -- (default: ``None``) a ``Matrix`` or ``GenericMatrix`` of
654
+ dimensions at most ``m*n``
655
+ - ``ring`` -- (default: ``None``) a Sage ring
656
+
657
+ .. NOTE::
658
+
659
+ This class is intended for internal use by the LinearMatroid class
660
+ only. Hence it does not derive from ``SageObject``. If ``A`` is a
661
+ LeanMatrix instance, and you need access from other parts of Sage,
662
+ use ``Matrix(A)`` instead.
663
+
664
+ If the constructor is fed a GenericMatrix instance, the ``ring``
665
+ argument is ignored. Otherwise, the matrix entries
666
+ will be converted to the appropriate ring.
667
+
668
+ EXAMPLES::
669
+
670
+ sage: M = Matroid(ring=GF(5), matrix=[[1, 0, 1, 1, 1], [0, 1, 1, 2, 3]]) # indirect doctest
671
+ sage: M.is_isomorphic(matroids.Uniform(2, 5))
672
+ True
673
+ """
674
+
675
+ def __init__(self, long nrows, long ncols, M=None, ring=None):
676
+ """
677
+ See the class docstring for full information.
678
+
679
+ EXAMPLES::
680
+
681
+ sage: from sage.matroids.lean_matrix import *
682
+ sage: A = GenericMatrix(2, 2, Matrix(GF(3), [[0, 0], [0, 0]])) # indirect doctest
683
+ sage: B = GenericMatrix(2, 2, ring=GF(3))
684
+ sage: A == B
685
+ True
686
+ """
687
+ cdef long i, j
688
+ cdef bint ring_override = False
689
+ self._nrows = nrows
690
+ self._ncols = ncols
691
+ if M is not None:
692
+ self._base_ring = M.base_ring()
693
+ if ring is not None:
694
+ # Overrides M's ring
695
+ self._base_ring = ring
696
+ ring_override = True
697
+ # Default:
698
+ if self._base_ring is None:
699
+ self._base_ring = ZZ
700
+ self._zero = self._base_ring.zero()
701
+ self._one = self._base_ring.one()
702
+ self._entries = [self._zero] * nrows * ncols
703
+ if M is not None:
704
+ if isinstance(M, GenericMatrix):
705
+ if nrows == (<GenericMatrix>M)._nrows and ncols == (<GenericMatrix>M)._ncols:
706
+ self._entries = (<GenericMatrix>M)._entries[:] # Slicing notation makes copy
707
+ else:
708
+ for i in range((<GenericMatrix>M)._nrows):
709
+ self._entries[i * self._ncols:i * self._ncols + (<GenericMatrix>M)._ncols] = (<GenericMatrix>M)._entries[i * (<GenericMatrix>M)._ncols:(i + 1) * (<GenericMatrix>M)._ncols]
710
+ elif isinstance(M, LeanMatrix):
711
+ if ring_override:
712
+ for i in range(M.nrows()):
713
+ for j in range(M.ncols()):
714
+ self._entries[i * self._ncols + j] = self._base_ring((<LeanMatrix>M).get_unsafe(i, j))
715
+ else:
716
+ for i in range(M.nrows()):
717
+ for j in range(M.ncols()):
718
+ self._entries[i * self._ncols + j] = (<LeanMatrix>M).get_unsafe(i, j)
719
+ else: # Sage Matrix or otherwise
720
+ if ring_override:
721
+ for i in range(M.nrows()):
722
+ for j in range(M.ncols()):
723
+ self._entries[i * self._ncols + j] = self._base_ring(M[i, j])
724
+ else:
725
+ for i in range(M.nrows()):
726
+ for j in range(M.ncols()):
727
+ self._entries[i * self._ncols + j] = M[i, j]
728
+
729
+ def __repr__(self):
730
+ """
731
+ Return representation.
732
+
733
+ EXAMPLES::
734
+
735
+ sage: from sage.matroids.lean_matrix import *
736
+ sage: A = GenericMatrix(2, 2, Matrix(GF(3), [[0, 0], [0, 0]]))
737
+ sage: repr(A) # indirect doctest
738
+ 'LeanMatrix instance with 2 rows and 2 columns over Finite Field of size 3'
739
+ """
740
+ return "LeanMatrix instance with " + str(self._nrows) + " rows and " + str(self._ncols) + " columns over " + repr(self._base_ring)
741
+
742
+ cdef LeanMatrix copy(self): # Deprecated Sage matrix operation
743
+ cdef GenericMatrix M = GenericMatrix(self._nrows, self._ncols, M=self)
744
+ return M
745
+
746
+ cdef int resize(self, long k) except -1: # Not a Sage matrix operation
747
+ """
748
+ Change number of rows to ``k``. Preserves data.
749
+ """
750
+ cdef long l = len(self._entries) - k * self._ncols
751
+ if l > 0:
752
+ self._entries.extend([self._zero] * l)
753
+ elif l < 0:
754
+ del self._entries[k * self._ncols:]
755
+ self._nrows = k
756
+ return 0
757
+
758
+ cdef LeanMatrix stack(self, LeanMatrix M):
759
+ """
760
+ Warning: assumes ``M`` is a GenericMatrix instance!
761
+ """
762
+ cdef GenericMatrix A
763
+ A = GenericMatrix(0, 0, ring=self._base_ring)
764
+ A._entries = self._entries + ((<GenericMatrix>M)._entries)
765
+ A._nrows = self._nrows + M.nrows()
766
+ A._ncols = self._ncols
767
+ return A
768
+
769
+ cdef LeanMatrix augment(self, LeanMatrix M):
770
+ """
771
+ Warning: assumes ``M`` is a GenericMatrix instance!
772
+ """
773
+ cdef GenericMatrix A
774
+ cdef long i
775
+ cdef long Mn = M.ncols()
776
+ A = GenericMatrix(self._nrows, self._ncols + Mn, ring=self._base_ring)
777
+ for i in range(self._nrows):
778
+ A._entries[i * A._ncols:i * A._ncols + self._ncols] = self._entries[i * self._ncols:(i + 1) * self._ncols]
779
+ A._entries[i * A._ncols + self._ncols:(i + 1) * A._ncols]=(<GenericMatrix>M)._entries[i * Mn:(i + 1) * Mn]
780
+ return A
781
+
782
+ cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation
783
+ cdef GenericMatrix A = GenericMatrix(self._nrows, self._ncols + self._nrows, ring=self._base_ring)
784
+ for i in range(self._nrows):
785
+ A._entries[i * A._ncols + i] = self._one
786
+ A._entries[i * A._ncols + self._nrows:(i + 1) * A._ncols]=self._entries[i * self._ncols:(i + 1) * self._ncols]
787
+ return A
788
+
789
+ cpdef base_ring(self):
790
+ """
791
+ Return the base ring of ``self``.
792
+
793
+ EXAMPLES::
794
+
795
+ sage: from sage.matroids.lean_matrix import GenericMatrix
796
+ sage: A = GenericMatrix(3, 4, ring=GF(5))
797
+ sage: A.base_ring()
798
+ Finite Field of size 5
799
+ """
800
+ return self._base_ring
801
+
802
+ cpdef characteristic(self):
803
+ """
804
+ Return the characteristic of ``self.base_ring()``.
805
+
806
+ EXAMPLES::
807
+
808
+ sage: from sage.matroids.lean_matrix import GenericMatrix
809
+ sage: A = GenericMatrix(3, 4, ring=GF(5))
810
+ sage: A.characteristic()
811
+ 5
812
+ """
813
+ if self._characteristic is None:
814
+ self._characteristic = self._base_ring.characteristic()
815
+ return self._characteristic
816
+
817
+ cdef get_unsafe(self, long r, long c):
818
+ return self._entries[r * self._ncols + c]
819
+
820
+ cdef int set_unsafe(self, long r, long c, x) except -1:
821
+ self._entries[r * self._ncols + c] = x
822
+ return 0
823
+
824
+ cdef int swap_rows_c(self, long x, long y) except -1:
825
+ """
826
+ Swap rows ``x`` and ``y``.
827
+ """
828
+ cdef list tmp = self._entries[x * self._ncols:(x + 1) * self._ncols]
829
+ self._entries[x * self._ncols:(x + 1) * self._ncols] = self._entries[y * self._ncols:(y + 1) * self._ncols]
830
+ self._entries[y * self._ncols:(y + 1) * self._ncols] = tmp
831
+ return 0
832
+
833
+ cdef LeanMatrix transpose(self):
834
+ """
835
+ Return the transpose of the matrix.
836
+ """
837
+ cdef GenericMatrix A
838
+ cdef long i, j
839
+ A = GenericMatrix(self._ncols, self._nrows, ring=self._base_ring)
840
+ for i in range(self._nrows):
841
+ for j in range(self._ncols):
842
+ A.set_unsafe(j, i, self.get_unsafe(i, j))
843
+ return A
844
+
845
+ cdef inline row_inner_product(self, long i, long j): # Not a Sage matrix operation
846
+ """
847
+ Return the inner product between rows ``i`` and ``j``.
848
+ """
849
+ cdef long k
850
+ res = 0
851
+ for k in range(self._ncols):
852
+ x = self.get_unsafe(i, k)
853
+ y = self.get_unsafe(j, k)
854
+ if y and y != self._one:
855
+ y += self._one
856
+ res += x * y
857
+ return res
858
+
859
+ cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other):
860
+ """
861
+ Return the product ``self * other``.
862
+ """
863
+ cdef GenericMatrix A, ot
864
+ cdef long i, j, t
865
+ ot = <GenericMatrix > other
866
+ A = GenericMatrix(self._nrows, ot._ncols, ring=self._base_ring)
867
+ for i in range(A._nrows):
868
+ for j in range(A._ncols):
869
+ s = self._zero
870
+ for t in range(self._ncols):
871
+ s += self.get_unsafe(i, t) * ot.get_unsafe(t, j)
872
+ A.set_unsafe(i, j, s)
873
+ return A
874
+
875
+ def __richcmp__(left, right, op):
876
+ """
877
+ Compare two matrices.
878
+
879
+ EXAMPLES::
880
+
881
+ sage: from sage.matroids.lean_matrix import *
882
+ sage: A = GenericMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]]))
883
+ sage: B = GenericMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]]))
884
+ sage: C = GenericMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]]))
885
+ sage: D = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]]))
886
+ sage: E = GenericMatrix(2, 3, Matrix(GF(2), [[1, 0, 0], [0, 1, 0]]))
887
+ sage: A == B # indirect doctest
888
+ True
889
+ sage: A != C # indirect doctest
890
+ True
891
+ sage: A == D # indirect doctest
892
+ False
893
+ sage: E == A
894
+ False
895
+ """
896
+ if op not in [Py_EQ, Py_NE]:
897
+ return NotImplemented
898
+ if not isinstance(left, GenericMatrix) or not isinstance(right, GenericMatrix):
899
+ return NotImplemented
900
+ if op == Py_EQ:
901
+ res = True
902
+ if op == Py_NE:
903
+ res = False
904
+ # res gets inverted if matroids are deemed different.
905
+ if left.nrows() != right.nrows():
906
+ return not res
907
+ if left.ncols() != right.ncols():
908
+ return not res
909
+ if left.base_ring() != right.base_ring():
910
+ return not res
911
+ if (<GenericMatrix>left)._entries != (<GenericMatrix>right)._entries:
912
+ return not res
913
+ return res
914
+
915
+ def __reduce__(self):
916
+ """
917
+ Save the object.
918
+
919
+ EXAMPLES::
920
+
921
+ sage: from sage.matroids.lean_matrix import *
922
+ sage: A = GenericMatrix(2, 5, ring=QQ)
923
+ sage: A == loads(dumps(A)) # indirect doctest
924
+ True
925
+ sage: C = GenericMatrix(2, 2, Matrix(GF(3), [[1, 1], [0, 1]]))
926
+ sage: C == loads(dumps(C))
927
+ True
928
+ """
929
+ import sage.matroids.unpickling
930
+ version = 0
931
+ data = (self.nrows(), self.ncols(), self.base_ring(), self._entries)
932
+ return sage.matroids.unpickling.unpickle_generic_matrix, (version, data)
933
+
934
+ # Binary matrices
935
+
936
+ cdef bint GF2_not_defined = True
937
+ cdef GF2, GF2_one, GF2_zero
938
+
939
+ cdef class BinaryMatrix(LeanMatrix):
940
+ """
941
+ Binary matrix class. Entries are stored bit-packed into integers.
942
+
943
+ INPUT:
944
+
945
+ - ``m`` -- number of rows
946
+ - ``n`` -- number of columns
947
+ - ``M`` -- (default: ``None``) ``Matrix`` or ``BinaryMatrix`` instance.
948
+ Assumption: dimensions of ``M`` are at most ``m`` by ``n``.
949
+ - ``ring`` -- (default: ``None``) ignored
950
+
951
+ EXAMPLES::
952
+
953
+ sage: from sage.matroids.lean_matrix import *
954
+ sage: A = BinaryMatrix(2, 2, Matrix(GF(7), [[0, 0], [0, 0]]))
955
+ sage: B = BinaryMatrix(2, 2, ring=GF(5))
956
+ sage: C = BinaryMatrix(2, 2)
957
+ sage: A == B and A == C
958
+ True
959
+ """
960
+ def __cinit__(self, long m, long n, object M=None, object ring=None):
961
+ """
962
+ Init internal data structures.
963
+
964
+ EXAMPLES::
965
+
966
+ sage: from sage.matroids.lean_matrix import *
967
+ sage: A = BinaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest
968
+ sage: A.nrows()
969
+ 2
970
+ """
971
+ cdef long i, j
972
+ self._nrows = m
973
+ self._ncols = n
974
+ self._M = <bitset_t* > sig_malloc(self._nrows * sizeof(bitset_t))
975
+ if isinstance(M, BinaryMatrix):
976
+ j = max(1, (<BinaryMatrix>M)._ncols)
977
+ else:
978
+ j = max(1, self._ncols)
979
+ for i in range(self._nrows):
980
+ bitset_init(self._M[i], j)
981
+ bitset_clear(self._M[i])
982
+ bitset_init(self._temp, j)
983
+
984
+ def __init__(self, long m, long n, object M=None, object ring=None):
985
+ """
986
+ See the class docstring for full specification.
987
+
988
+ EXAMPLES::
989
+
990
+ sage: from sage.matroids.lean_matrix import *
991
+ sage: A = BinaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest
992
+ sage: A.nrows()
993
+ 2
994
+ """
995
+ cdef long i, j
996
+ global GF2, GF2_zero, GF2_one, GF2_not_defined
997
+ if GF2_not_defined:
998
+ GF2 = GF(2)
999
+ GF2_zero = GF2.zero()
1000
+ GF2_one = GF2.one()
1001
+ GF2_not_defined = False
1002
+ if M is not None:
1003
+ if isinstance(M, BinaryMatrix):
1004
+ for i in range(M.nrows()):
1005
+ bitset_copy(self._M[i], (<BinaryMatrix>M)._M[i])
1006
+ elif isinstance(M, LeanMatrix):
1007
+ for i in range(M.nrows()):
1008
+ for j in range(M.ncols()):
1009
+ if int((<LeanMatrix>M).get_unsafe(i, j)) & 1:
1010
+ self.set(i, j)
1011
+ elif isinstance(M, Matrix):
1012
+ for i in range(M.nrows()):
1013
+ for j in range(M.ncols()):
1014
+ if int((<Matrix>M).get_unsafe(i, j)) & 1:
1015
+ self.set(i, j)
1016
+ else:
1017
+ raise TypeError("unrecognized input type")
1018
+
1019
+ def __dealloc__(self):
1020
+ cdef long i
1021
+ for i in range(self._nrows):
1022
+ bitset_free(self._M[i])
1023
+ sig_free(self._M)
1024
+ bitset_free(self._temp)
1025
+
1026
+ def __repr__(self):
1027
+ r"""
1028
+ Return representation string.
1029
+
1030
+ EXAMPLES::
1031
+
1032
+ sage: from sage.matroids.lean_matrix import *
1033
+ sage: A = BinaryMatrix(2, 3, Matrix(GF(4, 'x'), [[0, 0], [0, 0]]))
1034
+ sage: repr(A) # indirect doctest
1035
+ '2 x 3 BinaryMatrix\n[000]\n[000]'
1036
+ """
1037
+ out = str(self._nrows) + ' x ' + str(self._ncols) + ' BinaryMatrix'
1038
+ cdef long i
1039
+ if self._ncols > 0:
1040
+ for i in range(self._nrows):
1041
+ out += '\n[' + bitset_string(self._M[i]) + ']'
1042
+ else:
1043
+ for i in range(self._nrows):
1044
+ out += '[]'
1045
+ return out
1046
+
1047
+ def _matrix_(self):
1048
+ """
1049
+ Return a matrix version.
1050
+
1051
+ EXAMPLES::
1052
+
1053
+ sage: from sage.matroids.lean_matrix import *
1054
+ sage: A = Matrix(GF(2), [[1, 0], [0, 1]])
1055
+ sage: A == BinaryMatrix(2, 2, A)._matrix_()
1056
+ True
1057
+ """
1058
+ cdef long i, j
1059
+ M = matrix(GF(2), self._nrows, self._ncols)
1060
+ for i in range(self._nrows):
1061
+ for j in range(self._ncols):
1062
+ if bitset_in(self._M[i], j):
1063
+ M[i, j] = 1
1064
+ return M
1065
+
1066
+ cdef LeanMatrix copy(self): # Deprecated Sage matrix operation
1067
+ cdef BinaryMatrix B
1068
+ cdef long i
1069
+ B = BinaryMatrix(self.nrows(), self.ncols())
1070
+ for i in range(self._nrows):
1071
+ bitset_copy(B._M[i], self._M[i])
1072
+ return B
1073
+
1074
+ cdef int resize(self, long k) except -1: # Not a Sage matrix operation
1075
+ """
1076
+ Change number of rows to ``k``. Preserves data.
1077
+ """
1078
+ cdef long i, c
1079
+ if k < self._nrows:
1080
+ for i in range(k, self._nrows):
1081
+ bitset_free(self._M[i])
1082
+ self._nrows = k
1083
+ self._M = <bitset_t* > sig_realloc(self._M, k * sizeof(bitset_t))
1084
+ if k > self._nrows:
1085
+ self._M = <bitset_t* > sig_realloc(self._M, k * sizeof(bitset_t))
1086
+ c = max(1, self._ncols)
1087
+ for i in range(self._nrows, k):
1088
+ bitset_init(self._M[i], c)
1089
+ bitset_clear(self._M[i])
1090
+ self._nrows = k
1091
+ return 0
1092
+
1093
+ cdef LeanMatrix stack(self, LeanMatrix MM):
1094
+ """
1095
+ Given ``A`` and ``B``, return
1096
+ [A]
1097
+ [B]
1098
+ """
1099
+ cdef BinaryMatrix R
1100
+ cdef BinaryMatrix M = <BinaryMatrix > MM
1101
+ cdef long i
1102
+ R = BinaryMatrix(self.nrows() + M.nrows(), self.ncols(), self)
1103
+ for i in range(M.nrows()):
1104
+ bitset_copy(R._M[i + self.nrows()], M._M[i])
1105
+ return R
1106
+
1107
+ cdef LeanMatrix augment(self, LeanMatrix MM):
1108
+ """
1109
+ Given ``A`` and ``B``, return
1110
+ [A B]
1111
+ """
1112
+ cdef BinaryMatrix R
1113
+ cdef BinaryMatrix M = <BinaryMatrix > MM
1114
+ cdef long i, j
1115
+ R = BinaryMatrix(self.nrows(), self.ncols() + M.ncols(), self)
1116
+ for i in range(R.nrows()):
1117
+ for j in range(M.ncols()):
1118
+ bitset_set_to(R._M[i], self.ncols() + j, bitset_in(M._M[i], j))
1119
+ return R
1120
+
1121
+ cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation
1122
+ """
1123
+ Return the matrix obtained by prepending an identity matrix. Special case of ``augment``.
1124
+ """
1125
+ cdef long i
1126
+ cdef BinaryMatrix A = BinaryMatrix(self._nrows, self._ncols + self._nrows)
1127
+ for i in range(self._nrows):
1128
+ bitset_lshift(A._M[i], self._M[i], self._nrows)
1129
+ A.set(i, i)
1130
+ return A
1131
+
1132
+ cpdef base_ring(self):
1133
+ """
1134
+ Return `GF(2)`.
1135
+
1136
+ EXAMPLES::
1137
+
1138
+ sage: from sage.matroids.lean_matrix import *
1139
+ sage: A = BinaryMatrix(4, 4)
1140
+ sage: A.base_ring()
1141
+ Finite Field of size 2
1142
+ """
1143
+ global GF2
1144
+ return GF2
1145
+
1146
+ cpdef characteristic(self):
1147
+ """
1148
+ Return the characteristic of ``self.base_ring()``.
1149
+
1150
+ EXAMPLES::
1151
+
1152
+ sage: from sage.matroids.lean_matrix import *
1153
+ sage: A = BinaryMatrix(3, 4)
1154
+ sage: A.characteristic()
1155
+ 2
1156
+ """
1157
+ return 2
1158
+
1159
+ cdef get_unsafe(self, long r, long c):
1160
+ global GF2_one, GF2_zero
1161
+ if bitset_in(self._M[r], c):
1162
+ return GF2_one
1163
+ return GF2_zero
1164
+
1165
+ cdef int set_unsafe(self, long r, long c, x) except -1:
1166
+ if x:
1167
+ bitset_add(self._M[r], c)
1168
+ else:
1169
+ bitset_discard(self._M[r], c)
1170
+ return 0
1171
+
1172
+ cdef inline bint is_nonzero(self, long r, long c) except -2: # Not a Sage matrix operation
1173
+ return bitset_in(self._M[r], c)
1174
+
1175
+ cdef inline bint get(self, long r, long c) noexcept: # Not a Sage matrix operation
1176
+ return bitset_in(self._M[r], c)
1177
+
1178
+ cdef inline void set(self, long x, long y) noexcept: # Not a Sage matrix operation
1179
+ bitset_add(self._M[x], y)
1180
+
1181
+ cdef int pivot(self, long x, long y) except -1: # Not a Sage matrix operation
1182
+ """
1183
+ Row-reduce to make column ``y`` have a ``1`` in row ``x`` and
1184
+ zeroes elsewhere.
1185
+
1186
+ Assumption (not checked): the entry in row ``x``, column ``y``
1187
+ is nonzero to start with.
1188
+
1189
+ .. NOTE::
1190
+
1191
+ This is different from what matroid theorists tend to call a
1192
+ pivot, as it does not involve a column exchange!
1193
+ """
1194
+ cdef long i
1195
+ for i in range(self._nrows):
1196
+ if bitset_in(self._M[i], y) and i != x:
1197
+ bitset_symmetric_difference(self._M[i], self._M[i], self._M[x])
1198
+ return 0
1199
+
1200
+ cdef inline long row_len(self, long i) except -1: # Not a Sage matrix operation
1201
+ """
1202
+ Return number of nonzero entries in row ``i``.
1203
+ """
1204
+ return bitset_len(self._M[i])
1205
+
1206
+ cdef inline bint row_inner_product(self, long i, long j) noexcept: # Not a Sage matrix operation
1207
+ """
1208
+ Return the inner product between rows ``i`` and ``j``.
1209
+ """
1210
+ bitset_copy(self._temp, self._M[i])
1211
+ bitset_intersection(self._temp, self._temp, self._M[j])
1212
+ return bitset_len(self._temp) & 1
1213
+
1214
+ cdef int add_multiple_of_row_c(self, long i, long j, s, bint col_start) except -1:
1215
+ """
1216
+ Add row ``j`` to row ``i``. Other arguments are ignored.
1217
+ """
1218
+ bitset_symmetric_difference(self._M[i], self._M[i], self._M[j])
1219
+ return 0
1220
+
1221
+ cdef int swap_rows_c(self, long i, long j) except -1:
1222
+ bitset_copy(self._temp, self._M[i])
1223
+ bitset_copy(self._M[i], self._M[j])
1224
+ bitset_copy(self._M[j], self._temp)
1225
+ return 0
1226
+
1227
+ cdef inline list nonzero_positions_in_row(self, long i):
1228
+ """
1229
+ Get coordinates of nonzero entries of row ``r``.
1230
+ """
1231
+ return bitset_list(self._M[i])
1232
+
1233
+ cdef inline list row_sum(self, object L): # Not a Sage matrix operation
1234
+ """
1235
+ Return the mod-2 sum of the rows indexed by ``L``.
1236
+ """
1237
+ bitset_clear(self._temp)
1238
+ for l in L:
1239
+ bitset_symmetric_difference(self._temp, self._temp, self._M[l])
1240
+ return bitset_list(self._temp)
1241
+
1242
+ cdef inline list row_union(self, object L): # Not a Sage matrix operation
1243
+ """
1244
+ Return the ``or`` of the rows indexed by ``L``.
1245
+ """
1246
+ bitset_clear(self._temp)
1247
+ for l in L:
1248
+ bitset_union(self._temp, self._temp, self._M[l])
1249
+ return bitset_list(self._temp)
1250
+
1251
+ cdef LeanMatrix transpose(self):
1252
+ """
1253
+ Return the transpose of the matrix.
1254
+ """
1255
+ cdef BinaryMatrix T
1256
+ cdef long i, j
1257
+ T = BinaryMatrix(self._ncols, self._nrows)
1258
+ for i in range(self._nrows):
1259
+ j = bitset_first(self._M[i])
1260
+ while j >= 0:
1261
+ T.set(j, i)
1262
+ j = bitset_next(self._M[i], j + 1)
1263
+ return T
1264
+
1265
+ cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other):
1266
+ """
1267
+ Return the product ``self * other``.
1268
+ """
1269
+ cdef BinaryMatrix M
1270
+ cdef BinaryMatrix ot = <BinaryMatrix > other
1271
+ M = BinaryMatrix(self._nrows, ot._ncols)
1272
+ cdef long i, j
1273
+ for i in range(self._nrows):
1274
+ j = bitset_first(self._M[i])
1275
+ while j >= 0:
1276
+ bitset_symmetric_difference(M._M[i], M._M[i], ot._M[j])
1277
+ j = bitset_next(self._M[i], j + 1)
1278
+ return M
1279
+
1280
+ cdef LeanMatrix matrix_from_rows_and_columns(self, rows, columns):
1281
+ """
1282
+ Return submatrix indexed by indicated rows and columns.
1283
+ """
1284
+ cdef long r, c
1285
+ cdef BinaryMatrix A = BinaryMatrix(len(rows), len(columns))
1286
+ for r in range(len(rows)):
1287
+ for c in range(len(columns)):
1288
+ if bitset_in(self._M[rows[r]], <mp_bitcnt_t> columns[c]):
1289
+ bitset_add(A._M[r], c)
1290
+ return A
1291
+
1292
+ cdef matrix_from_rows_and_columns_reordered(self, rows, columns):
1293
+ """
1294
+ Return a submatrix indexed by indicated rows and columns, as well as
1295
+ the column order of the resulting submatrix.
1296
+ """
1297
+ cdef BinaryMatrix A = BinaryMatrix(len(rows), len(columns))
1298
+ cdef long r, c, lc, lg
1299
+ cdef mp_bitcnt_t *cols
1300
+ # deal with trivial case
1301
+ lc = len(columns)
1302
+ if lc == 0:
1303
+ return A, []
1304
+ # write [c for c in columns if c<lc] as bitset `mask` and
1305
+ # write [c for c in columns if c>=lc] as array `cols`
1306
+ cdef bitset_t mask
1307
+ bitset_init(mask, lc)
1308
+ bitset_clear(mask)
1309
+ cols = <mp_bitcnt_t*>sig_malloc(lc*sizeof(mp_bitcnt_t))
1310
+ g = 0
1311
+ for c in columns:
1312
+ if c<lc:
1313
+ bitset_add(mask, c)
1314
+ else:
1315
+ cols[g] = c
1316
+ g = g+1
1317
+ # write [ c for c in range(lc) if c not in columns] as array `gaps`
1318
+ cdef mp_bitcnt_t *gaps
1319
+ gaps = <mp_bitcnt_t*>sig_malloc(lc*sizeof(mp_bitcnt_t))
1320
+ bitset_complement(mask, mask)
1321
+ g = 0
1322
+ c = bitset_first(mask)
1323
+ while c >= 0:
1324
+ gaps[g] = c
1325
+ g = g + 1
1326
+ c = bitset_next(mask, c + 1)
1327
+ lg = g
1328
+ bitset_complement(mask, mask)
1329
+ # copy relevant part of this matrix into A
1330
+ cdef bitset_t row, row2
1331
+ for r in range(len(rows)):
1332
+ row = self._M[rows[r]]
1333
+ row2 = A._M[r]
1334
+ bitset_intersection(row2, row, mask) # yes, this is safe
1335
+ for g in range(lg):
1336
+ if bitset_in(row, cols[g]):
1337
+ bitset_add(row2, gaps[g])
1338
+ # record order of the columns in list `order`
1339
+ cdef list order = list(range(lc))
1340
+ g = 0
1341
+ for g in range(lg):
1342
+ order[gaps[g]] = cols[g]
1343
+ # free up the two arrays and the bitset
1344
+ sig_free(gaps)
1345
+ sig_free(cols)
1346
+ bitset_free(mask)
1347
+ return A, order
1348
+
1349
+ cdef list _character(self, bitset_t x): # Not a Sage matrix operation
1350
+ """
1351
+ Return the vector of intersection lengths of the rows with ``x``.
1352
+ """
1353
+ cdef long i
1354
+ I = []
1355
+ for i in range(self._nrows):
1356
+ bitset_intersection(self._temp, self._M[i], x)
1357
+ I.append(bitset_len(self._temp))
1358
+ return I
1359
+
1360
+ cdef BinaryMatrix _distinguish_by(self, BinaryMatrix P):
1361
+ """
1362
+ Helper method for equitable partition.
1363
+ """
1364
+ cdef BinaryMatrix Q
1365
+ d = {}
1366
+ for i in range(self._nrows):
1367
+ c = hash(tuple(P._character(self._M[i])))
1368
+ if c in d:
1369
+ d[c].append(i)
1370
+ else:
1371
+ d[c] = [i]
1372
+ Q = BinaryMatrix(len(d), self._nrows)
1373
+ i = 0
1374
+ cdef mp_bitcnt_t j
1375
+ for c in sorted(d):
1376
+ for j in d[c]:
1377
+ bitset_add(Q._M[i], j)
1378
+ i += 1
1379
+ return Q
1380
+
1381
+ cdef BinaryMatrix _splice_by(self, BinaryMatrix P):
1382
+ """
1383
+ Helper method for equitable partition.
1384
+ """
1385
+ cdef BinaryMatrix Q
1386
+ cdef long i, j, r
1387
+ Q = BinaryMatrix(self._ncols, self._ncols)
1388
+ r = 0
1389
+ for i in range(self._nrows):
1390
+ for j in range(P._nrows):
1391
+ bitset_intersection(self._temp, self._M[i], P._M[j])
1392
+ if not bitset_isempty(self._temp):
1393
+ bitset_copy(Q._M[r], self._temp)
1394
+ r += 1
1395
+ Q.resize(r)
1396
+ return Q
1397
+
1398
+ cdef BinaryMatrix _isolate(self, long j):
1399
+ """
1400
+ Helper method for isomorphism test.
1401
+ """
1402
+ cdef BinaryMatrix Q
1403
+ cdef long i
1404
+ Q = BinaryMatrix(self._nrows + 1, self._ncols)
1405
+ for i in range(self._nrows):
1406
+ bitset_copy(Q._M[i], self._M[i])
1407
+ bitset_discard(Q._M[i], j)
1408
+ bitset_add(Q._M[self._nrows], j)
1409
+ return Q
1410
+
1411
+ cdef BinaryMatrix equitable_partition(self, BinaryMatrix P=None):
1412
+ """
1413
+ Compute an equitable partition of the columns.
1414
+ """
1415
+ if P is None:
1416
+ P = BinaryMatrix(1, self._ncols)
1417
+ bitset_set_first_n(P._M[0], self._ncols)
1418
+ r = 0
1419
+ while P.nrows() > r:
1420
+ r = P.nrows()
1421
+ P = P._splice_by(self._distinguish_by(P))
1422
+ return P
1423
+
1424
+ cdef bint is_isomorphic(self, BinaryMatrix other, BinaryMatrix s_eq=None, BinaryMatrix o_eq=None) except -2: # Not a Sage matrix operation
1425
+ """
1426
+ Test for isomorphism between the row spaces.
1427
+ """
1428
+ cdef long e, f, i, j
1429
+ if s_eq is None:
1430
+ s_eq = self.equitable_partition()
1431
+ if o_eq is None:
1432
+ o_eq = other.equitable_partition()
1433
+
1434
+ if s_eq.nrows() != o_eq.nrows():
1435
+ return False
1436
+ if s_eq.nrows() == s_eq.ncols(): # s_eq and o_eq partition into singletons
1437
+ morph = [0 for _ in range(self._nrows)]
1438
+ for i in range(self._nrows):
1439
+ morph[bitset_first(s_eq._M[i])] = bitset_first(o_eq._M[i])
1440
+ for i in range(self._nrows):
1441
+ for j in range(self._ncols):
1442
+ if self.get(i, j) != other.get(morph[i], morph[j]):
1443
+ return False
1444
+ return True
1445
+
1446
+ for i in range(s_eq.nrows()):
1447
+ if s_eq.row_len(i) != o_eq.row_len(i):
1448
+ return False
1449
+ for i in range(s_eq.nrows()):
1450
+ if s_eq.row_len(i) > 1:
1451
+ break
1452
+ e = bitset_first(s_eq._M[i])
1453
+ s_eq2 = self.equitable_partition(s_eq._isolate(e))
1454
+ f = bitset_first(o_eq._M[i])
1455
+ while f >= 0:
1456
+ if self.is_isomorphic(other, s_eq2, other.equitable_partition(o_eq._isolate(f))):
1457
+ return True
1458
+ f = bitset_next(o_eq._M[i], f + 1)
1459
+ return False
1460
+
1461
+ def __neg__(self):
1462
+ """
1463
+ Negate the matrix.
1464
+
1465
+ In characteristic 2, this does nothing.
1466
+
1467
+ EXAMPLES::
1468
+
1469
+ sage: from sage.matroids.lean_matrix import *
1470
+ sage: A = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]]))
1471
+ sage: B = -A # indirect doctest
1472
+ sage: B == A
1473
+ True
1474
+ """
1475
+ return self.copy()
1476
+
1477
+ def __richcmp__(left, right, op):
1478
+ """
1479
+ Compare two matrices.
1480
+
1481
+ EXAMPLES::
1482
+
1483
+ sage: from sage.matroids.lean_matrix import *
1484
+ sage: A = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]]))
1485
+ sage: B = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]]))
1486
+ sage: C = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]]))
1487
+ sage: D = GenericMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]]))
1488
+ sage: E = BinaryMatrix(2, 3, Matrix(GF(2), [[1, 0, 0], [0, 1, 0]]))
1489
+ sage: A == B # indirect doctest
1490
+ True
1491
+ sage: A != C # indirect doctest
1492
+ True
1493
+ sage: A == D # indirect doctest
1494
+ False
1495
+ sage: E == A
1496
+ False
1497
+ """
1498
+ cdef long i
1499
+ if op not in [Py_EQ, Py_NE]:
1500
+ return NotImplemented
1501
+ if not isinstance(left, BinaryMatrix) or not isinstance(right, BinaryMatrix):
1502
+ return NotImplemented
1503
+ if op == Py_EQ:
1504
+ res = True
1505
+ if op == Py_NE:
1506
+ res = False
1507
+ # res gets inverted if matroids are deemed different.
1508
+ if left.nrows() != right.nrows():
1509
+ return not res
1510
+ if left.ncols() != right.ncols():
1511
+ return not res
1512
+ for i in range(left.nrows()):
1513
+ if not bitset_eq((<BinaryMatrix>left)._M[i], (<BinaryMatrix>right)._M[i]):
1514
+ return not res
1515
+ return res
1516
+
1517
+ def __reduce__(self):
1518
+ """
1519
+ Save the object.
1520
+
1521
+ EXAMPLES::
1522
+
1523
+ sage: from sage.matroids.lean_matrix import *
1524
+ sage: A = BinaryMatrix(2, 5)
1525
+ sage: A == loads(dumps(A)) # indirect doctest
1526
+ True
1527
+ sage: C = BinaryMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]]))
1528
+ sage: C == loads(dumps(C))
1529
+ True
1530
+ """
1531
+ import sage.matroids.unpickling
1532
+ version = 0
1533
+ M = []
1534
+ versionB = 0
1535
+ size = 0
1536
+ limbs = 0
1537
+ longsize = 0
1538
+ for i in range(self.nrows()):
1539
+ versionB, size, limbs, longsize, data = bitset_pickle(self._M[i])
1540
+ M.append(data)
1541
+ data = (self.nrows(), self.ncols(), versionB, size, limbs, longsize, M)
1542
+ return sage.matroids.unpickling.unpickle_binary_matrix, (version, data)
1543
+
1544
+ cdef bint GF3_not_defined = True
1545
+ cdef GF3, GF3_one, GF3_zero, GF3_minus_one
1546
+
1547
+
1548
+ cdef class TernaryMatrix(LeanMatrix):
1549
+ """
1550
+ Ternary matrix class. Entries are stored bit-packed into integers.
1551
+
1552
+ INPUT:
1553
+
1554
+ - ``m`` -- number of rows
1555
+ - ``n`` -- number of columns
1556
+ - ``M`` -- (default: ``None``) ``Matrix`` or ``TernaryMatrix`` instance.
1557
+ Assumption: dimensions of ``M`` are at most ``m`` by ``n``.
1558
+ - ``ring`` -- (default: ``None``) ignored
1559
+
1560
+ EXAMPLES::
1561
+
1562
+ sage: from sage.matroids.lean_matrix import *
1563
+ sage: A = TernaryMatrix(2, 2, Matrix(GF(7), [[0, 0], [0, 0]]))
1564
+ sage: B = TernaryMatrix(2, 2, ring=GF(5))
1565
+ sage: C = TernaryMatrix(2, 2)
1566
+ sage: A == B and A == C
1567
+ True
1568
+ """
1569
+ def __cinit__(self, long m, long n, M=None, ring=None):
1570
+ """
1571
+ Init internal data structures.
1572
+
1573
+ EXAMPLES::
1574
+
1575
+ sage: from sage.matroids.lean_matrix import *
1576
+ sage: A = TernaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest
1577
+ sage: A.nrows()
1578
+ 2
1579
+ """
1580
+ cdef long i, j
1581
+ global GF3, GF3_zero, GF3_one, GF3_minus_one, GF3_not_defined
1582
+ if GF3_not_defined:
1583
+ GF3 = GF(3)
1584
+ GF3_zero = GF3.zero()
1585
+ GF3_one = GF3.one()
1586
+ GF3_minus_one = GF3(2)
1587
+ GF3_not_defined = False
1588
+
1589
+ self._nrows = m
1590
+ self._ncols = n
1591
+ self._M0 = <bitset_t* > sig_malloc(self._nrows * sizeof(bitset_t))
1592
+ self._M1 = <bitset_t* > sig_malloc(self._nrows * sizeof(bitset_t))
1593
+
1594
+ if isinstance(M, TernaryMatrix):
1595
+ j = max(1, (<TernaryMatrix>M)._ncols)
1596
+ else:
1597
+ j = max(1, self._ncols)
1598
+ for i in range(self._nrows):
1599
+ bitset_init(self._M0[i], j)
1600
+ bitset_clear(self._M0[i])
1601
+ bitset_init(self._M1[i], j)
1602
+ bitset_clear(self._M1[i])
1603
+ bitset_init(self._s, j)
1604
+ bitset_init(self._t, j)
1605
+ bitset_init(self._u, j)
1606
+
1607
+ def __init__(self, long m, long n, M=None, ring=None):
1608
+ """
1609
+ See the class docstring for full specification.
1610
+
1611
+ EXAMPLES::
1612
+
1613
+ sage: from sage.matroids.lean_matrix import *
1614
+ sage: A = TernaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest
1615
+ sage: A.nrows()
1616
+ 2
1617
+ """
1618
+ cdef long i, j
1619
+ if M is not None:
1620
+ if isinstance(M, TernaryMatrix):
1621
+ for i in range((<TernaryMatrix>M)._nrows):
1622
+ bitset_copy(self._M0[i], (<TernaryMatrix>M)._M0[i])
1623
+ bitset_copy(self._M1[i], (<TernaryMatrix>M)._M1[i])
1624
+ return
1625
+ if isinstance(M, LeanMatrix):
1626
+ for i in range(M.nrows()):
1627
+ for j in range(M.ncols()):
1628
+ s = int((<LeanMatrix>M).get_unsafe(i, j)) % 3
1629
+ if s:
1630
+ bitset_add(self._M0[i], j)
1631
+ if s == 2:
1632
+ bitset_add(self._M1[i], j)
1633
+ return
1634
+ if isinstance(M, Matrix):
1635
+ for i in range(M.nrows()):
1636
+ for j in range(M.ncols()):
1637
+ s = int((<Matrix>M).get_unsafe(i, j)) % 3
1638
+ if s:
1639
+ bitset_add(self._M0[i], j)
1640
+ if s == 2:
1641
+ bitset_add(self._M1[i], j)
1642
+
1643
+ def __dealloc__(self):
1644
+ cdef long i
1645
+ for i in range(self._nrows):
1646
+ bitset_free(self._M0[i])
1647
+ bitset_free(self._M1[i])
1648
+ sig_free(self._M0)
1649
+ sig_free(self._M1)
1650
+ bitset_free(self._s)
1651
+ bitset_free(self._t)
1652
+ bitset_free(self._u)
1653
+
1654
+ def __repr__(self):
1655
+ r"""
1656
+ Return representation string.
1657
+
1658
+ EXAMPLES::
1659
+
1660
+ sage: from sage.matroids.lean_matrix import *
1661
+ sage: A = TernaryMatrix(2, 3, Matrix(GF(4, 'x'), [[0, 0], [0, 0]]))
1662
+ sage: repr(A) # indirect doctest
1663
+ '2 x 3 TernaryMatrix\n[000]\n[000]'
1664
+ """
1665
+ out = str(self._nrows) + ' x ' + str(self._ncols) + ' TernaryMatrix'
1666
+ cdef long i
1667
+ if self._ncols > 0:
1668
+ for i in range(self._nrows):
1669
+ out += '\n['
1670
+ for j in range(self._ncols):
1671
+ x = self.get(i, j)
1672
+ if x == 0:
1673
+ out += '0'
1674
+ if x == 1:
1675
+ out += '+'
1676
+ if x == -1:
1677
+ out += '-'
1678
+ out += ']'
1679
+ else:
1680
+ for i in range(self._nrows):
1681
+ out += '[]'
1682
+ return out
1683
+
1684
+ def _matrix_(self):
1685
+ """
1686
+ Return a matrix version.
1687
+
1688
+ EXAMPLES::
1689
+
1690
+ sage: from sage.matroids.lean_matrix import *
1691
+ sage: A = Matrix(GF(3), [[1, 0], [0, 1]])
1692
+ sage: A == TernaryMatrix(2, 2, A)._matrix_()
1693
+ True
1694
+ """
1695
+ cdef int i, j
1696
+ M = matrix(GF(3), self._nrows, self._ncols)
1697
+ for i in range(self._nrows):
1698
+ for j in range(self._ncols):
1699
+ M[i, j] = self.get(i, j)
1700
+ return M
1701
+
1702
+ cdef get_unsafe(self, long r, long c):
1703
+ global GF3_zero, GF3_one, GF3_minus_one
1704
+ if not bitset_in(self._M0[r], c):
1705
+ return GF3_zero
1706
+ if not bitset_in(self._M1[r], c):
1707
+ return GF3_one
1708
+ return GF3_minus_one
1709
+
1710
+ cdef int set_unsafe(self, long r, long c, x) except -1:
1711
+ self.set(r, c, x)
1712
+ return 0
1713
+
1714
+ cdef LeanMatrix copy(self): # Deprecated Sage matrix operation
1715
+ cdef TernaryMatrix T
1716
+ cdef long i
1717
+ T = TernaryMatrix(self._nrows, self._ncols)
1718
+ for i in range(self._nrows):
1719
+ bitset_copy(T._M0[i], self._M0[i])
1720
+ bitset_copy(T._M1[i], self._M1[i])
1721
+ return T
1722
+
1723
+ cdef int resize(self, long k) except -1: # Not a Sage matrix operation
1724
+ """
1725
+ Change number of rows to ``k``. Preserves data.
1726
+ """
1727
+ cdef long i
1728
+ cdef mp_bitcnt_t c
1729
+ if k < self._nrows:
1730
+ for i in range(k, self._nrows):
1731
+ bitset_free(self._M0[i])
1732
+ bitset_free(self._M1[i])
1733
+ self._nrows = k
1734
+ self._M0 = <bitset_t* > sig_realloc(self._M0, k * sizeof(bitset_t))
1735
+ self._M1 = <bitset_t* > sig_realloc(self._M1, k * sizeof(bitset_t))
1736
+ if k > self._nrows:
1737
+ self._M0 = <bitset_t* > sig_realloc(self._M0, k * sizeof(bitset_t))
1738
+ self._M1 = <bitset_t* > sig_realloc(self._M1, k * sizeof(bitset_t))
1739
+ c = max(1, self._ncols)
1740
+ for i in range(self._nrows, k):
1741
+ bitset_init(self._M0[i], c)
1742
+ bitset_clear(self._M0[i])
1743
+ bitset_init(self._M1[i], c)
1744
+ bitset_clear(self._M1[i])
1745
+ self._nrows = k
1746
+ return 0
1747
+
1748
+ cdef LeanMatrix stack(self, LeanMatrix MM):
1749
+ cdef TernaryMatrix R
1750
+ cdef TernaryMatrix M = <TernaryMatrix > MM
1751
+ cdef long i
1752
+ R = TernaryMatrix(self.nrows() + M.nrows(), self.ncols(), self)
1753
+ for i in range(M.nrows()):
1754
+ bitset_copy(R._M0[i + self.nrows()], M._M0[i])
1755
+ bitset_copy(R._M1[i + self.nrows()], M._M1[i])
1756
+ return R
1757
+
1758
+ cdef LeanMatrix augment(self, LeanMatrix MM):
1759
+ cdef TernaryMatrix R
1760
+ cdef TernaryMatrix M = <TernaryMatrix > MM
1761
+ cdef long i, j
1762
+ R = TernaryMatrix(self.nrows(), self.ncols() + M.ncols(), self)
1763
+ for i in range(R.nrows()):
1764
+ for j in range(M.ncols()):
1765
+ bitset_set_to(R._M0[i], self.ncols() + j, bitset_in(M._M0[i], j))
1766
+ bitset_set_to(R._M1[i], self.ncols() + j, bitset_in(M._M1[i], j))
1767
+ return R
1768
+
1769
+ cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation
1770
+ """
1771
+ Return the matrix obtained by prepending an identity matrix.
1772
+
1773
+ Special case of ``augment``.
1774
+ """
1775
+ cdef long i
1776
+ cdef TernaryMatrix A = TernaryMatrix(self._nrows, self._ncols + self._nrows)
1777
+ for i in range(self._nrows):
1778
+ bitset_lshift(A._M0[i], self._M0[i], self._nrows)
1779
+ bitset_lshift(A._M1[i], self._M1[i], self._nrows)
1780
+ A.set(i, i, 1)
1781
+ return A
1782
+
1783
+ cpdef base_ring(self):
1784
+ """
1785
+ Return GF(3).
1786
+
1787
+ EXAMPLES::
1788
+
1789
+ sage: from sage.matroids.lean_matrix import *
1790
+ sage: A = TernaryMatrix(3, 3)
1791
+ sage: A.base_ring()
1792
+ Finite Field of size 3
1793
+ """
1794
+ global GF3
1795
+ return GF3
1796
+
1797
+ cpdef characteristic(self):
1798
+ """
1799
+ Return the characteristic of ``self.base_ring()``.
1800
+
1801
+ EXAMPLES::
1802
+
1803
+ sage: from sage.matroids.lean_matrix import *
1804
+ sage: A = TernaryMatrix(3, 4)
1805
+ sage: A.characteristic()
1806
+ 3
1807
+ """
1808
+ return 3
1809
+
1810
+ cdef inline long get(self, long r, long c) noexcept: # Not a Sage matrix operation
1811
+ if not bitset_in(self._M0[r], c):
1812
+ return 0
1813
+ if not bitset_in(self._M1[r], c):
1814
+ return 1
1815
+ return -1
1816
+
1817
+ cdef inline int set(self, long r, long c, x) except -1: # Not a Sage matrix operation
1818
+ if x == 0:
1819
+ bitset_discard(self._M0[r], c)
1820
+ bitset_discard(self._M1[r], c)
1821
+ if x == 1:
1822
+ bitset_add(self._M0[r], c)
1823
+ bitset_discard(self._M1[r], c)
1824
+ if x == -1:
1825
+ bitset_add(self._M0[r], c)
1826
+ bitset_add(self._M1[r], c)
1827
+ return 0
1828
+
1829
+ cdef inline bint is_nonzero(self, long r, long c) except -2: # Not a Sage matrix operation
1830
+ return bitset_in(self._M0[r], c)
1831
+
1832
+ cdef inline bint _is_negative(self, long r, long c) noexcept:
1833
+ return bitset_in(self._M1[r], c)
1834
+
1835
+ cdef inline long row_len(self, long i) noexcept: # Not a Sage matrix operation
1836
+ """
1837
+ Return number of nonzero entries in row ``i``.
1838
+ """
1839
+ return bitset_len(self._M0[i])
1840
+
1841
+ cdef inline long row_inner_product(self, long i, long j) noexcept: # Not a Sage matrix operation
1842
+ """
1843
+ Return the inner product between rows ``i`` and ``j``.
1844
+ """
1845
+ cdef long u
1846
+ if i == j:
1847
+ return self.row_len(i) % 3
1848
+ bitset_intersection(self._s, self._M0[i], self._M0[j])
1849
+ bitset_symmetric_difference(self._t, self._M1[i], self._M1[j])
1850
+ bitset_intersection(self._t, self._t, self._s)
1851
+ u = (bitset_len(self._s) + bitset_len(self._t)) % 3
1852
+ return u
1853
+
1854
+ cdef int add_multiple_of_row_c(self, long x, long y, s, bint col_start) except -1:
1855
+ """
1856
+ Add ``s`` times row ``y`` to row ``x``. Argument ``col_start`` is
1857
+ ignored.
1858
+ """
1859
+ if s is None:
1860
+ bitset_symmetric_difference(self._s, self._M0[x], self._M1[y])
1861
+ bitset_symmetric_difference(self._t, self._M1[x], self._M0[y])
1862
+ bitset_intersection(self._u, self._s, self._t)
1863
+ bitset_symmetric_difference(self._s, self._s, self._M1[x])
1864
+ bitset_symmetric_difference(self._t, self._t, self._M1[y])
1865
+ bitset_union(self._M0[x], self._s, self._t)
1866
+ bitset_copy(self._M1[x], self._u)
1867
+ elif s == 1:
1868
+ bitset_symmetric_difference(self._s, self._M0[x], self._M1[y])
1869
+ bitset_symmetric_difference(self._t, self._M1[x], self._M0[y])
1870
+ bitset_intersection(self._u, self._s, self._t)
1871
+ bitset_symmetric_difference(self._s, self._s, self._M1[x])
1872
+ bitset_symmetric_difference(self._t, self._t, self._M1[y])
1873
+ bitset_union(self._M0[x], self._s, self._t)
1874
+ bitset_copy(self._M1[x], self._u)
1875
+ else: # -1, since we assume no 0-multiple ever gets added.
1876
+ self.row_subs(x, y)
1877
+ return 0
1878
+
1879
+ cdef void row_subs(self, long x, long y) noexcept: # Not a Sage matrix operation
1880
+ """
1881
+ Subtract row ``y`` from row ``x``.
1882
+ """
1883
+ bitset_symmetric_difference(self._s, self._M1[x], self._M1[y])
1884
+ bitset_symmetric_difference(self._t, self._M0[x], self._M0[y])
1885
+ bitset_union(self._M0[x], self._s, self._t)
1886
+ bitset_symmetric_difference(self._t, self._M1[y], self._t)
1887
+ bitset_symmetric_difference(self._s, self._M0[y], self._M1[x])
1888
+ bitset_intersection(self._M1[x], self._s, self._t)
1889
+
1890
+ cdef void _row_negate(self, long x) noexcept:
1891
+ bitset_symmetric_difference(self._M1[x], self._M1[x], self._M0[x])
1892
+
1893
+ cdef int swap_rows_c(self, long x, long y) except -1:
1894
+ bitset_copy(self._s, self._M0[x])
1895
+ bitset_copy(self._M0[x], self._M0[y])
1896
+ bitset_copy(self._M0[y], self._s)
1897
+ bitset_copy(self._t, self._M1[x])
1898
+ bitset_copy(self._M1[x], self._M1[y])
1899
+ bitset_copy(self._M1[y], self._t)
1900
+ return 0
1901
+
1902
+ cdef int pivot(self, long x, long y) except -1: # Not a Sage matrix operation
1903
+ """
1904
+ Row-reduce to make column ``y`` have a ``1`` in row ``x`` and zeroes
1905
+ elsewhere.
1906
+
1907
+ Assumption (not checked): the entry in row ``x``, column ``y`` is
1908
+ nonzero to start with.
1909
+
1910
+ .. NOTE::
1911
+
1912
+ This is different from what matroid theorists tend to call a
1913
+ pivot, as it does not involve a column exchange!
1914
+ """
1915
+ cdef long i
1916
+ if self._is_negative(x, y):
1917
+ self._row_negate(x)
1918
+ for i in range(self._nrows):
1919
+ if self.is_nonzero(i, y) and i != x:
1920
+ if self._is_negative(i, y):
1921
+ self.add_multiple_of_row_c(i, x, 1, 0)
1922
+ else:
1923
+ self.row_subs(i, x)
1924
+ return 0
1925
+
1926
+ cdef list nonzero_positions_in_row(self, long r):
1927
+ """
1928
+ Get coordinates of nonzero entries of row ``r``.
1929
+ """
1930
+ return bitset_list(self._M0[r])
1931
+
1932
+ cdef LeanMatrix transpose(self):
1933
+ """
1934
+ Return the transpose of the matrix.
1935
+ """
1936
+ cdef TernaryMatrix T
1937
+ cdef long i, j
1938
+ T = TernaryMatrix(self._ncols, self._nrows)
1939
+ for i in range(self._nrows):
1940
+ j = bitset_first(self._M0[i])
1941
+ while j >= 0:
1942
+ bitset_add(T._M0[j], i)
1943
+ if bitset_in(self._M1[i], j):
1944
+ bitset_add(T._M1[j], i)
1945
+ j = bitset_next(self._M0[i], j + 1)
1946
+ return T
1947
+
1948
+ cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other):
1949
+ """
1950
+ Return the product ``self * other``.
1951
+ """
1952
+ cdef TernaryMatrix M
1953
+ M = TernaryMatrix(self._nrows + 1, other.ncols())
1954
+ cdef long i, j
1955
+ for i in range(self._nrows):
1956
+ j = bitset_first(self._M0[i])
1957
+ while j >= 0:
1958
+ bitset_copy(M._M0[self._nrows], (<TernaryMatrix>other)._M0[j])
1959
+ bitset_copy(M._M1[self._nrows], (<TernaryMatrix>other)._M1[j])
1960
+ if bitset_in(self._M1[i], j):
1961
+ M.add_multiple_of_row_c(i, self._nrows, 1, 0)
1962
+ else:
1963
+ M.row_subs(i, self._nrows)
1964
+ j = bitset_next(self._M0[i], j + 1)
1965
+ M.resize(self._nrows)
1966
+ return M
1967
+
1968
+ cdef matrix_from_rows_and_columns_reordered(self, rows, columns):
1969
+ """
1970
+ Return a submatrix indexed by indicated rows and columns, as well as
1971
+ the column order of the resulting submatrix.
1972
+ """
1973
+ cdef TernaryMatrix A = TernaryMatrix(len(rows), len(columns))
1974
+ cdef long r, c, lc, lg
1975
+ cdef mp_bitcnt_t *cols
1976
+ # deal with trivial case
1977
+ lc = len(columns)
1978
+ if lc == 0:
1979
+ return A, []
1980
+ # write [c for c in columns if c<lc] as bitset `mask` and
1981
+ # write [c for c in columns if c>=lc] as array `cols`
1982
+ cdef bitset_t mask
1983
+ bitset_init(mask, lc)
1984
+ bitset_clear(mask)
1985
+ cols = <mp_bitcnt_t*>sig_malloc(lc*sizeof(mp_bitcnt_t))
1986
+ g = 0
1987
+ for c in columns:
1988
+ if c<lc:
1989
+ bitset_add(mask, c)
1990
+ else:
1991
+ cols[g] = c
1992
+ g = g+1
1993
+ # write [ c for c in range(lc) if c not in columns] as array `gaps`
1994
+ cdef mp_bitcnt_t *gaps
1995
+ gaps = <mp_bitcnt_t*>sig_malloc(lc*sizeof(mp_bitcnt_t))
1996
+ bitset_complement(mask, mask)
1997
+ g = 0
1998
+ c = bitset_first(mask)
1999
+ while c >= 0:
2000
+ gaps[g] = c
2001
+ g = g + 1
2002
+ c = bitset_next(mask, c + 1)
2003
+ lg = g
2004
+ bitset_complement(mask, mask)
2005
+ # copy relevant part of this matrix into A
2006
+ cdef bitset_t row0, row1, row0_2, row1_2
2007
+ cdef mp_bitcnt_t p, q
2008
+ for r in range(len(rows)):
2009
+ row0 = self._M0[rows[r]]
2010
+ row1 = self._M1[rows[r]]
2011
+ row0_2 = A._M0[r]
2012
+ row1_2 = A._M1[r]
2013
+ bitset_intersection(row0_2, row0, mask) # yes, this is safe
2014
+ bitset_intersection(row1_2, row1, mask) # yes, this is safe
2015
+ for g in range(lg):
2016
+ p = cols[g]
2017
+ if bitset_in(row0, p):
2018
+ q = gaps[g]
2019
+ bitset_add(row0_2, q)
2020
+ if bitset_in(row1, p):
2021
+ bitset_add(row1_2, q)
2022
+ # record order of the columns in list `order`
2023
+ cdef list order = list(range(lc))
2024
+ g = 0
2025
+ for g in range(lg):
2026
+ order[gaps[g]] = cols[g]
2027
+ # free up the two arrays and the bitset
2028
+ sig_free(gaps)
2029
+ sig_free(cols)
2030
+ bitset_free(mask)
2031
+ return A, order
2032
+
2033
+ def __richcmp__(left, right, op):
2034
+ """
2035
+ Compare two matrices.
2036
+
2037
+ EXAMPLES::
2038
+
2039
+ sage: from sage.matroids.lean_matrix import *
2040
+ sage: A = TernaryMatrix(2, 2, Matrix(GF(3), [[1, 0], [0, 1]]))
2041
+ sage: B = TernaryMatrix(2, 2, Matrix(GF(3), [[1, 0], [0, 1]]))
2042
+ sage: C = TernaryMatrix(2, 2, Matrix(GF(3), [[1, 1], [0, 1]]))
2043
+ sage: D = TernaryMatrix(2, 2, Matrix(GF(3), [[1, 1], [0, 1]]))
2044
+ sage: E = TernaryMatrix(2, 3, Matrix(GF(3), [[1, 0, 0], [0, 1, 0]]))
2045
+ sage: A == B # indirect doctest
2046
+ True
2047
+ sage: A != C # indirect doctest
2048
+ True
2049
+ sage: A == D # indirect doctest
2050
+ False
2051
+ sage: E == A
2052
+ False
2053
+ """
2054
+ cdef long i
2055
+ if op not in [Py_EQ, Py_NE]:
2056
+ return NotImplemented
2057
+ if not isinstance(left, TernaryMatrix) or not isinstance(right, TernaryMatrix):
2058
+ return NotImplemented
2059
+ if op == Py_EQ:
2060
+ res = True
2061
+ if op == Py_NE:
2062
+ res = False
2063
+ # res gets inverted if matroids are deemed different.
2064
+ if left.nrows() != right.nrows():
2065
+ return not res
2066
+ if left.ncols() != right.ncols():
2067
+ return not res
2068
+ for i in range(left.nrows()):
2069
+ if not bitset_eq((<TernaryMatrix>left)._M0[i], (<TernaryMatrix>right)._M0[i]):
2070
+ return not res
2071
+ if not bitset_eq((<TernaryMatrix>left)._M1[i], (<TernaryMatrix>right)._M1[i]):
2072
+ return not res
2073
+ return res
2074
+
2075
+ def __reduce__(self):
2076
+ """
2077
+ Save the object.
2078
+
2079
+ EXAMPLES::
2080
+
2081
+ sage: from sage.matroids.lean_matrix import *
2082
+ sage: A = TernaryMatrix(2, 5)
2083
+ sage: A == loads(dumps(A)) # indirect doctest
2084
+ True
2085
+ sage: C = TernaryMatrix(2, 2, Matrix(GF(3), [[1, 1], [0, 1]]))
2086
+ sage: C == loads(dumps(C))
2087
+ True
2088
+ """
2089
+ import sage.matroids.unpickling
2090
+ version = 0
2091
+ M0 = []
2092
+ M1 = []
2093
+ versionB = 0
2094
+ size = 0
2095
+ limbs = 0
2096
+ longsize = 0
2097
+ for i in range(self.nrows()):
2098
+ versionB, size, limbs, longsize, data = bitset_pickle(self._M0[i])
2099
+ M0.append(data)
2100
+ versionB, size, limbs, longsize, data = bitset_pickle(self._M1[i])
2101
+ M1.append(data)
2102
+ data = (self.nrows(), self.ncols(), versionB, size, limbs, longsize, M0, M1)
2103
+ return sage.matroids.unpickling.unpickle_ternary_matrix, (version, data)
2104
+
2105
+ cdef class QuaternaryMatrix(LeanMatrix):
2106
+ """
2107
+ Matrices over GF(4).
2108
+
2109
+ INPUT:
2110
+
2111
+ - ``m`` -- number of rows
2112
+ - ``n`` -- number of columns
2113
+ - ``M`` -- (default: ``None``) ``QuaternaryMatrix`` or ``LeanMatrix`` or
2114
+ (Sage) ``Matrix`` instance. If not given, new matrix will be filled with
2115
+ zeroes. Assumption: ``M`` has dimensions at most ``m`` times ``n``.
2116
+ - ``ring`` -- (default: ``None``) a copy of GF(4); useful for specifying
2117
+ generator name
2118
+
2119
+ EXAMPLES::
2120
+
2121
+ sage: from sage.matroids.lean_matrix import *
2122
+ sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]]))
2123
+ sage: B = QuaternaryMatrix(2, 2, GenericMatrix(2, 2, ring=GF(4, 'x')))
2124
+ sage: C = QuaternaryMatrix(2, 2, ring=GF(4, 'x'))
2125
+ sage: A == B and A == C
2126
+ True
2127
+ """
2128
+ def __cinit__(self, long m, long n, M=None, ring=None):
2129
+ """
2130
+ Init internal data structures.
2131
+
2132
+ EXAMPLES::
2133
+
2134
+ sage: from sage.matroids.lean_matrix import *
2135
+ sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest
2136
+ sage: A.nrows()
2137
+ 2
2138
+ """
2139
+ cdef long i, j
2140
+ self._nrows = m
2141
+ self._ncols = n
2142
+ self._M0 = <bitset_t* > sig_malloc(self._nrows * sizeof(bitset_t))
2143
+ self._M1 = <bitset_t* > sig_malloc(self._nrows * sizeof(bitset_t))
2144
+
2145
+ if isinstance(M, QuaternaryMatrix):
2146
+ j = max(1, (<QuaternaryMatrix>M)._ncols)
2147
+ else:
2148
+ j = max(1, self._ncols)
2149
+
2150
+ for i in range(self._nrows):
2151
+ bitset_init(self._M0[i], j)
2152
+ bitset_clear(self._M0[i])
2153
+ bitset_init(self._M1[i], j)
2154
+ bitset_clear(self._M1[i])
2155
+ bitset_init(self._s, j)
2156
+ bitset_init(self._t, j)
2157
+ bitset_init(self._u, j)
2158
+
2159
+ def __init__(self, long m, long n, M=None, ring=None):
2160
+ """
2161
+ See the class docstring for full specification.
2162
+
2163
+ EXAMPLES::
2164
+
2165
+ sage: from sage.matroids.lean_matrix import *
2166
+ sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest
2167
+ sage: A.nrows()
2168
+ 2
2169
+ """
2170
+ cdef long i, j
2171
+ if M is not None:
2172
+ if isinstance(M, QuaternaryMatrix):
2173
+ self._gf4 = (<QuaternaryMatrix>M)._gf4
2174
+ self._zero = self._gf4.zero()
2175
+ self._one = self._gf4.one()
2176
+ self._x_zero = self._gf4.gens()[0]
2177
+ self._x_one = self._x_zero + self._one
2178
+ for i in range((<QuaternaryMatrix>M)._nrows):
2179
+ bitset_copy(self._M0[i], (<QuaternaryMatrix>M)._M0[i])
2180
+ bitset_copy(self._M1[i], (<QuaternaryMatrix>M)._M1[i])
2181
+ elif isinstance(M, LeanMatrix):
2182
+ self._gf4 = (<LeanMatrix>M).base_ring()
2183
+ self._zero = self._gf4.zero()
2184
+ self._one = self._gf4.one()
2185
+ self._x_zero = self._gf4.gens()[0]
2186
+ self._x_one = self._x_zero + self._one
2187
+ for i in range(M.nrows()):
2188
+ for j in range(M.ncols()):
2189
+ self.set(i, j, (<LeanMatrix>M).get_unsafe(i, j))
2190
+ elif isinstance(M, Matrix):
2191
+ self._gf4 = (<Matrix>M).base_ring()
2192
+ self._zero = self._gf4.zero()
2193
+ self._one = self._gf4.one()
2194
+ self._x_zero = self._gf4.gens()[0]
2195
+ self._x_one = self._x_zero + self._one
2196
+ for i in range(M.nrows()):
2197
+ for j in range(M.ncols()):
2198
+ self.set(i, j, (<Matrix>M).get_unsafe(i, j))
2199
+ else:
2200
+ raise TypeError("unrecognized input type")
2201
+ else:
2202
+ self._gf4 = ring
2203
+ self._zero = self._gf4.zero()
2204
+ self._one = self._gf4.one()
2205
+ self._x_zero = self._gf4.gens()[0]
2206
+ self._x_one = self._x_zero + self._one
2207
+
2208
+ def __dealloc__(self):
2209
+ """
2210
+ Free internal data structures.
2211
+
2212
+ EXAMPLES::
2213
+
2214
+ sage: from sage.matroids.lean_matrix import *
2215
+ sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest
2216
+ sage: A.nrows()
2217
+ 2
2218
+ sage: A = None
2219
+ """
2220
+ cdef long i
2221
+ for i in range(self._nrows):
2222
+ bitset_free(self._M0[i])
2223
+ bitset_free(self._M1[i])
2224
+ sig_free(self._M0)
2225
+ sig_free(self._M1)
2226
+ bitset_free(self._s)
2227
+ bitset_free(self._t)
2228
+ bitset_free(self._u)
2229
+
2230
+ def __repr__(self):
2231
+ r"""
2232
+ Return representation string.
2233
+
2234
+ EXAMPLES::
2235
+
2236
+ sage: from sage.matroids.lean_matrix import *
2237
+ sage: A = QuaternaryMatrix(2, 3, Matrix(GF(4, 'x'), [[0, 0], [0, 0]]))
2238
+ sage: repr(A) # indirect doctest
2239
+ '2 x 3 QuaternaryMatrix\n[000]\n[000]'
2240
+ """
2241
+ out = str(self._nrows) + ' x ' + str(self._ncols) + ' QuaternaryMatrix'
2242
+ cdef long i
2243
+ if self._ncols > 0:
2244
+ for i in range(self._nrows):
2245
+ out += '\n['
2246
+ for j in range(self._ncols):
2247
+ x = self.get(i, j)
2248
+ if x == self._zero:
2249
+ out += '0'
2250
+ if x == self._one:
2251
+ out += '1'
2252
+ if x == self._x_zero:
2253
+ out += 'x'
2254
+ if x == self._x_one:
2255
+ out += 'y'
2256
+ out += ']'
2257
+ else:
2258
+ for i in range(self._nrows):
2259
+ out += '[]'
2260
+ return out
2261
+
2262
+ def _matrix_(self):
2263
+ """
2264
+ Return Sage Matrix version of ``self``.
2265
+
2266
+ EXAMPLES::
2267
+
2268
+ sage: from sage.matroids.lean_matrix import *
2269
+ sage: A = QuaternaryMatrix(2, 3, Matrix(GF(4, 'x'), [[0, 0], [0, 0]]))
2270
+ sage: A._matrix_()
2271
+ [0 0 0]
2272
+ [0 0 0]
2273
+ """
2274
+ M = matrix(self._gf4, self._nrows, self._ncols)
2275
+ for i in range(self._nrows):
2276
+ for j in range(self._ncols):
2277
+ M[i, j] = self.get(i, j)
2278
+ return M
2279
+
2280
+ cdef inline get(self, long r, long c): # Not a Sage matrix operation
2281
+ if bitset_in(self._M0[r], c):
2282
+ if bitset_in(self._M1[r], c):
2283
+ return self._x_one
2284
+ else:
2285
+ return self._one
2286
+ else:
2287
+ if bitset_in(self._M1[r], c):
2288
+ return self._x_zero
2289
+ else:
2290
+ return self._zero
2291
+
2292
+ cdef inline int set(self, long r, long c, x) except -1: # Not a Sage matrix operation
2293
+ if x == self._zero:
2294
+ bitset_discard(self._M0[r], c)
2295
+ bitset_discard(self._M1[r], c)
2296
+ if x == self._one:
2297
+ bitset_add(self._M0[r], c)
2298
+ bitset_discard(self._M1[r], c)
2299
+ if x == self._x_zero:
2300
+ bitset_discard(self._M0[r], c)
2301
+ bitset_add(self._M1[r], c)
2302
+ if x == self._x_one:
2303
+ bitset_add(self._M0[r], c)
2304
+ bitset_add(self._M1[r], c)
2305
+ return 0
2306
+
2307
+ cdef get_unsafe(self, long r, long c):
2308
+ return self.get(r, c)
2309
+
2310
+ cdef int set_unsafe(self, long r, long c, x) except -1:
2311
+ self.set(r, c, x)
2312
+ return 0
2313
+
2314
+ cdef inline bint is_nonzero(self, long r, long c) except -2: # Not a Sage matrix operation
2315
+ return bitset_in(self._M0[r], c) or bitset_in(self._M1[r], c)
2316
+
2317
+ cdef LeanMatrix copy(self): # Deprecated Sage matrix operation
2318
+ cdef QuaternaryMatrix T
2319
+ cdef long i
2320
+ T = QuaternaryMatrix(self._nrows, self._ncols, ring=self._gf4)
2321
+ for i in range(self._nrows):
2322
+ bitset_copy(T._M0[i], self._M0[i])
2323
+ bitset_copy(T._M1[i], self._M1[i])
2324
+ return T
2325
+
2326
+ cdef int resize(self, long k) except -1: # Not a Sage matrix operation
2327
+ """
2328
+ Change number of rows to ``k``. Preserves data.
2329
+ """
2330
+ cdef mp_bitcnt_t c
2331
+ if k < self._nrows:
2332
+ for i in range(k, self._nrows):
2333
+ bitset_free(self._M0[i])
2334
+ bitset_free(self._M1[i])
2335
+ self._nrows = k
2336
+ self._M0 = <bitset_t* > sig_realloc(self._M0, k * sizeof(bitset_t))
2337
+ self._M1 = <bitset_t* > sig_realloc(self._M1, k * sizeof(bitset_t))
2338
+ if k > self._nrows:
2339
+ self._M0 = <bitset_t* > sig_realloc(self._M0, k * sizeof(bitset_t))
2340
+ self._M1 = <bitset_t* > sig_realloc(self._M1, k * sizeof(bitset_t))
2341
+ c = max(1, self._ncols)
2342
+ for i in range(self._nrows, k):
2343
+ bitset_init(self._M0[i], c)
2344
+ bitset_clear(self._M0[i])
2345
+ bitset_init(self._M1[i], c)
2346
+ bitset_clear(self._M1[i])
2347
+ self._nrows = k
2348
+ return 0
2349
+
2350
+ cdef LeanMatrix stack(self, LeanMatrix MM):
2351
+ cdef QuaternaryMatrix R
2352
+ cdef QuaternaryMatrix M = <QuaternaryMatrix > MM
2353
+ cdef long i
2354
+ R = QuaternaryMatrix(self.nrows() + M.nrows(), self.ncols(), self)
2355
+ for i in range(self._nrows):
2356
+ bitset_copy(R._M0[i + self.nrows()], M._M0[i])
2357
+ bitset_copy(R._M1[i + self.nrows()], M._M1[i])
2358
+ return R
2359
+
2360
+ cdef LeanMatrix augment(self, LeanMatrix MM):
2361
+ cdef QuaternaryMatrix R
2362
+ cdef QuaternaryMatrix M = <QuaternaryMatrix > MM
2363
+ cdef long i, j
2364
+ R = QuaternaryMatrix(self.nrows(), self.ncols() + M.ncols(), self)
2365
+ for i in range(R.nrows()):
2366
+ for j in range(M.ncols()):
2367
+ bitset_set_to(R._M0[i], self.ncols() + j, bitset_in(M._M0[i], j))
2368
+ bitset_set_to(R._M1[i], self.ncols() + j, bitset_in(M._M1[i], j))
2369
+ return R
2370
+
2371
+ cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation
2372
+ """
2373
+ Return the matrix obtained by prepending an identity matrix. Special
2374
+ case of ``augment``.
2375
+ """
2376
+ cdef long i
2377
+ cdef QuaternaryMatrix A = QuaternaryMatrix(self._nrows, self._ncols + self._nrows, ring=self._gf4)
2378
+ for i in range(self._nrows):
2379
+ bitset_lshift(A._M0[i], self._M0[i], self._nrows)
2380
+ bitset_lshift(A._M1[i], self._M1[i], self._nrows)
2381
+ A.set(i, i, 1)
2382
+ return A
2383
+
2384
+ cpdef base_ring(self):
2385
+ """
2386
+ Return copy of `GF(4)` with appropriate generator.
2387
+
2388
+ EXAMPLES::
2389
+
2390
+ sage: from sage.matroids.lean_matrix import *
2391
+ sage: A = QuaternaryMatrix(2, 2, ring=GF(4, 'f'))
2392
+ sage: A.base_ring()
2393
+ Finite Field in f of size 2^2
2394
+ """
2395
+ return self._gf4
2396
+
2397
+ cpdef characteristic(self):
2398
+ """
2399
+ Return the characteristic of ``self.base_ring()``.
2400
+
2401
+ EXAMPLES::
2402
+
2403
+ sage: from sage.matroids.lean_matrix import *
2404
+ sage: A = QuaternaryMatrix(200, 5000, ring=GF(4, 'x'))
2405
+ sage: A.characteristic()
2406
+ 2
2407
+ """
2408
+ return 2
2409
+
2410
+ cdef inline long row_len(self, long i) except -1: # Not a Sage matrix operation
2411
+ """
2412
+ Return number of nonzero entries in row ``i``.
2413
+ """
2414
+ bitset_union(self._t, self._M0[i], self._M1[i])
2415
+ return bitset_len(self._t)
2416
+
2417
+ cdef inline row_inner_product(self, long i, long j): # Not a Sage matrix operation
2418
+ """
2419
+ Return the inner product between rows ``i`` and ``j``.
2420
+ """
2421
+ cdef bint a, b
2422
+ bitset_intersection(self._t, self._M0[i], self._M0[j])
2423
+ bitset_intersection(self._u, self._M0[i], self._M1[j])
2424
+ bitset_symmetric_difference(self._t, self._t, self._u)
2425
+ bitset_intersection(self._s, self._M1[i], self._M0[j])
2426
+ bitset_symmetric_difference(self._u, self._u, self._s)
2427
+ bitset_intersection(self._s, self._M1[i], self._M1[j])
2428
+ bitset_symmetric_difference(self._t, self._t, self._s)
2429
+ a = bitset_len(self._t) & 1
2430
+ b = bitset_len(self._u) & 1
2431
+ if a:
2432
+ if b:
2433
+ return self._x_one
2434
+ else:
2435
+ return self._one
2436
+ else:
2437
+ if b:
2438
+ return self._x_zero
2439
+ else:
2440
+ return self._zero
2441
+
2442
+ cdef int add_multiple_of_row_c(self, long x, long y, s, bint col_start) except -1:
2443
+ """
2444
+ Add ``s`` times row ``y`` to row ``x``. Argument ``col_start`` is
2445
+ ignored.
2446
+ """
2447
+ if s == self._zero:
2448
+ return 0
2449
+ if s == self._one or s is None:
2450
+ bitset_symmetric_difference(self._M0[x], self._M0[x], self._M0[y])
2451
+ bitset_symmetric_difference(self._M1[x], self._M1[x], self._M1[y])
2452
+ return 0
2453
+ if s == self._x_zero:
2454
+ bitset_symmetric_difference(self._M0[x], self._M0[x], self._M1[y])
2455
+ bitset_symmetric_difference(self._M1[x], self._M1[x], self._M0[y])
2456
+ bitset_symmetric_difference(self._M1[x], self._M1[x], self._M1[y])
2457
+ return 0
2458
+ if s == self._x_one:
2459
+ bitset_symmetric_difference(self._M0[x], self._M0[x], self._M0[y])
2460
+ bitset_symmetric_difference(self._M0[x], self._M0[x], self._M1[y])
2461
+ bitset_symmetric_difference(self._M1[x], self._M1[x], self._M0[y])
2462
+ return 0
2463
+
2464
+ cdef int swap_rows_c(self, long x, long y) except -1:
2465
+ bitset_copy(self._s, self._M0[x])
2466
+ bitset_copy(self._M0[x], self._M0[y])
2467
+ bitset_copy(self._M0[y], self._s)
2468
+ bitset_copy(self._t, self._M1[x])
2469
+ bitset_copy(self._M1[x], self._M1[y])
2470
+ bitset_copy(self._M1[y], self._t)
2471
+ return 0
2472
+
2473
+ cdef inline int _row_div(self, long x, object s) except -1:
2474
+ """
2475
+ Divide all entries in row ``x`` by ``s``.
2476
+ """
2477
+ if s == self._one:
2478
+ return 0
2479
+ if s == self._x_zero:
2480
+ bitset_symmetric_difference(self._M0[x], self._M0[x], self._M1[x])
2481
+ bitset_symmetric_difference(self._M1[x], self._M0[x], self._M1[x])
2482
+ return 0
2483
+ if s == self._x_one:
2484
+ bitset_symmetric_difference(self._M1[x], self._M0[x], self._M1[x])
2485
+ bitset_symmetric_difference(self._M0[x], self._M0[x], self._M1[x])
2486
+ return 0
2487
+ raise ZeroDivisionError
2488
+
2489
+ cdef int pivot(self, long x, long y) except -1: # Not a Sage matrix operation
2490
+ """
2491
+ Row-reduce to make column ``y`` have a ``1`` in row ``x`` and zeroes
2492
+ elsewhere.
2493
+
2494
+ Assumption (not checked): the entry in row ``x``, column ``y`` is
2495
+ nonzero to start with.
2496
+
2497
+ .. NOTE::
2498
+
2499
+ This is different from what matroid theorists tend to call a
2500
+ pivot, as it does not involve a column exchange!
2501
+ """
2502
+ cdef long i
2503
+ self._row_div(x, self.get(x, y))
2504
+ for i in range(self._nrows):
2505
+ if self.is_nonzero(i, y) and i != x:
2506
+ self.add_multiple_of_row_c(i, x, self.get(i, y), 0)
2507
+ return 0
2508
+
2509
+ cdef list nonzero_positions_in_row(self, long r):
2510
+ """
2511
+ Get coordinates of nonzero entries of row ``r``.
2512
+ """
2513
+ bitset_union(self._t, self._M0[r], self._M1[r])
2514
+ return bitset_list(self._t)
2515
+
2516
+ cdef LeanMatrix transpose(self):
2517
+ """
2518
+ Return the transpose of the matrix.
2519
+ """
2520
+ cdef QuaternaryMatrix T
2521
+ cdef long i, j
2522
+ T = QuaternaryMatrix(self._ncols, self._nrows, ring=self._gf4)
2523
+ for i in range(self._ncols):
2524
+ for j in range(self._nrows):
2525
+ T.set(i, j, self.get(j, i))
2526
+ return T
2527
+
2528
+ cdef void conjugate(self) noexcept: # Not a Sage matrix operation
2529
+ """
2530
+ Apply the nontrivial GF(4)-automorphism to the entries.
2531
+ """
2532
+ cdef long i
2533
+ for i in range(self._nrows):
2534
+ bitset_symmetric_difference(self._M0[i], self._M0[i], self._M1[i])
2535
+
2536
+ cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other):
2537
+ """
2538
+ Return the product ``self * other``.
2539
+ """
2540
+ cdef QuaternaryMatrix M, ot
2541
+ ot = <QuaternaryMatrix > other
2542
+ M = QuaternaryMatrix(self._nrows + 1, ot._ncols, ring=self._gf4)
2543
+ cdef long i, j
2544
+ for i in range(self._nrows):
2545
+ for j in range(self._ncols):
2546
+ bitset_copy(M._M0[self._nrows], ot._M0[j])
2547
+ bitset_copy(M._M1[self._nrows], ot._M1[j])
2548
+ M.add_multiple_of_row_c(i, self._nrows, self.get(i, j), 0)
2549
+ M.resize(self._nrows)
2550
+ return M
2551
+
2552
+ cdef matrix_from_rows_and_columns_reordered(self, rows, columns):
2553
+ """
2554
+ Return a submatrix indexed by indicated rows and columns, as well as
2555
+ the column order of the resulting submatrix.
2556
+ """
2557
+ cdef QuaternaryMatrix A = QuaternaryMatrix(len(rows), len(columns), ring=self._gf4)
2558
+ cdef long r, c, lc, lg
2559
+ cdef mp_bitcnt_t *cols
2560
+ # deal with trivial case
2561
+ lc = len(columns)
2562
+ if lc == 0:
2563
+ return A, []
2564
+ # write [c for c in columns if c<lc] as bitset `mask` and
2565
+ # write [c for c in columns if c>=lc] as array `cols`
2566
+ cdef bitset_t mask
2567
+ bitset_init(mask, lc)
2568
+ bitset_clear(mask)
2569
+ cols = <mp_bitcnt_t*>sig_malloc(lc*sizeof(mp_bitcnt_t))
2570
+ g = 0
2571
+ for c in columns:
2572
+ if c<lc:
2573
+ bitset_add(mask, c)
2574
+ else:
2575
+ cols[g] = c
2576
+ g = g+1
2577
+ # write [ c for c in range(lc) if c not in columns] as array `gaps`
2578
+ cdef mp_bitcnt_t *gaps
2579
+ gaps = <mp_bitcnt_t*>sig_malloc(lc*sizeof(mp_bitcnt_t))
2580
+ bitset_complement(mask, mask)
2581
+ g = 0
2582
+ c = bitset_first(mask)
2583
+ while c >= 0:
2584
+ gaps[g] = c
2585
+ g = g + 1
2586
+ c = bitset_next(mask, c + 1)
2587
+ lg = g
2588
+ bitset_complement(mask, mask)
2589
+ # copy relevant part of this matrix into A
2590
+ cdef bitset_t row0, row1, row0_2, row1_2
2591
+ cdef mp_bitcnt_t p, q
2592
+ for r in range(len(rows)):
2593
+ row0 = self._M0[rows[r]]
2594
+ row1 = self._M1[rows[r]]
2595
+ row0_2 = A._M0[r]
2596
+ row1_2 = A._M1[r]
2597
+ bitset_intersection(row0_2, row0, mask) # yes, this is safe
2598
+ bitset_intersection(row1_2, row1, mask)
2599
+ for g in range(lg):
2600
+ p = cols[g]
2601
+ q = gaps[g]
2602
+ if bitset_in(row0, p):
2603
+ bitset_add(row0_2, q)
2604
+ if bitset_in(row1, p):
2605
+ bitset_add(row1_2, q)
2606
+ # record order of the columns in list `order`
2607
+ cdef list order = list(range(lc))
2608
+ g = 0
2609
+ for g in range(lg):
2610
+ order[gaps[g]] = cols[g]
2611
+ # free up the two arrays and the bitset
2612
+ sig_free(gaps)
2613
+ sig_free(cols)
2614
+ bitset_free(mask)
2615
+ return A, order
2616
+
2617
+ def __neg__(self):
2618
+ """
2619
+ Negate the matrix.
2620
+
2621
+ In characteristic 2, this does nothing.
2622
+
2623
+ EXAMPLES::
2624
+
2625
+ sage: from sage.matroids.lean_matrix import *
2626
+ sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[1, 0], [0, 1]]))
2627
+ sage: B = -A # indirect doctest
2628
+ sage: B == A
2629
+ True
2630
+ """
2631
+ return self.copy()
2632
+
2633
+ def __richcmp__(left, right, op):
2634
+ """
2635
+ Compare two matrices.
2636
+
2637
+ EXAMPLES::
2638
+
2639
+ sage: from sage.matroids.lean_matrix import *
2640
+ sage: A = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[1, 0], [0, 1]]))
2641
+ sage: B = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[1, 0], [0, 1]]))
2642
+ sage: C = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[1, 1], [0, 1]]))
2643
+ sage: D = QuaternaryMatrix(2, 2, Matrix(GF(4, 'y'), [[1, 0], [0, 1]]))
2644
+ sage: E = QuaternaryMatrix(2, 3, Matrix(GF(4, 'x'), [[1, 0, 0], [0, 1, 0]]))
2645
+ sage: A == B # indirect doctest
2646
+ True
2647
+ sage: A != C # indirect doctest
2648
+ True
2649
+ sage: A == D # indirect doctest
2650
+ False
2651
+ sage: E == A
2652
+ False
2653
+ """
2654
+ cdef long i
2655
+ if op not in [Py_EQ, Py_NE]:
2656
+ return NotImplemented
2657
+ if not isinstance(left, QuaternaryMatrix) or not isinstance(right, QuaternaryMatrix):
2658
+ return NotImplemented
2659
+ if op == Py_EQ:
2660
+ res = True
2661
+ if op == Py_NE:
2662
+ res = False
2663
+ if left.base_ring() != right.base_ring():
2664
+ return not res
2665
+ # res gets inverted if matroids are deemed different.
2666
+ if left.nrows() != right.nrows():
2667
+ return not res
2668
+ if left.ncols() != right.ncols():
2669
+ return not res
2670
+ for i in range(left.nrows()):
2671
+ if not bitset_eq((<QuaternaryMatrix>left)._M0[i], (<QuaternaryMatrix>right)._M0[i]):
2672
+ return not res
2673
+ if not bitset_eq((<QuaternaryMatrix>left)._M1[i], (<QuaternaryMatrix>right)._M1[i]):
2674
+ return not res
2675
+ return res
2676
+
2677
+ def __reduce__(self):
2678
+ """
2679
+ Save the object.
2680
+
2681
+ EXAMPLES::
2682
+
2683
+ sage: from sage.matroids.lean_matrix import *
2684
+ sage: A = QuaternaryMatrix(2, 5, ring=GF(4, 'x'))
2685
+ sage: A == loads(dumps(A)) # indirect doctest
2686
+ True
2687
+ sage: C = QuaternaryMatrix(2, 2, Matrix(GF(4, 'x'), [[1, 1], [0, 1]]))
2688
+ sage: C == loads(dumps(C))
2689
+ True
2690
+ """
2691
+ import sage.matroids.unpickling
2692
+ version = 0
2693
+ M0 = []
2694
+ M1 = []
2695
+ versionB = 0
2696
+ size = 0
2697
+ limbs = 0
2698
+ longsize = 0
2699
+ ring = self._gf4
2700
+ for i in range(self.nrows()):
2701
+ versionB, size, limbs, longsize, data = bitset_pickle(self._M0[i])
2702
+ M0.append(data)
2703
+ versionB, size, limbs, longsize, data = bitset_pickle(self._M1[i])
2704
+ M1.append(data)
2705
+ data = (self.nrows(), self.ncols(), ring, versionB, size, limbs, longsize, M0, M1)
2706
+ return sage.matroids.unpickling.unpickle_quaternary_matrix, (version, data)
2707
+
2708
+ cpdef GenericMatrix generic_identity(n, ring):
2709
+ """
2710
+ Return a GenericMatrix instance containing the `n \times n` identity
2711
+ matrix over ``ring``.
2712
+
2713
+ EXAMPLES::
2714
+
2715
+ sage: from sage.matroids.lean_matrix import *
2716
+ sage: A = generic_identity(2, QQ)
2717
+ sage: Matrix(A)
2718
+ [1 0]
2719
+ [0 1]
2720
+ """
2721
+ cdef long i
2722
+ cdef GenericMatrix A = GenericMatrix(n, n, ring=ring)
2723
+ for i in range(n):
2724
+ A.set_unsafe(i, i, A._one)
2725
+ return A
2726
+
2727
+ # Integer matrices
2728
+
2729
+ cdef class PlusMinusOneMatrix(LeanMatrix):
2730
+ r"""
2731
+ Matrix with nonzero entries of `\pm 1`.
2732
+
2733
+ INPUT:
2734
+
2735
+ - ``nrows`` -- number of rows
2736
+ - ``ncols`` -- number of columns
2737
+ - ``M`` -- (default: ``None``) a ``Matrix`` or ``GenericMatrix`` of
2738
+ dimensions at most ``m*n``
2739
+
2740
+ .. NOTE::
2741
+
2742
+ This class is intended for internal use by the
2743
+ :class:`~sage.matroids.linear_matroid.LinearMatroid` class
2744
+ only. Hence it does not derive from ``SageObject``.
2745
+ If ``A`` is a :class:`~sage.matroids.lean_matrix.LeanMatrix`
2746
+ instance, and you need access from other parts of Sage,
2747
+ use ``Matrix(A)`` instead.
2748
+
2749
+ This class is mainly intended for use with the
2750
+ :class:`~sage.matroids.linear_matroid.RegularMatroid` class,
2751
+ so entries are assumed to be `\pm 1` or `0`. No overflow checking
2752
+ takes place!
2753
+
2754
+ EXAMPLES::
2755
+
2756
+ sage: # needs sage.graphs
2757
+ sage: M = Matroid(graphs.CompleteGraph(4).incidence_matrix(oriented=True), # indirect doctest
2758
+ ....: regular=True)
2759
+ sage: M.is_isomorphic(matroids.Wheel(3))
2760
+ True
2761
+ """
2762
+ def __cinit__(self, long nrows, long ncols, M=None, ring=None):
2763
+ """
2764
+ Init internal data structures.
2765
+
2766
+ EXAMPLES::
2767
+
2768
+ sage: from sage.matroids.lean_matrix import *
2769
+ sage: A = PlusMinusOneMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest
2770
+ sage: A.nrows()
2771
+ 2
2772
+ """
2773
+ self._nrows = nrows
2774
+ self._ncols = ncols
2775
+ self._entries = <int* > sig_malloc(nrows * ncols * sizeof(int))
2776
+ memset(self._entries, 0, nrows * ncols * sizeof(int))
2777
+
2778
+ def __init__(self, long nrows, long ncols, M=None, ring=None):
2779
+ """
2780
+ See the class docstring for full information.
2781
+
2782
+ EXAMPLES::
2783
+
2784
+ sage: from sage.matroids.lean_matrix import *
2785
+ sage: A = PlusMinusOneMatrix(2, 2, Matrix(GF(3), [[0, 0], [0, 0]])) # indirect doctest
2786
+ sage: B = PlusMinusOneMatrix(2, 2)
2787
+ sage: A == B
2788
+ True
2789
+ """
2790
+ cdef long i, j
2791
+ if M is not None:
2792
+ if isinstance(M, PlusMinusOneMatrix):
2793
+ for i in range(M.nrows()):
2794
+ memcpy(self._entries + i * self._ncols, (<PlusMinusOneMatrix>M)._entries + i * (<PlusMinusOneMatrix>M)._ncols, (<PlusMinusOneMatrix>M)._ncols * sizeof(int))
2795
+ elif isinstance(M, LeanMatrix):
2796
+ for i in range(M.nrows()):
2797
+ for j in range(M.ncols()):
2798
+ self._entries[i * self._ncols + j] = int((<LeanMatrix>M).get_unsafe(i, j))
2799
+ else: # Sage Matrix or otherwise
2800
+ for i in range(M.nrows()):
2801
+ for j in range(M.ncols()):
2802
+ self._entries[i * self._ncols + j] = int(M[i, j])
2803
+
2804
+ def __dealloc__(self):
2805
+ """
2806
+ Free internal data structures.
2807
+
2808
+ EXAMPLES::
2809
+
2810
+ sage: from sage.matroids.lean_matrix import *
2811
+ sage: A = PlusMinusOneMatrix(2, 2, Matrix(GF(4, 'x'), [[0, 0], [0, 0]])) # indirect doctest
2812
+ sage: A.nrows()
2813
+ 2
2814
+ sage: A = None
2815
+ """
2816
+ sig_free(self._entries)
2817
+
2818
+ def __repr__(self):
2819
+ """
2820
+ Return representation.
2821
+
2822
+ EXAMPLES::
2823
+
2824
+ sage: from sage.matroids.lean_matrix import *
2825
+ sage: A = PlusMinusOneMatrix(2, 2, Matrix(GF(3), [[0, 0], [0, 0]]))
2826
+ sage: repr(A) # indirect doctest
2827
+ 'PlusMinusOneMatrix instance with 2 rows and 2 columns'
2828
+ """
2829
+ return "PlusMinusOneMatrix instance with {} rows and {} columns".format(self._nrows, self._ncols)
2830
+
2831
+ cdef inline int get(self, long r, long c) noexcept: # Not a Sage matrix operation
2832
+ return self._entries[r * self._ncols + c]
2833
+
2834
+ cdef inline void set(self, long r, long c, int x) noexcept: # Not a Sage matrix operation
2835
+ self._entries[r * self._ncols + c] = x
2836
+
2837
+ cdef get_unsafe(self, long r, long c):
2838
+ """
2839
+ Return a Sage Integer, for safety down the line when dividing.
2840
+
2841
+ EXAMPLES:
2842
+
2843
+ By returning an Integer rather than an int, the following test no
2844
+ longer fails::
2845
+
2846
+ sage: from sage.matroids.advanced import *
2847
+ sage: M = RegularMatroid(matrix([
2848
+ ....: (1, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0),
2849
+ ....: (0, 1, 0, 0, -1, 1, 0, 0, 0, 0, 0),
2850
+ ....: (0, 0, 1, 0, 0, -1, 1, 0, 0, 1, 0),
2851
+ ....: (0, 0, 0, 1, 0, 0, -1, 1, 0, 0, 0),
2852
+ ....: (0, 0, 0, 0, 0, 0, -1, 0, 1, -1, 0),
2853
+ ....: (0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 1)]))
2854
+ sage: all(N.is_valid() for N in M.linear_extensions(F=[4, 10]))
2855
+ True
2856
+ """
2857
+ return Integer(self.get(r, c))
2858
+
2859
+ cdef int set_unsafe(self, long r, long c, x) except -1:
2860
+ self.set(r, c, x)
2861
+ return 0
2862
+
2863
+ cdef bint is_nonzero(self, long r, long c) except -2: # Not a Sage matrix operation
2864
+ return self.get(r, c) != 0
2865
+
2866
+ cdef LeanMatrix copy(self): # Deprecated Sage matrix operation
2867
+ cdef PlusMinusOneMatrix M = PlusMinusOneMatrix(self._nrows, self._ncols)
2868
+ memcpy(M._entries, self._entries, self._nrows * self._ncols * sizeof(int))
2869
+ return M
2870
+
2871
+ cdef int resize(self, long k) except -1: # Not a Sage matrix operation
2872
+ """
2873
+ Change number of rows to ``k``. Preserves data.
2874
+ """
2875
+ cdef long l = self._ncols * (self._nrows - k)
2876
+ if l > 0:
2877
+ sig_realloc(self._entries, self._ncols * k * sizeof(int))
2878
+ memset(self._entries + self._nrows * self._ncols, 0, l * self._ncols * sizeof(int))
2879
+ elif l < 0:
2880
+ sig_realloc(self._entries, self._ncols * k * sizeof(int))
2881
+ self._nrows = k
2882
+ return 0
2883
+
2884
+ cdef LeanMatrix stack(self, LeanMatrix M):
2885
+ """
2886
+ Warning: assumes ``M`` is a PlusMinusOneMatrix instance of right
2887
+ dimensions!
2888
+ """
2889
+ cdef PlusMinusOneMatrix A
2890
+ A = PlusMinusOneMatrix(self._nrows + M.nrows(), self._ncols)
2891
+ memcpy(A._entries, self._entries, self._nrows * self._ncols * sizeof(int))
2892
+ memcpy(A._entries + self._nrows * self._ncols, (<PlusMinusOneMatrix>M)._entries, M.nrows() * M.ncols() * sizeof(int))
2893
+ return A
2894
+
2895
+ cdef LeanMatrix augment(self, LeanMatrix M):
2896
+ """
2897
+ Warning: assumes ``M`` is a PlusMinusOneMatrix instance!
2898
+ """
2899
+ cdef PlusMinusOneMatrix A
2900
+ cdef long i
2901
+ cdef long Mn = M.ncols()
2902
+ A = PlusMinusOneMatrix(self._nrows, self._ncols + Mn)
2903
+ for i in range(self._nrows):
2904
+ memcpy(A._entries + i * A._ncols, self._entries + i * self._ncols, self._ncols * sizeof(int))
2905
+ memcpy(A._entries + (i * A._ncols + self._ncols), (<PlusMinusOneMatrix>M)._entries + i * Mn, Mn * sizeof(int))
2906
+ return A
2907
+
2908
+ cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation
2909
+ cdef PlusMinusOneMatrix A = PlusMinusOneMatrix(self._nrows, self._ncols + self._nrows, ring=self._base_ring)
2910
+ cdef long i
2911
+ for i in range(self._nrows):
2912
+ A._entries[i * A._ncols + i] = 1
2913
+ memcpy(A._entries + (i * A._ncols + self._nrows), self._entries + i * self._ncols, self._ncols * sizeof(int))
2914
+ return A
2915
+
2916
+ cpdef base_ring(self):
2917
+ """
2918
+ Return the base ring of ``self``.
2919
+
2920
+ EXAMPLES::
2921
+
2922
+ sage: from sage.matroids.lean_matrix import PlusMinusOneMatrix
2923
+ sage: A = PlusMinusOneMatrix(3, 4)
2924
+ sage: A.base_ring()
2925
+ Integer Ring
2926
+ """
2927
+ return ZZ
2928
+
2929
+ cpdef characteristic(self):
2930
+ """
2931
+ Return the characteristic of ``self.base_ring()``.
2932
+
2933
+ EXAMPLES::
2934
+
2935
+ sage: from sage.matroids.lean_matrix import PlusMinusOneMatrix
2936
+ sage: A = PlusMinusOneMatrix(3, 4)
2937
+ sage: A.characteristic()
2938
+ 0
2939
+ """
2940
+ return 0
2941
+
2942
+ cdef inline long row_len(self, long i) except -1: # Not a Sage matrix operation
2943
+ """
2944
+ Return number of nonzero entries in row ``i``.
2945
+ """
2946
+ cdef long k
2947
+ cdef long res = 0
2948
+ for k in range(self._ncols):
2949
+ if self.get(i, k):
2950
+ res += 1
2951
+ return res
2952
+
2953
+ cdef inline row_inner_product(self, long i, long j): # Not a Sage matrix operation
2954
+ """
2955
+ Return the inner product between rows ``i`` and ``j``.
2956
+ """
2957
+ cdef long k
2958
+ cdef int res = 0
2959
+ for k in range(self._ncols):
2960
+ res += self.get(i, k) * self.get(j, k)
2961
+ return res
2962
+
2963
+ cdef int add_multiple_of_row_c(self, long x, long y, s, bint col_start) except -1:
2964
+ """
2965
+ Add ``s`` times row ``y`` to row ``x``. Argument ``col_start`` is
2966
+ ignored.
2967
+ """
2968
+ cdef long i
2969
+ cdef int sval
2970
+ if s is None:
2971
+ for i in range(self._ncols):
2972
+ self.set(x, i, self.get(x, i) + self.get(y, i))
2973
+ else:
2974
+ sval = s
2975
+ for i in range(self._ncols):
2976
+ self.set(x, i, self.get(x, i) + sval * self.get(y, i))
2977
+ return 0
2978
+
2979
+ cdef int swap_rows_c(self, long x, long y) except -1:
2980
+ """
2981
+ Swap rows ``x`` and ``y``.
2982
+ """
2983
+ cdef int* tmp
2984
+ tmp = <int* > sig_malloc(self._ncols * sizeof(int))
2985
+ if not tmp:
2986
+ raise MemoryError
2987
+ memcpy(tmp, self._entries + x * self._ncols, self._ncols * sizeof(int))
2988
+ memcpy(self._entries + x * self._ncols, self._entries + y * self._ncols, self._ncols * sizeof(int))
2989
+ memcpy(self._entries + y * self._ncols, tmp, self._ncols * sizeof(int))
2990
+ sig_free(tmp)
2991
+ return 0
2992
+
2993
+ cdef int rescale_row_c(self, long x, s, bint col_start) except -1:
2994
+ """
2995
+ Scale row ``x`` by ``s``. Argument ``col_start`` is for Sage
2996
+ compatibility, and is ignored.
2997
+ """
2998
+ cdef long i
2999
+ cdef int sval = s
3000
+ for i in range(self._ncols):
3001
+ self.set(x, i, sval * self.get(x, i))
3002
+ return 0
3003
+
3004
+ cdef int rescale_column_c(self, long y, s, bint start_row) except -1:
3005
+ """
3006
+ Scale column ``y`` by ``s``. Argument ``start_row`` is for Sage
3007
+ compatibility, and is ignored.
3008
+ """
3009
+ cdef long j
3010
+ cdef int sval = s
3011
+ for j in range(self._nrows):
3012
+ self.set(j, y, self.get(j, y) * sval)
3013
+ return 0
3014
+
3015
+ cdef int pivot(self, long x, long y) except -1: # Not a Sage matrix operation
3016
+ """
3017
+ Row-reduce to make column ``y`` have a ``1`` in row ``x`` and zeroes
3018
+ elsewhere.
3019
+
3020
+ Assumption (not checked): the entry in row ``x``, column ``y`` is
3021
+ invertible (so 1 or -1) to start with.
3022
+
3023
+ .. NOTE::
3024
+
3025
+ This is different from what matroid theorists tend to call a
3026
+ pivot, as it does not involve a column exchange!
3027
+ """
3028
+ cdef long i
3029
+ cdef int a, s
3030
+ a = self.get(x, y) # 1 or -1, so inverse is equal to itself
3031
+ self.rescale_row_c(x, a, 0)
3032
+ for i in range(self._nrows):
3033
+ s = self.get(i, y)
3034
+ if s and i != x:
3035
+ self.add_multiple_of_row_c(i, x, -s, 0)
3036
+ return 0
3037
+
3038
+ cdef list nonzero_positions_in_row(self, long r):
3039
+ """
3040
+ Get coordinates of nonzero entries of row ``r``.
3041
+ """
3042
+ cdef long j
3043
+ cdef list res = []
3044
+ for j in range(r * self._ncols, (r + 1) * self._ncols):
3045
+ if self._entries[j]:
3046
+ res.append(j - r * self._ncols)
3047
+ return res
3048
+
3049
+ cdef LeanMatrix transpose(self):
3050
+ """
3051
+ Return the transpose of the matrix.
3052
+ """
3053
+ cdef PlusMinusOneMatrix A
3054
+ cdef long i, j
3055
+ A = PlusMinusOneMatrix(self._ncols, self._nrows)
3056
+ for i in range(self._nrows):
3057
+ for j in range(self._ncols):
3058
+ A.set(j, i, self.get(i, j))
3059
+ return A
3060
+
3061
+ cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other):
3062
+ """
3063
+ Return the product ``self * other``.
3064
+ """
3065
+ cdef PlusMinusOneMatrix A, ot
3066
+ cdef long i, j, t
3067
+ cdef int s
3068
+ ot = <PlusMinusOneMatrix> other
3069
+ A = PlusMinusOneMatrix(self._nrows, ot._ncols)
3070
+ for i in range(A._nrows):
3071
+ for j in range(A._ncols):
3072
+ s = 0
3073
+ for t in range(self._ncols):
3074
+ s += self.get(i, t) * ot.get(t, j)
3075
+ A.set(i, j, s)
3076
+ return A
3077
+
3078
+ cdef list gauss_jordan_reduce(self, columns): # Not a Sage matrix operation
3079
+ """
3080
+ Row-reduce so the lexicographically first basis indexes an identity
3081
+ submatrix.
3082
+ """
3083
+ cdef long r = 0
3084
+ cdef list P = []
3085
+ cdef long a, c, p, row
3086
+ cdef bint is_pivot
3087
+ for c in columns:
3088
+ is_pivot = False
3089
+ for row from r <= row < self._nrows:
3090
+ a = self.get(row, c)
3091
+ if a:
3092
+ if a < -1 or a > 1:
3093
+ raise ValueError("not a totally unimodular matrix")
3094
+ is_pivot = True
3095
+ p = row
3096
+ break
3097
+ if is_pivot:
3098
+ self.swap_rows_c(p, r)
3099
+ self.rescale_row_c(r, self.get(r, c), 0) # Inverting not needed for integers -1, 1
3100
+ for row in range(self._nrows):
3101
+ if row != r and self.is_nonzero(row, c):
3102
+ self.add_multiple_of_row_c(row, r, -self.get(row, c), 0)
3103
+ P.append(c)
3104
+ r += 1
3105
+ if r == self._nrows:
3106
+ break
3107
+ return P
3108
+
3109
+ def __richcmp__(left, right, op):
3110
+ """
3111
+ Compare two matrices.
3112
+
3113
+ EXAMPLES::
3114
+
3115
+ sage: from sage.matroids.lean_matrix import *
3116
+ sage: A = PlusMinusOneMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]]))
3117
+ sage: B = PlusMinusOneMatrix(2, 2, Matrix(GF(2), [[1, 0], [0, 1]]))
3118
+ sage: C = PlusMinusOneMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]]))
3119
+ sage: D = PlusMinusOneMatrix(2, 2, Matrix(GF(2), [[1, 1], [0, 1]]))
3120
+ sage: E = PlusMinusOneMatrix(2, 3, Matrix(GF(2), [[1, 0, 0], [0, 1, 0]]))
3121
+ sage: A == B # indirect doctest
3122
+ True
3123
+ sage: A != C # indirect doctest
3124
+ True
3125
+ sage: A == D # indirect doctest
3126
+ False
3127
+ sage: E == A
3128
+ False
3129
+ """
3130
+ cdef long i
3131
+ if op not in [Py_EQ, Py_NE]:
3132
+ return NotImplemented
3133
+ if not isinstance(left, PlusMinusOneMatrix) or not isinstance(right, PlusMinusOneMatrix):
3134
+ return NotImplemented
3135
+ if op == Py_EQ:
3136
+ res = True
3137
+ if op == Py_NE:
3138
+ res = False
3139
+ # res gets inverted if matroids are deemed different.
3140
+ if left.nrows() != right.nrows():
3141
+ return not res
3142
+ if left.ncols() != right.ncols():
3143
+ return not res
3144
+ for i in range(left.nrows() * left.ncols()):
3145
+ if (<PlusMinusOneMatrix>left)._entries[i] != (<PlusMinusOneMatrix>right)._entries[i]:
3146
+ return not res
3147
+ return res
3148
+
3149
+ def __reduce__(self):
3150
+ """
3151
+ Save the object.
3152
+
3153
+ EXAMPLES::
3154
+
3155
+ sage: from sage.matroids.lean_matrix import *
3156
+ sage: A = PlusMinusOneMatrix(2, 5)
3157
+ sage: A == loads(dumps(A)) # indirect doctest
3158
+ True
3159
+ sage: C = PlusMinusOneMatrix(2, 2, Matrix(GF(3), [[1, 1], [0, 1]]))
3160
+ sage: C == loads(dumps(C))
3161
+ True
3162
+ """
3163
+ import sage.matroids.unpickling
3164
+ cdef list entries = []
3165
+ cdef long i
3166
+ for i in range(self._nrows * self._ncols):
3167
+ entries.append(self._entries[i])
3168
+ version = 0
3169
+ data = (self.nrows(), self.ncols(), entries)
3170
+ return sage.matroids.unpickling.unpickle_plus_minus_one_matrix, (version, data)
3171
+
3172
+ # Rational matrices
3173
+
3174
+ cdef class RationalMatrix(LeanMatrix):
3175
+ """
3176
+ Matrix over the rationals.
3177
+
3178
+ INPUT:
3179
+
3180
+ - ``nrows`` -- number of rows
3181
+ - ``ncols`` -- number of columns
3182
+ - ``M`` -- (default: ``None``) a ``Matrix`` or ``GenericMatrix`` of
3183
+ dimensions at most ``m * n``
3184
+
3185
+ EXAMPLES::
3186
+
3187
+ sage: # needs sage.graphs
3188
+ sage: M = Matroid(graphs.CompleteGraph(4).incidence_matrix(oriented=True)) # indirect doctest
3189
+ sage: M.is_isomorphic(matroids.Wheel(3))
3190
+ True
3191
+ """
3192
+ def __cinit__(self, long nrows, long ncols, M=None, ring=None):
3193
+ """
3194
+ Init internal data structures.
3195
+
3196
+ EXAMPLES::
3197
+
3198
+ sage: from sage.matroids.lean_matrix import RationalMatrix
3199
+ sage: A = RationalMatrix(2, 2, Matrix(GF(5), [[0, 0], [0, 0]]))
3200
+ sage: A.nrows()
3201
+ 2
3202
+ """
3203
+ cdef Py_ssize_t i
3204
+ cdef mpq_t* entries = <mpq_t*> sig_malloc(nrows * ncols * sizeof(mpq_t))
3205
+ self._nrows = nrows
3206
+ self._ncols = ncols
3207
+ sig_on()
3208
+ for i in range(nrows * ncols):
3209
+ mpq_init(entries[i])
3210
+ sig_off()
3211
+ self._entries = entries
3212
+
3213
+ def __init__(self, long nrows, long ncols, M=None, ring=None):
3214
+ """
3215
+ See the class docstring for full information.
3216
+
3217
+ EXAMPLES::
3218
+
3219
+ sage: from sage.matroids.lean_matrix import RationalMatrix, PlusMinusOneMatrix
3220
+ sage: A = RationalMatrix(2, 2, Matrix(GF(3), [[0, 0], [0, 0]]))
3221
+ sage: B = RationalMatrix(2, 2)
3222
+ sage: A == B
3223
+ True
3224
+
3225
+ sage: IM = PlusMinusOneMatrix(2, 2, Matrix([[-1, 0], [0, 1]]))
3226
+ sage: A = RationalMatrix(2, 2, IM)
3227
+ sage: B = RationalMatrix(2, 2, Matrix(QQ, [[-1, 0], [0, 1]]))
3228
+ sage: A == B
3229
+ True
3230
+ """
3231
+ cdef long i, j
3232
+ if M is not None:
3233
+ if isinstance(M, RationalMatrix):
3234
+ for i in range((<RationalMatrix>M)._nrows * (<RationalMatrix>M)._ncols):
3235
+ mpq_set(self._entries[i], (<RationalMatrix>M)._entries[i])
3236
+ if isinstance(M, PlusMinusOneMatrix):
3237
+ for i in range((<PlusMinusOneMatrix> M)._nrows * (<PlusMinusOneMatrix> M)._ncols):
3238
+ mpq_set_si(self._entries[i], (<PlusMinusOneMatrix> M)._entries[i], 1)
3239
+ elif isinstance(M, LeanMatrix):
3240
+ for i in range(M.nrows()):
3241
+ for j in range(M.ncols()):
3242
+ mpq_set(self._entries[i * self._ncols + j], Rational((<LeanMatrix>M).get_unsafe(i, j)).value)
3243
+ else: # Sage Matrix or otherwise
3244
+ for i in range(M.nrows()):
3245
+ for j in range(M.ncols()):
3246
+ mpq_set(self._entries[i * self._ncols + j], Rational(M[i, j]).value)
3247
+
3248
+ def __dealloc__(self):
3249
+ """
3250
+ Free internal data structures.
3251
+
3252
+ EXAMPLES::
3253
+
3254
+ sage: from sage.matroids.lean_matrix import RationalMatrix
3255
+ sage: A = RationalMatrix(2, 3, matrix([[0, 0, 0], [1, 0, 0]]))
3256
+ sage: del A
3257
+ """
3258
+ cdef Py_ssize_t i
3259
+ if self._entries:
3260
+ # Do *not* use sig_on() here, since __dealloc__
3261
+ # cannot raise exceptions!
3262
+ for i in range(self._nrows * self._ncols):
3263
+ mpq_clear(self._entries[i])
3264
+ sig_free(self._entries)
3265
+
3266
+ def __repr__(self):
3267
+ """
3268
+ Return representation.
3269
+
3270
+ EXAMPLES::
3271
+
3272
+ sage: from sage.matroids.lean_matrix import RationalMatrix
3273
+ sage: A = RationalMatrix(2, 3, matrix([[0, 0, 0], [1, 0, 0]]))
3274
+ sage: A
3275
+ RationalMatrix instance with 2 rows and 3 columns
3276
+ """
3277
+ return "RationalMatrix instance with {} rows and {} columns".format(self._nrows, self._ncols)
3278
+
3279
+ cdef inline long index(self, long r, long c) noexcept: # Not a Sage matrix operation
3280
+ return r * self._ncols + c
3281
+
3282
+ cdef inline void set(self, long r, long c, mpq_t x) noexcept: # Not a Sage matrix operation
3283
+ mpq_set(self._entries[r * self._ncols + c], x)
3284
+
3285
+ cdef get_unsafe(self, long r, long c):
3286
+ """
3287
+ Return a Sage Integer, for safety down the line when dividing.
3288
+
3289
+ EXAMPLES:
3290
+
3291
+ By returning an Integer rather than an int, the following test no
3292
+ longer fails::
3293
+
3294
+ sage: from sage.matroids.advanced import *
3295
+ sage: M = RegularMatroid(matrix([
3296
+ ....: (1, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0),
3297
+ ....: (0, 1, 0, 0, -1, 1, 0, 0, 0, 0, 0),
3298
+ ....: (0, 0, 1, 0, 0, -1, 1, 0, 0, 1, 0),
3299
+ ....: (0, 0, 0, 1, 0, 0, -1, 1, 0, 0, 0),
3300
+ ....: (0, 0, 0, 0, 0, 0, -1, 0, 1, -1, 0),
3301
+ ....: (0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 1)]))
3302
+ sage: all(N.is_valid() for N in M.linear_extensions(F=[4, 10]))
3303
+ True
3304
+ """
3305
+ cdef Rational z = Rational.__new__(Rational)
3306
+ mpq_set(z.value, self._entries[self.index(r, c)])
3307
+ return z
3308
+
3309
+ cdef int set_unsafe(self, long r, long c, x) except -1:
3310
+ self.set(r, c, Rational(x).value)
3311
+ return 0
3312
+
3313
+ cdef bint is_nonzero(self, long r, long c) except -2: # Not a Sage matrix operation
3314
+ return mpq_sgn(self._entries[self.index(r, c)]) != 0
3315
+
3316
+ cdef LeanMatrix copy(self): # Deprecated Sage matrix operation
3317
+ cdef RationalMatrix M = RationalMatrix(self._nrows, self._ncols)
3318
+ cdef long i
3319
+ for i in range(self._nrows * self._ncols):
3320
+ mpq_set(M._entries[i], self._entries[i])
3321
+ return M
3322
+
3323
+ cdef int resize(self, long k) except -1: # Not a Sage matrix operation
3324
+ """
3325
+ Change number of rows to ``k``. Preserves data.
3326
+ """
3327
+ if self._nrows == k:
3328
+ # Nothing to do
3329
+ return 0
3330
+
3331
+ cdef long i
3332
+ if self._nrows > k:
3333
+ for i in range(self._nrows * self._ncols, k * self._ncols):
3334
+ mpq_init(self._entries[i])
3335
+ else:
3336
+ for i in range(k * self._ncols, self._nrows * self._ncols):
3337
+ mpq_clear(self._entries[i])
3338
+ sig_realloc(self._entries, self._ncols * k * sizeof(mpq_t))
3339
+ self._nrows = k
3340
+ return 0
3341
+
3342
+ cdef LeanMatrix stack(self, LeanMatrix M):
3343
+ """
3344
+ Warning: assumes ``M`` is a RationalMatrix instance of right
3345
+ dimensions!
3346
+ """
3347
+ cdef RationalMatrix A
3348
+ cdef long i
3349
+ cdef long l = self._nrows * self._ncols
3350
+ A = RationalMatrix(self._nrows + M.nrows(), self._ncols)
3351
+ for i in range(l):
3352
+ mpq_set(A._entries[i], self._entries[i])
3353
+ for i in range(M.nrows() * M.ncols()):
3354
+ mpq_set(A._entries[l+i], (<RationalMatrix>M)._entries[i])
3355
+ return A
3356
+
3357
+ cdef LeanMatrix augment(self, LeanMatrix M):
3358
+ """
3359
+ Warning: assumes ``M`` is a RationalMatrix instance!
3360
+ """
3361
+ cdef RationalMatrix A
3362
+ cdef long i, j
3363
+ cdef long Mn = M.ncols()
3364
+ A = RationalMatrix(self._nrows, self._ncols + Mn)
3365
+ for i in range(self._nrows):
3366
+ for j in range(self._ncols):
3367
+ mpq_set(A._entries[A.index(i, j)], self._entries[self.index(i, j)])
3368
+ mpq_set(A._entries[i*A._ncols + self._ncols + j], (<RationalMatrix>M)._entries[i*Mn + j])
3369
+ return A
3370
+
3371
+ cdef LeanMatrix prepend_identity(self): # Not a Sage matrix operation
3372
+ cdef RationalMatrix A = RationalMatrix(self._nrows, self._ncols + self._nrows)
3373
+ cdef long i, j
3374
+ for i in range(self._nrows):
3375
+ mpq_set_si(A._entries[A.index(i, i)], 1, 1)
3376
+ for j in range(self._ncols):
3377
+ mpq_set(A._entries[A.index(i, self._nrows + j)],
3378
+ self._entries[self.index(i, j)])
3379
+ return A
3380
+
3381
+ cpdef base_ring(self):
3382
+ """
3383
+ Return the base ring of ``self``.
3384
+
3385
+ EXAMPLES::
3386
+
3387
+ sage: from sage.matroids.lean_matrix import RationalMatrix
3388
+ sage: A = RationalMatrix(3, 4)
3389
+ sage: A.base_ring()
3390
+ Rational Field
3391
+ """
3392
+ return QQ
3393
+
3394
+ cpdef characteristic(self):
3395
+ """
3396
+ Return the characteristic of ``self.base_ring()``.
3397
+
3398
+ EXAMPLES::
3399
+
3400
+ sage: from sage.matroids.lean_matrix import RationalMatrix
3401
+ sage: A = RationalMatrix(3, 4)
3402
+ sage: A.characteristic()
3403
+ 0
3404
+ """
3405
+ return 0
3406
+
3407
+ cdef inline long row_len(self, long i) except -1: # Not a Sage matrix operation
3408
+ """
3409
+ Return number of nonzero entries in row ``i``.
3410
+ """
3411
+ cdef long k
3412
+ cdef long res = 0
3413
+ for k in range(self._ncols):
3414
+ if mpq_sgn(self._entries[self.index(i, k)]) != 0:
3415
+ res += 1
3416
+ return res
3417
+
3418
+ cdef inline row_inner_product(self, long i, long j): # Not a Sage matrix operation
3419
+ """
3420
+ Return the inner product between rows ``i`` and ``j``.
3421
+ """
3422
+ cdef long k
3423
+ cdef Rational z = Rational.__new__(Rational)
3424
+ cdef mpq_t t
3425
+ mpq_init(t)
3426
+ mpq_set_si(z.value, 0, 1)
3427
+ for k in range(self._ncols):
3428
+ mpq_mul(t, self._entries[self.index(i, k)], self._entries[self.index(j, k)])
3429
+ mpq_add(z.value, z.value, t)
3430
+ mpq_clear(t)
3431
+ return z
3432
+
3433
+ cdef int add_multiple_of_row_c(self, long x, long y, s, bint col_start) except -1:
3434
+ """
3435
+ Add ``s`` times row ``y`` to row ``x``. Argument ``col_start`` is
3436
+ ignored.
3437
+ """
3438
+ if s is None:
3439
+ for i in range(self._ncols):
3440
+ # In place addition for position (x, i)
3441
+ mpq_add(self._entries[self.index(x, i)], self._entries[self.index(x, i)], self._entries[self.index(y, i)])
3442
+ else:
3443
+ return self.add_multiple_of_row_mpq(x, y, Rational(s).value, col_start)
3444
+
3445
+ cdef int add_multiple_of_row_mpq(self, long x, long y, mpq_t s, bint col_start) except -1:
3446
+ cdef long i
3447
+ cdef mpq_t t
3448
+ mpq_init(t)
3449
+
3450
+ for i in range(self._ncols):
3451
+ mpq_mul(t, s, self._entries[self.index(y, i)])
3452
+ # In place addition for position (x, i)
3453
+ mpq_add(self._entries[self.index(x, i)], self._entries[self.index(x, i)], t)
3454
+ mpq_clear(t)
3455
+ return 0
3456
+
3457
+ cdef int swap_rows_c(self, long x, long y) except -1:
3458
+ """
3459
+ Swap rows ``x`` and ``y``.
3460
+ """
3461
+ cdef mpq_t* tmp
3462
+ tmp = <mpq_t*> sig_malloc(self._ncols * sizeof(mpq_t))
3463
+ if not tmp:
3464
+ raise MemoryError
3465
+ memcpy(tmp, self._entries + x * self._ncols, self._ncols * sizeof(mpq_t))
3466
+ memcpy(self._entries + x * self._ncols, self._entries + y * self._ncols, self._ncols * sizeof(mpq_t))
3467
+ memcpy(self._entries + y * self._ncols, tmp, self._ncols * sizeof(mpq_t))
3468
+ sig_free(tmp)
3469
+ return 0
3470
+
3471
+ cdef int rescale_row_c(self, long x, s, bint col_start) except -1:
3472
+ """
3473
+ Scale row ``x`` by ``s``. Argument ``col_start`` is for Sage
3474
+ compatibility, and is ignored.
3475
+ """
3476
+ if s == 1:
3477
+ # Nothing to do
3478
+ return 0
3479
+ return self.rescale_row_mpq(x, Rational(s).value, col_start)
3480
+
3481
+ cdef int rescale_row_mpq(self, long x, mpq_t s, bint col_start) except -1:
3482
+ cdef long i
3483
+ for i in range(self._ncols):
3484
+ # This is inplace multiplication
3485
+ mpq_mul(self._entries[self.index(x, i)], s, self._entries[self.index(x, i)])
3486
+ return 0
3487
+
3488
+ cdef int rescale_column_c(self, long y, s, bint start_row) except -1:
3489
+ """
3490
+ Scale column ``y`` by ``s``. Argument ``start_row`` is for Sage
3491
+ compatibility, and is ignored.
3492
+ """
3493
+ if s == 1:
3494
+ # Nothing to do
3495
+ return 0
3496
+ return self.rescale_column_mpq(y, Rational(s).value, start_row)
3497
+
3498
+ cdef int rescale_column_mpq(self, long y, mpq_t s, bint start_row) except -1:
3499
+ cdef long j
3500
+ for j in range(self._nrows):
3501
+ # This is inplace multiplication
3502
+ mpq_mul(self._entries[self.index(j, y)], self._entries[self.index(j, y)], s)
3503
+ return 0
3504
+
3505
+ cdef int pivot(self, long x, long y) except -1: # Not a Sage matrix operation
3506
+ """
3507
+ Row-reduce to make column ``y`` have a ``1`` in row ``x`` and zeroes
3508
+ elsewhere.
3509
+
3510
+ .. NOTE::
3511
+
3512
+ This is different from what matroid theorists tend to call a
3513
+ pivot, as it does not involve a column exchange!
3514
+ """
3515
+ cdef long i
3516
+ cdef mpq_t t
3517
+ mpq_init(t)
3518
+ mpq_inv(t, self._entries[self.index(x, y)])
3519
+ self.rescale_row_mpq(x, t, 0)
3520
+ for i in range(self._nrows):
3521
+ if mpq_sgn(self._entries[self.index(i, y)]) != 0 and i != x:
3522
+ mpq_neg(t, self._entries[self.index(i, y)])
3523
+ self.add_multiple_of_row_mpq(i, x, t, 0)
3524
+ mpq_clear(t)
3525
+ return 0
3526
+
3527
+ cdef list nonzero_positions_in_row(self, long r):
3528
+ """
3529
+ Get coordinates of nonzero entries of row ``r``.
3530
+ """
3531
+ cdef long j
3532
+ cdef list res = []
3533
+ for j in range(r * self._ncols, (r + 1) * self._ncols):
3534
+ if mpq_sgn(self._entries[j]) != 0:
3535
+ res.append(j - r * self._ncols)
3536
+ return res
3537
+
3538
+ cdef LeanMatrix transpose(self):
3539
+ """
3540
+ Return the transpose of the matrix.
3541
+ """
3542
+ cdef RationalMatrix A
3543
+ cdef long i, j
3544
+ A = RationalMatrix(self._ncols, self._nrows)
3545
+ for i in range(self._nrows):
3546
+ for j in range(self._ncols):
3547
+ A.set(j, i, self._entries[self.index(i, j)])
3548
+ return A
3549
+
3550
+ cdef LeanMatrix _matrix_times_matrix_(self, LeanMatrix other):
3551
+ """
3552
+ Return the product ``self * other``.
3553
+ """
3554
+ cdef RationalMatrix A, ot
3555
+ cdef long i, j, t, ind
3556
+ cdef mpq_t s
3557
+ mpq_init(s)
3558
+ ot = <RationalMatrix> other
3559
+ A = RationalMatrix(self._nrows, ot._ncols)
3560
+ for i in range(A._nrows):
3561
+ for j in range(A._ncols):
3562
+ ind = A.index(i, j)
3563
+ # We do all operations inplace on A._entries[ind]
3564
+ for t in range(self._ncols):
3565
+ mpq_mul(s, self._entries[self.index(i, t)], ot._entries[ot.index(t, j)])
3566
+ mpq_add(A._entries[ind], A._entries[ind], s)
3567
+ mpq_clear(s)
3568
+ return A
3569
+
3570
+ cdef list gauss_jordan_reduce(self, columns): # Not a Sage matrix operation
3571
+ """
3572
+ Row-reduce so the lexicographically first basis indexes an identity
3573
+ submatrix.
3574
+ """
3575
+ cdef long r = 0
3576
+ cdef list P = []
3577
+ cdef long c, p, row
3578
+ cdef mpq_t a
3579
+ cdef bint is_pivot
3580
+ mpq_init(a)
3581
+ for c in columns:
3582
+ is_pivot = False
3583
+ for row in range(r, self._nrows):
3584
+ if mpq_sgn(self._entries[self.index(row, c)]) != 0:
3585
+ is_pivot = True
3586
+ p = row
3587
+ break
3588
+ if is_pivot:
3589
+ self.swap_rows_c(p, r)
3590
+ mpq_inv(a, self._entries[self.index(r, c)])
3591
+ self.rescale_row_mpq(r, a, 0)
3592
+ for row in range(self._nrows):
3593
+ if row != r and mpq_sgn(self._entries[self.index(row, c)]) != 0:
3594
+ mpq_neg(a, self._entries[self.index(row, c)])
3595
+ self.add_multiple_of_row_mpq(row, r, a, 0)
3596
+ P.append(c)
3597
+ r += 1
3598
+ if r == self._nrows:
3599
+ break
3600
+ mpq_clear(a)
3601
+ return P
3602
+
3603
+ def __richcmp__(left, right, op):
3604
+ """
3605
+ Compare two matrices.
3606
+
3607
+ EXAMPLES::
3608
+
3609
+ sage: from sage.matroids.lean_matrix import RationalMatrix
3610
+ sage: A = RationalMatrix(2, 2, matrix(QQ, [[1, 0], [0, 1/2]]))
3611
+ sage: B = RationalMatrix(2, 2, matrix(QQ, [[1, 0], [0, 1/2]]))
3612
+ sage: C = RationalMatrix(2, 2, matrix(QQ, [[1, 1/3], [0, 1/2]]))
3613
+ sage: D = RationalMatrix(2, 2, matrix(QQ, [[1, 1/3], [0, 1/2]]))
3614
+ sage: E = RationalMatrix(2, 3, matrix(QQ, [[1, 0, 0], [0, 1/2, 0]]))
3615
+ sage: A == B
3616
+ True
3617
+ sage: A != C
3618
+ True
3619
+ sage: A == D
3620
+ False
3621
+ sage: E == A
3622
+ False
3623
+ """
3624
+ cdef long i
3625
+ if op not in [Py_EQ, Py_NE]:
3626
+ return NotImplemented
3627
+ if not isinstance(left, RationalMatrix) or not isinstance(right, RationalMatrix):
3628
+ return NotImplemented
3629
+ if op == Py_EQ:
3630
+ res = True
3631
+ if op == Py_NE:
3632
+ res = False
3633
+ # res gets inverted if matroids are deemed different.
3634
+ if left.nrows() != right.nrows():
3635
+ return not res
3636
+ if left.ncols() != right.ncols():
3637
+ return not res
3638
+ for i in range(left.nrows() * left.ncols()):
3639
+ if not mpq_equal((<RationalMatrix>left)._entries[i], (<RationalMatrix>right)._entries[i]):
3640
+ return not res
3641
+ return res
3642
+
3643
+ def __reduce__(self):
3644
+ """
3645
+ Save the object.
3646
+
3647
+ EXAMPLES::
3648
+
3649
+ sage: from sage.matroids.lean_matrix import RationalMatrix
3650
+ sage: A = RationalMatrix(2, 5)
3651
+ sage: A == loads(dumps(A)) # indirect doctest
3652
+ True
3653
+ sage: C = RationalMatrix(2, 2, matrix(QQ, [[1, 1/3], [0, -1]]))
3654
+ sage: C == loads(dumps(C))
3655
+ True
3656
+ """
3657
+ from sage.matroids.unpickling import unpickle_rational_matrix
3658
+ cdef Rational z
3659
+ cdef list entries = []
3660
+ cdef long i
3661
+ for i in range(self._nrows * self._ncols):
3662
+ z = Rational.__new__(Rational)
3663
+ mpq_set(z.value, self._entries[i])
3664
+ entries.append(z)
3665
+ version = 0
3666
+ data = (self.nrows(), self.ncols(), entries)
3667
+ return unpickle_rational_matrix, (version, data)