passagemath-modules 10.6.31rc3__cp314-cp314-musllinux_1_2_aarch64.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.
- passagemath_modules-10.6.31rc3.dist-info/METADATA +281 -0
- passagemath_modules-10.6.31rc3.dist-info/RECORD +807 -0
- passagemath_modules-10.6.31rc3.dist-info/WHEEL +5 -0
- passagemath_modules-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_modules.libs/libgcc_s-2d945d6c.so.1 +0 -0
- passagemath_modules.libs/libgfortran-67378ab2.so.5.0.0 +0 -0
- passagemath_modules.libs/libgmp-28992bcb.so.10.5.0 +0 -0
- passagemath_modules.libs/libgsl-23768756.so.28.0.0 +0 -0
- passagemath_modules.libs/libmpc-7897025b.so.3.3.1 +0 -0
- passagemath_modules.libs/libmpfr-e34bb864.so.6.2.1 +0 -0
- passagemath_modules.libs/libopenblasp-r0-503f0c35.3.29.so +0 -0
- sage/algebras/all__sagemath_modules.py +20 -0
- sage/algebras/catalog.py +148 -0
- sage/algebras/clifford_algebra.py +3107 -0
- sage/algebras/clifford_algebra_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/algebras/clifford_algebra_element.pxd +16 -0
- sage/algebras/clifford_algebra_element.pyx +997 -0
- sage/algebras/commutative_dga.py +4252 -0
- sage/algebras/exterior_algebra_groebner.cpython-314-aarch64-linux-musl.so +0 -0
- sage/algebras/exterior_algebra_groebner.pxd +55 -0
- sage/algebras/exterior_algebra_groebner.pyx +727 -0
- sage/algebras/finite_dimensional_algebras/all.py +2 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +1029 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pxd +12 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +706 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py +196 -0
- sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_morphism.py +255 -0
- sage/algebras/finite_gca.py +528 -0
- sage/algebras/group_algebra.py +232 -0
- sage/algebras/lie_algebras/abelian.py +197 -0
- sage/algebras/lie_algebras/affine_lie_algebra.py +1213 -0
- sage/algebras/lie_algebras/all.py +25 -0
- sage/algebras/lie_algebras/all__sagemath_modules.py +1 -0
- sage/algebras/lie_algebras/bch.py +177 -0
- sage/algebras/lie_algebras/bgg_dual_module.py +1184 -0
- sage/algebras/lie_algebras/bgg_resolution.py +232 -0
- sage/algebras/lie_algebras/center_uea.py +767 -0
- sage/algebras/lie_algebras/classical_lie_algebra.py +2516 -0
- sage/algebras/lie_algebras/examples.py +683 -0
- sage/algebras/lie_algebras/free_lie_algebra.py +973 -0
- sage/algebras/lie_algebras/heisenberg.py +820 -0
- sage/algebras/lie_algebras/lie_algebra.py +1562 -0
- sage/algebras/lie_algebras/lie_algebra_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/algebras/lie_algebras/lie_algebra_element.pxd +68 -0
- sage/algebras/lie_algebras/lie_algebra_element.pyx +2122 -0
- sage/algebras/lie_algebras/morphism.py +661 -0
- sage/algebras/lie_algebras/nilpotent_lie_algebra.py +457 -0
- sage/algebras/lie_algebras/onsager.py +1324 -0
- sage/algebras/lie_algebras/poincare_birkhoff_witt.py +816 -0
- sage/algebras/lie_algebras/quotient.py +462 -0
- sage/algebras/lie_algebras/rank_two_heisenberg_virasoro.py +355 -0
- sage/algebras/lie_algebras/representation.py +1040 -0
- sage/algebras/lie_algebras/structure_coefficients.py +459 -0
- sage/algebras/lie_algebras/subalgebra.py +967 -0
- sage/algebras/lie_algebras/symplectic_derivation.py +289 -0
- sage/algebras/lie_algebras/verma_module.py +1630 -0
- sage/algebras/lie_algebras/virasoro.py +1186 -0
- sage/algebras/octonion_algebra.cpython-314-aarch64-linux-musl.so +0 -0
- sage/algebras/octonion_algebra.pxd +20 -0
- sage/algebras/octonion_algebra.pyx +987 -0
- sage/algebras/orlik_solomon.py +907 -0
- sage/algebras/orlik_terao.py +779 -0
- sage/algebras/steenrod/all.py +7 -0
- sage/algebras/steenrod/steenrod_algebra.py +4258 -0
- sage/algebras/steenrod/steenrod_algebra_bases.py +1179 -0
- sage/algebras/steenrod/steenrod_algebra_misc.py +1167 -0
- sage/algebras/steenrod/steenrod_algebra_mult.py +954 -0
- sage/algebras/weyl_algebra.py +1126 -0
- sage/all__sagemath_modules.py +62 -0
- sage/calculus/all__sagemath_modules.py +19 -0
- sage/calculus/expr.py +205 -0
- sage/calculus/integration.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/integration.pyx +698 -0
- sage/calculus/interpolation.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/interpolation.pxd +13 -0
- sage/calculus/interpolation.pyx +387 -0
- sage/calculus/interpolators.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/interpolators.pyx +326 -0
- sage/calculus/ode.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/ode.pxd +5 -0
- sage/calculus/ode.pyx +610 -0
- sage/calculus/riemann.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/riemann.pyx +1521 -0
- sage/calculus/test_sympy.py +201 -0
- sage/calculus/transforms/all.py +7 -0
- sage/calculus/transforms/dft.py +844 -0
- sage/calculus/transforms/dwt.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/transforms/dwt.pxd +7 -0
- sage/calculus/transforms/dwt.pyx +160 -0
- sage/calculus/transforms/fft.cpython-314-aarch64-linux-musl.so +0 -0
- sage/calculus/transforms/fft.pxd +12 -0
- sage/calculus/transforms/fft.pyx +487 -0
- sage/calculus/wester.py +662 -0
- sage/coding/abstract_code.py +1108 -0
- sage/coding/ag_code.py +868 -0
- sage/coding/ag_code_decoders.cpython-314-aarch64-linux-musl.so +0 -0
- sage/coding/ag_code_decoders.pyx +2639 -0
- sage/coding/all.py +15 -0
- sage/coding/bch_code.py +494 -0
- sage/coding/binary_code.cpython-314-aarch64-linux-musl.so +0 -0
- sage/coding/binary_code.pxd +124 -0
- sage/coding/binary_code.pyx +4139 -0
- sage/coding/bounds_catalog.py +43 -0
- sage/coding/channel.py +819 -0
- sage/coding/channels_catalog.py +29 -0
- sage/coding/code_bounds.py +755 -0
- sage/coding/code_constructions.py +804 -0
- sage/coding/codes_catalog.py +111 -0
- sage/coding/cyclic_code.py +1329 -0
- sage/coding/databases.py +316 -0
- sage/coding/decoder.py +373 -0
- sage/coding/decoders_catalog.py +88 -0
- sage/coding/delsarte_bounds.py +709 -0
- sage/coding/encoder.py +390 -0
- sage/coding/encoders_catalog.py +64 -0
- sage/coding/extended_code.py +468 -0
- sage/coding/gabidulin_code.py +1058 -0
- sage/coding/golay_code.py +404 -0
- sage/coding/goppa_code.py +441 -0
- sage/coding/grs_code.py +2371 -0
- sage/coding/guava.py +107 -0
- sage/coding/guruswami_sudan/all.py +1 -0
- sage/coding/guruswami_sudan/gs_decoder.py +897 -0
- sage/coding/guruswami_sudan/interpolation.py +409 -0
- sage/coding/guruswami_sudan/utils.py +176 -0
- sage/coding/hamming_code.py +176 -0
- sage/coding/information_set_decoder.py +1032 -0
- sage/coding/kasami_codes.cpython-314-aarch64-linux-musl.so +0 -0
- sage/coding/kasami_codes.pyx +351 -0
- sage/coding/linear_code.py +3067 -0
- sage/coding/linear_code_no_metric.py +1354 -0
- sage/coding/linear_rank_metric.py +961 -0
- sage/coding/parity_check_code.py +353 -0
- sage/coding/punctured_code.py +719 -0
- sage/coding/reed_muller_code.py +999 -0
- sage/coding/self_dual_codes.py +942 -0
- sage/coding/source_coding/all.py +2 -0
- sage/coding/source_coding/huffman.py +553 -0
- sage/coding/subfield_subcode.py +423 -0
- sage/coding/two_weight_db.py +399 -0
- sage/combinat/all__sagemath_modules.py +7 -0
- sage/combinat/cartesian_product.py +347 -0
- sage/combinat/family.py +11 -0
- sage/combinat/free_module.py +1977 -0
- sage/combinat/root_system/all.py +147 -0
- sage/combinat/root_system/ambient_space.py +527 -0
- sage/combinat/root_system/associahedron.py +471 -0
- sage/combinat/root_system/braid_move_calculator.py +143 -0
- sage/combinat/root_system/braid_orbit.cpython-314-aarch64-linux-musl.so +0 -0
- sage/combinat/root_system/braid_orbit.pyx +144 -0
- sage/combinat/root_system/branching_rules.py +2301 -0
- sage/combinat/root_system/cartan_matrix.py +1245 -0
- sage/combinat/root_system/cartan_type.py +3069 -0
- sage/combinat/root_system/coxeter_group.py +162 -0
- sage/combinat/root_system/coxeter_matrix.py +1261 -0
- sage/combinat/root_system/coxeter_type.py +681 -0
- sage/combinat/root_system/dynkin_diagram.py +900 -0
- sage/combinat/root_system/extended_affine_weyl_group.py +2993 -0
- sage/combinat/root_system/fundamental_group.py +795 -0
- sage/combinat/root_system/hecke_algebra_representation.py +1203 -0
- sage/combinat/root_system/integrable_representations.py +1227 -0
- sage/combinat/root_system/non_symmetric_macdonald_polynomials.py +1965 -0
- sage/combinat/root_system/pieri_factors.py +1147 -0
- sage/combinat/root_system/plot.py +1615 -0
- sage/combinat/root_system/root_lattice_realization_algebras.py +1214 -0
- sage/combinat/root_system/root_lattice_realizations.py +4628 -0
- sage/combinat/root_system/root_space.py +487 -0
- sage/combinat/root_system/root_system.py +882 -0
- sage/combinat/root_system/type_A.py +348 -0
- sage/combinat/root_system/type_A_affine.py +227 -0
- sage/combinat/root_system/type_A_infinity.py +241 -0
- sage/combinat/root_system/type_B.py +347 -0
- sage/combinat/root_system/type_BC_affine.py +287 -0
- sage/combinat/root_system/type_B_affine.py +216 -0
- sage/combinat/root_system/type_C.py +317 -0
- sage/combinat/root_system/type_C_affine.py +188 -0
- sage/combinat/root_system/type_D.py +357 -0
- sage/combinat/root_system/type_D_affine.py +208 -0
- sage/combinat/root_system/type_E.py +641 -0
- sage/combinat/root_system/type_E_affine.py +231 -0
- sage/combinat/root_system/type_F.py +387 -0
- sage/combinat/root_system/type_F_affine.py +137 -0
- sage/combinat/root_system/type_G.py +293 -0
- sage/combinat/root_system/type_G_affine.py +132 -0
- sage/combinat/root_system/type_H.py +105 -0
- sage/combinat/root_system/type_I.py +110 -0
- sage/combinat/root_system/type_Q.py +150 -0
- sage/combinat/root_system/type_affine.py +509 -0
- sage/combinat/root_system/type_dual.py +704 -0
- sage/combinat/root_system/type_folded.py +301 -0
- sage/combinat/root_system/type_marked.py +748 -0
- sage/combinat/root_system/type_reducible.py +601 -0
- sage/combinat/root_system/type_relabel.py +730 -0
- sage/combinat/root_system/type_super_A.py +837 -0
- sage/combinat/root_system/weight_lattice_realizations.py +1188 -0
- sage/combinat/root_system/weight_space.py +639 -0
- sage/combinat/root_system/weyl_characters.py +2238 -0
- sage/crypto/__init__.py +4 -0
- sage/crypto/all.py +28 -0
- sage/crypto/block_cipher/all.py +7 -0
- sage/crypto/block_cipher/des.py +1065 -0
- sage/crypto/block_cipher/miniaes.py +2171 -0
- sage/crypto/block_cipher/present.py +909 -0
- sage/crypto/block_cipher/sdes.py +1527 -0
- sage/crypto/boolean_function.cpython-314-aarch64-linux-musl.so +0 -0
- sage/crypto/boolean_function.pxd +10 -0
- sage/crypto/boolean_function.pyx +1487 -0
- sage/crypto/cipher.py +78 -0
- sage/crypto/classical.py +3668 -0
- sage/crypto/classical_cipher.py +569 -0
- sage/crypto/cryptosystem.py +387 -0
- sage/crypto/key_exchange/all.py +7 -0
- sage/crypto/key_exchange/catalog.py +24 -0
- sage/crypto/key_exchange/diffie_hellman.py +323 -0
- sage/crypto/key_exchange/key_exchange_scheme.py +107 -0
- sage/crypto/lattice.py +312 -0
- sage/crypto/lfsr.py +295 -0
- sage/crypto/lwe.py +840 -0
- sage/crypto/mq/__init__.py +4 -0
- sage/crypto/mq/mpolynomialsystemgenerator.py +204 -0
- sage/crypto/mq/rijndael_gf.py +2345 -0
- sage/crypto/mq/sbox.py +7 -0
- sage/crypto/mq/sr.py +3344 -0
- sage/crypto/public_key/all.py +5 -0
- sage/crypto/public_key/blum_goldwasser.py +776 -0
- sage/crypto/sbox.cpython-314-aarch64-linux-musl.so +0 -0
- sage/crypto/sbox.pyx +2090 -0
- sage/crypto/sboxes.py +2090 -0
- sage/crypto/stream.py +390 -0
- sage/crypto/stream_cipher.py +297 -0
- sage/crypto/util.py +519 -0
- sage/ext/all__sagemath_modules.py +1 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_modules.py +2 -0
- sage/ext/interpreters/wrapper_cc.cpython-314-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_cc.pxd +30 -0
- sage/ext/interpreters/wrapper_cc.pyx +252 -0
- sage/ext/interpreters/wrapper_cdf.cpython-314-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_cdf.pxd +26 -0
- sage/ext/interpreters/wrapper_cdf.pyx +245 -0
- sage/ext/interpreters/wrapper_rdf.cpython-314-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_rdf.pxd +23 -0
- sage/ext/interpreters/wrapper_rdf.pyx +221 -0
- sage/ext/interpreters/wrapper_rr.cpython-314-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_rr.pxd +28 -0
- sage/ext/interpreters/wrapper_rr.pyx +335 -0
- sage/geometry/all__sagemath_modules.py +5 -0
- sage/geometry/toric_lattice.py +1745 -0
- sage/geometry/toric_lattice_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/geometry/toric_lattice_element.pyx +432 -0
- sage/groups/abelian_gps/abelian_group.py +1925 -0
- sage/groups/abelian_gps/abelian_group_element.py +164 -0
- sage/groups/abelian_gps/all__sagemath_modules.py +5 -0
- sage/groups/abelian_gps/dual_abelian_group.py +421 -0
- sage/groups/abelian_gps/dual_abelian_group_element.py +179 -0
- sage/groups/abelian_gps/element_base.py +341 -0
- sage/groups/abelian_gps/values.py +488 -0
- sage/groups/additive_abelian/additive_abelian_group.py +476 -0
- sage/groups/additive_abelian/additive_abelian_wrapper.py +857 -0
- sage/groups/additive_abelian/all.py +4 -0
- sage/groups/additive_abelian/qmodnz.py +231 -0
- sage/groups/additive_abelian/qmodnz_element.py +349 -0
- sage/groups/affine_gps/affine_group.py +535 -0
- sage/groups/affine_gps/all.py +1 -0
- sage/groups/affine_gps/catalog.py +17 -0
- sage/groups/affine_gps/euclidean_group.py +246 -0
- sage/groups/affine_gps/group_element.py +562 -0
- sage/groups/all__sagemath_modules.py +12 -0
- sage/groups/galois_group.py +479 -0
- sage/groups/matrix_gps/all.py +4 -0
- sage/groups/matrix_gps/all__sagemath_modules.py +13 -0
- sage/groups/matrix_gps/catalog.py +26 -0
- sage/groups/matrix_gps/coxeter_group.py +927 -0
- sage/groups/matrix_gps/finitely_generated.py +487 -0
- sage/groups/matrix_gps/group_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/groups/matrix_gps/group_element.pxd +11 -0
- sage/groups/matrix_gps/group_element.pyx +431 -0
- sage/groups/matrix_gps/linear.py +440 -0
- sage/groups/matrix_gps/matrix_group.py +617 -0
- sage/groups/matrix_gps/named_group.py +296 -0
- sage/groups/matrix_gps/orthogonal.py +544 -0
- sage/groups/matrix_gps/symplectic.py +251 -0
- sage/groups/matrix_gps/unitary.py +436 -0
- sage/groups/misc_gps/all__sagemath_modules.py +1 -0
- sage/groups/misc_gps/argument_groups.py +1905 -0
- sage/groups/misc_gps/imaginary_groups.py +479 -0
- sage/groups/perm_gps/all__sagemath_modules.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_modules.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.cpython-314-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.pxd +41 -0
- sage/groups/perm_gps/partn_ref/refinement_binary.pyx +1167 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.cpython-314-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.pxd +31 -0
- sage/groups/perm_gps/partn_ref/refinement_matrices.pyx +385 -0
- sage/homology/algebraic_topological_model.py +595 -0
- sage/homology/all.py +2 -0
- sage/homology/all__sagemath_modules.py +8 -0
- sage/homology/chain_complex.py +2148 -0
- sage/homology/chain_complex_homspace.py +165 -0
- sage/homology/chain_complex_morphism.py +629 -0
- sage/homology/chain_homotopy.py +604 -0
- sage/homology/chains.py +653 -0
- sage/homology/free_resolution.py +923 -0
- sage/homology/graded_resolution.py +567 -0
- sage/homology/hochschild_complex.py +756 -0
- sage/homology/homology_group.py +188 -0
- sage/homology/homology_morphism.py +422 -0
- sage/homology/homology_vector_space_with_basis.py +1454 -0
- sage/homology/koszul_complex.py +169 -0
- sage/homology/matrix_utils.py +205 -0
- sage/libs/all__sagemath_modules.py +1 -0
- sage/libs/gsl/__init__.py +1 -0
- sage/libs/gsl/airy.pxd +56 -0
- sage/libs/gsl/all.pxd +66 -0
- sage/libs/gsl/array.cpython-314-aarch64-linux-musl.so +0 -0
- sage/libs/gsl/array.pxd +5 -0
- sage/libs/gsl/array.pyx +102 -0
- sage/libs/gsl/bessel.pxd +208 -0
- sage/libs/gsl/blas.pxd +116 -0
- sage/libs/gsl/blas_types.pxd +34 -0
- sage/libs/gsl/block.pxd +52 -0
- sage/libs/gsl/chebyshev.pxd +37 -0
- sage/libs/gsl/clausen.pxd +12 -0
- sage/libs/gsl/combination.pxd +47 -0
- sage/libs/gsl/complex.pxd +151 -0
- sage/libs/gsl/coulomb.pxd +30 -0
- sage/libs/gsl/coupling.pxd +21 -0
- sage/libs/gsl/dawson.pxd +12 -0
- sage/libs/gsl/debye.pxd +24 -0
- sage/libs/gsl/dilog.pxd +14 -0
- sage/libs/gsl/eigen.pxd +46 -0
- sage/libs/gsl/elementary.pxd +12 -0
- sage/libs/gsl/ellint.pxd +48 -0
- sage/libs/gsl/elljac.pxd +8 -0
- sage/libs/gsl/erf.pxd +32 -0
- sage/libs/gsl/errno.pxd +26 -0
- sage/libs/gsl/exp.pxd +44 -0
- sage/libs/gsl/expint.pxd +44 -0
- sage/libs/gsl/fermi_dirac.pxd +44 -0
- sage/libs/gsl/fft.pxd +121 -0
- sage/libs/gsl/fit.pxd +50 -0
- sage/libs/gsl/gamma.pxd +94 -0
- sage/libs/gsl/gegenbauer.pxd +26 -0
- sage/libs/gsl/histogram.pxd +176 -0
- sage/libs/gsl/hyperg.pxd +52 -0
- sage/libs/gsl/integration.pxd +69 -0
- sage/libs/gsl/interp.pxd +109 -0
- sage/libs/gsl/laguerre.pxd +24 -0
- sage/libs/gsl/lambert.pxd +16 -0
- sage/libs/gsl/legendre.pxd +90 -0
- sage/libs/gsl/linalg.pxd +185 -0
- sage/libs/gsl/log.pxd +26 -0
- sage/libs/gsl/math.pxd +43 -0
- sage/libs/gsl/matrix.pxd +143 -0
- sage/libs/gsl/matrix_complex.pxd +130 -0
- sage/libs/gsl/min.pxd +67 -0
- sage/libs/gsl/monte.pxd +56 -0
- sage/libs/gsl/ntuple.pxd +32 -0
- sage/libs/gsl/odeiv.pxd +70 -0
- sage/libs/gsl/permutation.pxd +78 -0
- sage/libs/gsl/poly.pxd +40 -0
- sage/libs/gsl/pow_int.pxd +12 -0
- sage/libs/gsl/psi.pxd +28 -0
- sage/libs/gsl/qrng.pxd +29 -0
- sage/libs/gsl/random.pxd +257 -0
- sage/libs/gsl/rng.pxd +100 -0
- sage/libs/gsl/roots.pxd +72 -0
- sage/libs/gsl/sort.pxd +36 -0
- sage/libs/gsl/statistics.pxd +59 -0
- sage/libs/gsl/sum.pxd +55 -0
- sage/libs/gsl/synchrotron.pxd +16 -0
- sage/libs/gsl/transport.pxd +24 -0
- sage/libs/gsl/trig.pxd +58 -0
- sage/libs/gsl/types.pxd +137 -0
- sage/libs/gsl/vector.pxd +101 -0
- sage/libs/gsl/vector_complex.pxd +83 -0
- sage/libs/gsl/wavelet.pxd +49 -0
- sage/libs/gsl/zeta.pxd +28 -0
- sage/libs/mpc/__init__.pxd +114 -0
- sage/libs/mpc/types.pxd +28 -0
- sage/libs/mpfr/__init__.pxd +299 -0
- sage/libs/mpfr/types.pxd +26 -0
- sage/libs/mpmath/__init__.py +1 -0
- sage/libs/mpmath/all.py +27 -0
- sage/libs/mpmath/all__sagemath_modules.py +1 -0
- sage/libs/mpmath/utils.cpython-314-aarch64-linux-musl.so +0 -0
- sage/libs/mpmath/utils.pxd +4 -0
- sage/libs/mpmath/utils.pyx +319 -0
- sage/matrix/action.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/action.pxd +26 -0
- sage/matrix/action.pyx +596 -0
- sage/matrix/all.py +9 -0
- sage/matrix/args.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/args.pxd +144 -0
- sage/matrix/args.pyx +1668 -0
- sage/matrix/benchmark.py +1258 -0
- sage/matrix/berlekamp_massey.py +95 -0
- sage/matrix/compute_J_ideal.py +926 -0
- sage/matrix/constructor.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/constructor.pyx +750 -0
- sage/matrix/docs.py +430 -0
- sage/matrix/echelon_matrix.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/echelon_matrix.pyx +155 -0
- sage/matrix/matrix.pxd +2 -0
- sage/matrix/matrix0.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix0.pxd +68 -0
- sage/matrix/matrix0.pyx +6324 -0
- sage/matrix/matrix1.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix1.pxd +8 -0
- sage/matrix/matrix1.pyx +2851 -0
- sage/matrix/matrix2.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix2.pxd +25 -0
- sage/matrix/matrix2.pyx +20181 -0
- sage/matrix/matrix_cdv.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_cdv.pxd +4 -0
- sage/matrix/matrix_cdv.pyx +93 -0
- sage/matrix/matrix_complex_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_complex_double_dense.pxd +5 -0
- sage/matrix/matrix_complex_double_dense.pyx +98 -0
- sage/matrix/matrix_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_dense.pxd +5 -0
- sage/matrix/matrix_dense.pyx +343 -0
- sage/matrix/matrix_domain_dense.pxd +5 -0
- sage/matrix/matrix_domain_sparse.pxd +5 -0
- sage/matrix/matrix_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_double_dense.pxd +7 -0
- sage/matrix/matrix_double_dense.pyx +3906 -0
- sage/matrix/matrix_double_sparse.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_double_sparse.pxd +6 -0
- sage/matrix/matrix_double_sparse.pyx +248 -0
- sage/matrix/matrix_generic_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_generic_dense.pxd +7 -0
- sage/matrix/matrix_generic_dense.pyx +354 -0
- sage/matrix/matrix_generic_sparse.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_generic_sparse.pxd +7 -0
- sage/matrix/matrix_generic_sparse.pyx +461 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.pxd +5 -0
- sage/matrix/matrix_laurent_mpolynomial_dense.pyx +115 -0
- sage/matrix/matrix_misc.py +313 -0
- sage/matrix/matrix_numpy_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_numpy_dense.pxd +14 -0
- sage/matrix/matrix_numpy_dense.pyx +450 -0
- sage/matrix/matrix_numpy_integer_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_numpy_integer_dense.pxd +7 -0
- sage/matrix/matrix_numpy_integer_dense.pyx +59 -0
- sage/matrix/matrix_polynomial_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_polynomial_dense.pxd +5 -0
- sage/matrix/matrix_polynomial_dense.pyx +5341 -0
- sage/matrix/matrix_real_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_real_double_dense.pxd +7 -0
- sage/matrix/matrix_real_double_dense.pyx +122 -0
- sage/matrix/matrix_space.py +2848 -0
- sage/matrix/matrix_sparse.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_sparse.pxd +5 -0
- sage/matrix/matrix_sparse.pyx +1222 -0
- sage/matrix/matrix_window.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_window.pxd +37 -0
- sage/matrix/matrix_window.pyx +242 -0
- sage/matrix/misc_mpfr.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/misc_mpfr.pyx +80 -0
- sage/matrix/operation_table.py +1182 -0
- sage/matrix/special.py +3666 -0
- sage/matrix/strassen.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matrix/strassen.pyx +851 -0
- sage/matrix/symplectic_basis.py +541 -0
- sage/matrix/template.pxd +6 -0
- sage/matrix/tests.py +71 -0
- sage/matroids/advanced.py +77 -0
- sage/matroids/all.py +13 -0
- sage/matroids/basis_exchange_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/basis_exchange_matroid.pxd +96 -0
- sage/matroids/basis_exchange_matroid.pyx +2344 -0
- sage/matroids/basis_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/basis_matroid.pxd +45 -0
- sage/matroids/basis_matroid.pyx +1217 -0
- sage/matroids/catalog.py +44 -0
- sage/matroids/chow_ring.py +473 -0
- sage/matroids/chow_ring_ideal.py +849 -0
- sage/matroids/circuit_closures_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/circuit_closures_matroid.pxd +16 -0
- sage/matroids/circuit_closures_matroid.pyx +559 -0
- sage/matroids/circuits_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/circuits_matroid.pxd +38 -0
- sage/matroids/circuits_matroid.pyx +947 -0
- sage/matroids/constructor.py +1086 -0
- sage/matroids/database_collections.py +365 -0
- sage/matroids/database_matroids.py +5338 -0
- sage/matroids/dual_matroid.py +583 -0
- sage/matroids/extension.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/extension.pxd +34 -0
- sage/matroids/extension.pyx +519 -0
- sage/matroids/flats_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/flats_matroid.pxd +28 -0
- sage/matroids/flats_matroid.pyx +715 -0
- sage/matroids/gammoid.py +600 -0
- sage/matroids/graphic_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/graphic_matroid.pxd +39 -0
- sage/matroids/graphic_matroid.pyx +2024 -0
- sage/matroids/lean_matrix.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/lean_matrix.pxd +126 -0
- sage/matroids/lean_matrix.pyx +3667 -0
- sage/matroids/linear_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/linear_matroid.pxd +180 -0
- sage/matroids/linear_matroid.pyx +6649 -0
- sage/matroids/matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/matroid.pxd +243 -0
- sage/matroids/matroid.pyx +8759 -0
- sage/matroids/matroids_catalog.py +190 -0
- sage/matroids/matroids_plot_helpers.py +890 -0
- sage/matroids/minor_matroid.py +480 -0
- sage/matroids/minorfix.h +9 -0
- sage/matroids/named_matroids.py +5 -0
- sage/matroids/rank_matroid.py +268 -0
- sage/matroids/set_system.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/set_system.pxd +38 -0
- sage/matroids/set_system.pyx +800 -0
- sage/matroids/transversal_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/transversal_matroid.pxd +14 -0
- sage/matroids/transversal_matroid.pyx +893 -0
- sage/matroids/union_matroid.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/union_matroid.pxd +20 -0
- sage/matroids/union_matroid.pyx +331 -0
- sage/matroids/unpickling.cpython-314-aarch64-linux-musl.so +0 -0
- sage/matroids/unpickling.pyx +843 -0
- sage/matroids/utilities.py +809 -0
- sage/misc/all__sagemath_modules.py +20 -0
- sage/misc/c3.cpython-314-aarch64-linux-musl.so +0 -0
- sage/misc/c3.pyx +238 -0
- sage/misc/compat.py +87 -0
- sage/misc/element_with_label.py +173 -0
- sage/misc/func_persist.py +79 -0
- sage/misc/pickle_old.cpython-314-aarch64-linux-musl.so +0 -0
- sage/misc/pickle_old.pyx +19 -0
- sage/misc/proof.py +7 -0
- sage/misc/replace_dot_all.py +472 -0
- sage/misc/sagedoc_conf.py +168 -0
- sage/misc/sphinxify.py +167 -0
- sage/misc/test_class_pickling.py +85 -0
- sage/modules/all.py +42 -0
- sage/modules/complex_double_vector.py +25 -0
- sage/modules/diamond_cutting.py +380 -0
- sage/modules/fg_pid/all.py +1 -0
- sage/modules/fg_pid/fgp_element.py +456 -0
- sage/modules/fg_pid/fgp_module.py +2091 -0
- sage/modules/fg_pid/fgp_morphism.py +550 -0
- sage/modules/filtered_vector_space.py +1271 -0
- sage/modules/finite_submodule_iter.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/finite_submodule_iter.pxd +27 -0
- sage/modules/finite_submodule_iter.pyx +452 -0
- sage/modules/fp_graded/all.py +1 -0
- sage/modules/fp_graded/element.py +346 -0
- sage/modules/fp_graded/free_element.py +298 -0
- sage/modules/fp_graded/free_homspace.py +53 -0
- sage/modules/fp_graded/free_module.py +1060 -0
- sage/modules/fp_graded/free_morphism.py +217 -0
- sage/modules/fp_graded/homspace.py +563 -0
- sage/modules/fp_graded/module.py +1340 -0
- sage/modules/fp_graded/morphism.py +1990 -0
- sage/modules/fp_graded/steenrod/all.py +1 -0
- sage/modules/fp_graded/steenrod/homspace.py +65 -0
- sage/modules/fp_graded/steenrod/module.py +477 -0
- sage/modules/fp_graded/steenrod/morphism.py +404 -0
- sage/modules/fp_graded/steenrod/profile.py +241 -0
- sage/modules/free_module.py +8447 -0
- sage/modules/free_module_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/free_module_element.pxd +22 -0
- sage/modules/free_module_element.pyx +5445 -0
- sage/modules/free_module_homspace.py +369 -0
- sage/modules/free_module_integer.py +896 -0
- sage/modules/free_module_morphism.py +823 -0
- sage/modules/free_module_pseudohomspace.py +352 -0
- sage/modules/free_module_pseudomorphism.py +578 -0
- sage/modules/free_quadratic_module.py +1706 -0
- sage/modules/free_quadratic_module_integer_symmetric.py +1790 -0
- sage/modules/matrix_morphism.py +1745 -0
- sage/modules/misc.py +103 -0
- sage/modules/module_functors.py +192 -0
- sage/modules/multi_filtered_vector_space.py +719 -0
- sage/modules/ore_module.py +2208 -0
- sage/modules/ore_module_element.py +178 -0
- sage/modules/ore_module_homspace.py +147 -0
- sage/modules/ore_module_morphism.py +968 -0
- sage/modules/quotient_module.py +699 -0
- sage/modules/real_double_vector.py +22 -0
- sage/modules/submodule.py +255 -0
- sage/modules/tensor_operations.py +567 -0
- sage/modules/torsion_quadratic_module.py +1352 -0
- sage/modules/tutorial_free_modules.py +248 -0
- sage/modules/vector_complex_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_complex_double_dense.pxd +6 -0
- sage/modules/vector_complex_double_dense.pyx +117 -0
- sage/modules/vector_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_double_dense.pxd +6 -0
- sage/modules/vector_double_dense.pyx +604 -0
- sage/modules/vector_integer_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_integer_dense.pxd +15 -0
- sage/modules/vector_integer_dense.pyx +361 -0
- sage/modules/vector_integer_sparse.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_integer_sparse.pxd +29 -0
- sage/modules/vector_integer_sparse.pyx +406 -0
- sage/modules/vector_modn_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_modn_dense.pxd +12 -0
- sage/modules/vector_modn_dense.pyx +394 -0
- sage/modules/vector_modn_sparse.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_modn_sparse.pxd +21 -0
- sage/modules/vector_modn_sparse.pyx +298 -0
- sage/modules/vector_numpy_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_numpy_dense.pxd +15 -0
- sage/modules/vector_numpy_dense.pyx +304 -0
- sage/modules/vector_numpy_integer_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_numpy_integer_dense.pxd +7 -0
- sage/modules/vector_numpy_integer_dense.pyx +54 -0
- sage/modules/vector_rational_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_rational_dense.pxd +15 -0
- sage/modules/vector_rational_dense.pyx +387 -0
- sage/modules/vector_rational_sparse.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_rational_sparse.pxd +30 -0
- sage/modules/vector_rational_sparse.pyx +413 -0
- sage/modules/vector_real_double_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/vector_real_double_dense.pxd +6 -0
- sage/modules/vector_real_double_dense.pyx +126 -0
- sage/modules/vector_space_homspace.py +430 -0
- sage/modules/vector_space_morphism.py +989 -0
- sage/modules/with_basis/all.py +15 -0
- sage/modules/with_basis/cell_module.py +494 -0
- sage/modules/with_basis/indexed_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/modules/with_basis/indexed_element.pxd +13 -0
- sage/modules/with_basis/indexed_element.pyx +1058 -0
- sage/modules/with_basis/invariant.py +1075 -0
- sage/modules/with_basis/morphism.py +1636 -0
- sage/modules/with_basis/representation.py +2939 -0
- sage/modules/with_basis/subquotient.py +685 -0
- sage/numerical/all__sagemath_modules.py +6 -0
- sage/numerical/gauss_legendre.cpython-314-aarch64-linux-musl.so +0 -0
- sage/numerical/gauss_legendre.pyx +381 -0
- sage/numerical/optimize.py +910 -0
- sage/probability/all.py +10 -0
- sage/probability/probability_distribution.cpython-314-aarch64-linux-musl.so +0 -0
- sage/probability/probability_distribution.pyx +1242 -0
- sage/probability/random_variable.py +411 -0
- sage/quadratic_forms/all.py +4 -0
- sage/quadratic_forms/all__sagemath_modules.py +15 -0
- sage/quadratic_forms/binary_qf.py +2042 -0
- sage/quadratic_forms/bqf_class_group.py +748 -0
- sage/quadratic_forms/constructions.py +93 -0
- sage/quadratic_forms/count_local_2.cpython-314-aarch64-linux-musl.so +0 -0
- sage/quadratic_forms/count_local_2.pyx +365 -0
- sage/quadratic_forms/extras.py +195 -0
- sage/quadratic_forms/quadratic_form.py +1753 -0
- sage/quadratic_forms/quadratic_form__count_local_2.py +221 -0
- sage/quadratic_forms/quadratic_form__equivalence_testing.py +708 -0
- sage/quadratic_forms/quadratic_form__evaluate.cpython-314-aarch64-linux-musl.so +0 -0
- sage/quadratic_forms/quadratic_form__evaluate.pyx +139 -0
- sage/quadratic_forms/quadratic_form__local_density_congruence.py +977 -0
- sage/quadratic_forms/quadratic_form__local_field_invariants.py +1072 -0
- sage/quadratic_forms/quadratic_form__neighbors.py +424 -0
- sage/quadratic_forms/quadratic_form__reduction_theory.py +488 -0
- sage/quadratic_forms/quadratic_form__split_local_covering.py +416 -0
- sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +657 -0
- sage/quadratic_forms/quadratic_form__theta.py +352 -0
- sage/quadratic_forms/quadratic_form__variable_substitutions.py +370 -0
- sage/quadratic_forms/random_quadraticform.py +209 -0
- sage/quadratic_forms/ternary.cpython-314-aarch64-linux-musl.so +0 -0
- sage/quadratic_forms/ternary.pyx +1154 -0
- sage/quadratic_forms/ternary_qf.py +2027 -0
- sage/rings/all__sagemath_modules.py +28 -0
- sage/rings/asymptotic/all__sagemath_modules.py +1 -0
- sage/rings/asymptotic/misc.py +1252 -0
- sage/rings/cc.py +4 -0
- sage/rings/cfinite_sequence.py +1306 -0
- sage/rings/complex_conversion.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/complex_conversion.pxd +8 -0
- sage/rings/complex_conversion.pyx +23 -0
- sage/rings/complex_double.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/complex_double.pxd +21 -0
- sage/rings/complex_double.pyx +2654 -0
- sage/rings/complex_mpc.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/complex_mpc.pxd +21 -0
- sage/rings/complex_mpc.pyx +2576 -0
- sage/rings/complex_mpfr.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/complex_mpfr.pxd +18 -0
- sage/rings/complex_mpfr.pyx +3602 -0
- sage/rings/derivation.py +2334 -0
- sage/rings/finite_rings/all__sagemath_modules.py +1 -0
- sage/rings/finite_rings/maps_finite_field.py +191 -0
- sage/rings/function_field/all__sagemath_modules.py +8 -0
- sage/rings/function_field/derivations.py +102 -0
- sage/rings/function_field/derivations_rational.py +132 -0
- sage/rings/function_field/differential.py +853 -0
- sage/rings/function_field/divisor.py +1107 -0
- sage/rings/function_field/drinfeld_modules/action.py +199 -0
- sage/rings/function_field/drinfeld_modules/all.py +1 -0
- sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py +673 -0
- sage/rings/function_field/drinfeld_modules/drinfeld_module.py +2087 -0
- sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +1131 -0
- sage/rings/function_field/drinfeld_modules/homset.py +420 -0
- sage/rings/function_field/drinfeld_modules/morphism.py +820 -0
- sage/rings/function_field/hermite_form_polynomial.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/hermite_form_polynomial.pyx +188 -0
- sage/rings/function_field/khuri_makdisi.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/khuri_makdisi.pyx +935 -0
- sage/rings/invariants/all.py +4 -0
- sage/rings/invariants/invariant_theory.py +4597 -0
- sage/rings/invariants/reconstruction.py +395 -0
- sage/rings/polynomial/all__sagemath_modules.py +17 -0
- sage/rings/polynomial/integer_valued_polynomials.py +1230 -0
- sage/rings/polynomial/laurent_polynomial_mpair.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/laurent_polynomial_mpair.pxd +15 -0
- sage/rings/polynomial/laurent_polynomial_mpair.pyx +2023 -0
- sage/rings/polynomial/ore_function_element.py +952 -0
- sage/rings/polynomial/ore_function_field.py +1028 -0
- sage/rings/polynomial/ore_polynomial_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/ore_polynomial_element.pxd +48 -0
- sage/rings/polynomial/ore_polynomial_element.pyx +3145 -0
- sage/rings/polynomial/ore_polynomial_ring.py +1334 -0
- sage/rings/polynomial/polynomial_real_mpfr_dense.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +788 -0
- sage/rings/polynomial/q_integer_valued_polynomials.py +1264 -0
- sage/rings/polynomial/skew_polynomial_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/skew_polynomial_element.pxd +9 -0
- sage/rings/polynomial/skew_polynomial_element.pyx +684 -0
- sage/rings/polynomial/skew_polynomial_finite_field.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_field.pxd +19 -0
- sage/rings/polynomial/skew_polynomial_finite_field.pyx +1093 -0
- sage/rings/polynomial/skew_polynomial_finite_order.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/skew_polynomial_finite_order.pxd +10 -0
- sage/rings/polynomial/skew_polynomial_finite_order.pyx +567 -0
- sage/rings/polynomial/skew_polynomial_ring.py +908 -0
- sage/rings/real_double_element_gsl.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/real_double_element_gsl.pxd +8 -0
- sage/rings/real_double_element_gsl.pyx +794 -0
- sage/rings/real_field.py +58 -0
- sage/rings/real_mpfr.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/real_mpfr.pxd +29 -0
- sage/rings/real_mpfr.pyx +6122 -0
- sage/rings/ring_extension.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/ring_extension.pxd +42 -0
- sage/rings/ring_extension.pyx +2779 -0
- sage/rings/ring_extension_conversion.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/ring_extension_conversion.pxd +16 -0
- sage/rings/ring_extension_conversion.pyx +462 -0
- sage/rings/ring_extension_element.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/ring_extension_element.pxd +21 -0
- sage/rings/ring_extension_element.pyx +1635 -0
- sage/rings/ring_extension_homset.py +64 -0
- sage/rings/ring_extension_morphism.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/ring_extension_morphism.pxd +35 -0
- sage/rings/ring_extension_morphism.pyx +920 -0
- sage/schemes/all__sagemath_modules.py +1 -0
- sage/schemes/projective/all__sagemath_modules.py +1 -0
- sage/schemes/projective/coherent_sheaf.py +300 -0
- sage/schemes/projective/cohomology.py +510 -0
- sage/stats/all.py +15 -0
- sage/stats/basic_stats.py +489 -0
- sage/stats/distributions/all.py +7 -0
- sage/stats/distributions/catalog.py +34 -0
- sage/stats/distributions/dgs.h +50 -0
- sage/stats/distributions/dgs.pxd +111 -0
- sage/stats/distributions/dgs_bern.h +400 -0
- sage/stats/distributions/dgs_gauss.h +614 -0
- sage/stats/distributions/dgs_misc.h +104 -0
- sage/stats/distributions/discrete_gaussian_integer.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/distributions/discrete_gaussian_integer.pxd +14 -0
- sage/stats/distributions/discrete_gaussian_integer.pyx +498 -0
- sage/stats/distributions/discrete_gaussian_lattice.py +908 -0
- sage/stats/distributions/discrete_gaussian_polynomial.py +141 -0
- sage/stats/hmm/all.py +15 -0
- sage/stats/hmm/chmm.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/hmm/chmm.pyx +1595 -0
- sage/stats/hmm/distributions.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/hmm/distributions.pxd +29 -0
- sage/stats/hmm/distributions.pyx +531 -0
- sage/stats/hmm/hmm.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/hmm/hmm.pxd +17 -0
- sage/stats/hmm/hmm.pyx +1388 -0
- sage/stats/hmm/util.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/hmm/util.pxd +7 -0
- sage/stats/hmm/util.pyx +165 -0
- sage/stats/intlist.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/intlist.pxd +14 -0
- sage/stats/intlist.pyx +588 -0
- sage/stats/r.py +49 -0
- sage/stats/time_series.cpython-314-aarch64-linux-musl.so +0 -0
- sage/stats/time_series.pxd +6 -0
- sage/stats/time_series.pyx +2546 -0
- sage/tensor/all.py +2 -0
- sage/tensor/modules/all.py +8 -0
- sage/tensor/modules/alternating_contr_tensor.py +761 -0
- sage/tensor/modules/comp.py +5598 -0
- sage/tensor/modules/ext_pow_free_module.py +824 -0
- sage/tensor/modules/finite_rank_free_module.py +3589 -0
- sage/tensor/modules/format_utilities.py +333 -0
- sage/tensor/modules/free_module_alt_form.py +858 -0
- sage/tensor/modules/free_module_automorphism.py +1207 -0
- sage/tensor/modules/free_module_basis.py +1074 -0
- sage/tensor/modules/free_module_element.py +284 -0
- sage/tensor/modules/free_module_homset.py +652 -0
- sage/tensor/modules/free_module_linear_group.py +564 -0
- sage/tensor/modules/free_module_morphism.py +1581 -0
- sage/tensor/modules/free_module_tensor.py +3289 -0
- sage/tensor/modules/reflexive_module.py +386 -0
- sage/tensor/modules/tensor_free_module.py +780 -0
- sage/tensor/modules/tensor_free_submodule.py +538 -0
- sage/tensor/modules/tensor_free_submodule_basis.py +140 -0
- 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)
|