passagemath-modules 10.6.31rc3__cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-modules might be problematic. Click here for more details.
- 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 +6 -0
- passagemath_modules-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_modules.libs/libgfortran-83c28eba.so.5.0.0 +0 -0
- passagemath_modules.libs/libgmp-6e109695.so.10.5.0 +0 -0
- passagemath_modules.libs/libgsl-cda90e79.so.28.0.0 +0 -0
- passagemath_modules.libs/libmpc-7f678fcf.so.3.3.1 +0 -0
- passagemath_modules.libs/libmpfr-82690d50.so.6.2.1 +0 -0
- passagemath_modules.libs/libopenblasp-r0-6dcb67f9.3.29.so +0 -0
- passagemath_modules.libs/libquadmath-2284e583.so.0.0.0 +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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.so +0 -0
- sage/calculus/integration.pyx +698 -0
- sage/calculus/interpolation.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/calculus/interpolation.pxd +13 -0
- sage/calculus/interpolation.pyx +387 -0
- sage/calculus/interpolators.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/calculus/interpolators.pyx +326 -0
- sage/calculus/ode.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/calculus/ode.pxd +5 -0
- sage/calculus/ode.pyx +610 -0
- sage/calculus/riemann.cpython-314-x86_64-linux-gnu.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-x86_64-linux-gnu.so +0 -0
- sage/calculus/transforms/dwt.pxd +7 -0
- sage/calculus/transforms/dwt.pyx +160 -0
- sage/calculus/transforms/fft.cpython-314-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.so +0 -0
- sage/libs/mpmath/utils.pxd +4 -0
- sage/libs/mpmath/utils.pyx +319 -0
- sage/matrix/action.cpython-314-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.so +0 -0
- sage/matrix/constructor.pyx +750 -0
- sage/matrix/docs.py +430 -0
- sage/matrix/echelon_matrix.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/matrix/echelon_matrix.pyx +155 -0
- sage/matrix/matrix.pxd +2 -0
- sage/matrix/matrix0.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix0.pxd +68 -0
- sage/matrix/matrix0.pyx +6324 -0
- sage/matrix/matrix1.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix1.pxd +8 -0
- sage/matrix/matrix1.pyx +2851 -0
- sage/matrix/matrix2.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix2.pxd +25 -0
- sage/matrix/matrix2.pyx +20181 -0
- sage/matrix/matrix_cdv.cpython-314-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_sparse.pxd +5 -0
- sage/matrix/matrix_sparse.pyx +1222 -0
- sage/matrix/matrix_window.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_window.pxd +37 -0
- sage/matrix/matrix_window.pyx +242 -0
- sage/matrix/misc_mpfr.cpython-314-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.so +0 -0
- sage/matroids/extension.pxd +34 -0
- sage/matroids/extension.pyx +519 -0
- sage/matroids/flats_matroid.cpython-314-x86_64-linux-gnu.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-x86_64-linux-gnu.so +0 -0
- sage/matroids/graphic_matroid.pxd +39 -0
- sage/matroids/graphic_matroid.pyx +2024 -0
- sage/matroids/lean_matrix.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/matroids/lean_matrix.pxd +126 -0
- sage/matroids/lean_matrix.pyx +3667 -0
- sage/matroids/linear_matroid.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/matroids/linear_matroid.pxd +180 -0
- sage/matroids/linear_matroid.pyx +6649 -0
- sage/matroids/matroid.cpython-314-x86_64-linux-gnu.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-x86_64-linux-gnu.so +0 -0
- sage/matroids/set_system.pxd +38 -0
- sage/matroids/set_system.pyx +800 -0
- sage/matroids/transversal_matroid.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/matroids/transversal_matroid.pxd +14 -0
- sage/matroids/transversal_matroid.pyx +893 -0
- sage/matroids/union_matroid.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/matroids/union_matroid.pxd +20 -0
- sage/matroids/union_matroid.pyx +331 -0
- sage/matroids/unpickling.cpython-314-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.so +0 -0
- sage/rings/complex_conversion.pxd +8 -0
- sage/rings/complex_conversion.pyx +23 -0
- sage/rings/complex_double.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/rings/complex_double.pxd +21 -0
- sage/rings/complex_double.pyx +2654 -0
- sage/rings/complex_mpc.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/rings/complex_mpc.pxd +21 -0
- sage/rings/complex_mpc.pyx +2576 -0
- sage/rings/complex_mpfr.cpython-314-x86_64-linux-gnu.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-x86_64-linux-gnu.so +0 -0
- sage/rings/function_field/hermite_form_polynomial.pyx +188 -0
- sage/rings/function_field/khuri_makdisi.cpython-314-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.so +0 -0
- sage/rings/real_mpfr.pxd +29 -0
- sage/rings/real_mpfr.pyx +6122 -0
- sage/rings/ring_extension.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/rings/ring_extension.pxd +42 -0
- sage/rings/ring_extension.pyx +2779 -0
- sage/rings/ring_extension_conversion.cpython-314-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.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-x86_64-linux-gnu.so +0 -0
- sage/stats/hmm/chmm.pyx +1595 -0
- sage/stats/hmm/distributions.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/stats/hmm/distributions.pxd +29 -0
- sage/stats/hmm/distributions.pyx +531 -0
- sage/stats/hmm/hmm.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/stats/hmm/hmm.pxd +17 -0
- sage/stats/hmm/hmm.pyx +1388 -0
- sage/stats/hmm/util.cpython-314-x86_64-linux-gnu.so +0 -0
- sage/stats/hmm/util.pxd +7 -0
- sage/stats/hmm/util.pyx +165 -0
- sage/stats/intlist.cpython-314-x86_64-linux-gnu.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-x86_64-linux-gnu.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,2024 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-modules
|
|
2
|
+
# sage.doctest: optional - sage.graphs
|
|
3
|
+
r"""
|
|
4
|
+
Graphic matroids
|
|
5
|
+
|
|
6
|
+
Let `G = (V,E)` be a graph and let `C` be the collection of the edge sets
|
|
7
|
+
of cycles in `G`. The corresponding graphic matroid `M(G)` has groundset `E`
|
|
8
|
+
and circuits `C`.
|
|
9
|
+
|
|
10
|
+
Construction
|
|
11
|
+
============
|
|
12
|
+
|
|
13
|
+
The recommended way to create a graphic matroid is by using the
|
|
14
|
+
:func:`Matroid() <sage.matroids.constructor.Matroid>` function, with a
|
|
15
|
+
graph `G` as input. This function can accept many different kinds of input
|
|
16
|
+
to get a graphic matroid if the ``graph`` keyword is used, similar to the
|
|
17
|
+
:func:`Graph() <sage.graphs.graph.Graph>` constructor. However,
|
|
18
|
+
invoking the class directly is possible too. To get access to it, type::
|
|
19
|
+
|
|
20
|
+
sage: from sage.matroids.advanced import *
|
|
21
|
+
|
|
22
|
+
See also :mod:`sage.matroids.advanced`.
|
|
23
|
+
|
|
24
|
+
Graphic matroids do not have a representation matrix or any of the
|
|
25
|
+
functionality of regular matroids. It is possible to get an instance of the
|
|
26
|
+
:class:`~sage.matroids.linear_matroid.RegularMatroid` class by using the
|
|
27
|
+
``regular`` keyword when constructing the matroid. It is also possible to cast
|
|
28
|
+
a :class:`GraphicMatroid` as a :class:`RegularMatroid` with the
|
|
29
|
+
:meth:`~sage.matroids.graphic_matroids.GraphicMatroid.regular_matroid`
|
|
30
|
+
method::
|
|
31
|
+
|
|
32
|
+
sage: M1 = Matroid(graphs.DiamondGraph(), regular=True)
|
|
33
|
+
sage: M2 = Matroid(graphs.DiamondGraph())
|
|
34
|
+
sage: M3 = M2.regular_matroid()
|
|
35
|
+
|
|
36
|
+
Below are some examples of constructing a graphic matroid.
|
|
37
|
+
|
|
38
|
+
::
|
|
39
|
+
|
|
40
|
+
sage: from sage.matroids.advanced import *
|
|
41
|
+
sage: edgelist = [(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'c')]
|
|
42
|
+
sage: G = Graph(edgelist)
|
|
43
|
+
sage: M1 = Matroid(G)
|
|
44
|
+
sage: M2 = Matroid(graph=edgelist)
|
|
45
|
+
sage: M3 = Matroid(graphs.CycleGraph(3))
|
|
46
|
+
sage: M1 == M3
|
|
47
|
+
False
|
|
48
|
+
sage: M1.is_isomorphic(M3)
|
|
49
|
+
True
|
|
50
|
+
sage: M1.equals(M2)
|
|
51
|
+
True
|
|
52
|
+
sage: M1 == M2
|
|
53
|
+
True
|
|
54
|
+
sage: isinstance(M1, GraphicMatroid)
|
|
55
|
+
True
|
|
56
|
+
sage: isinstance(M1, RegularMatroid)
|
|
57
|
+
False
|
|
58
|
+
|
|
59
|
+
Note that if there is not a complete set of unique edge labels, and
|
|
60
|
+
there are no parallel edges, then vertex tuples will be used for the
|
|
61
|
+
groundset. The user may wish to override this by specifying the
|
|
62
|
+
groundset, as the vertex tuples will not be updated if the matroid is
|
|
63
|
+
modified::
|
|
64
|
+
|
|
65
|
+
sage: G = graphs.DiamondGraph()
|
|
66
|
+
sage: M1 = Matroid(G)
|
|
67
|
+
sage: N1 = M1.contract((0,1))
|
|
68
|
+
sage: N1.graph().edges_incident(0, sort=True)
|
|
69
|
+
[(0, 2, (0, 2)), (0, 2, (1, 2)), (0, 3, (1, 3))]
|
|
70
|
+
sage: M2 = Matroid(range(G.num_edges()), G)
|
|
71
|
+
sage: N2 = M2.contract(0)
|
|
72
|
+
sage: N1.is_isomorphic(N2)
|
|
73
|
+
True
|
|
74
|
+
|
|
75
|
+
AUTHORS:
|
|
76
|
+
|
|
77
|
+
- Zachary Gershkoff (2017-07-07): initial version
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
# ****************************************************************************
|
|
81
|
+
# Copyright (C) 2017 Zachary Gershkoff <zgersh2@lsu.edu>
|
|
82
|
+
#
|
|
83
|
+
#
|
|
84
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
85
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
86
|
+
# the License, or (at your option) any later version.
|
|
87
|
+
# https://www.gnu.org/licenses/
|
|
88
|
+
# ****************************************************************************
|
|
89
|
+
|
|
90
|
+
from sage.matroids.matroid cimport Matroid
|
|
91
|
+
from copy import copy
|
|
92
|
+
from sage.matroids.utilities import newlabel, split_vertex, sanitize_contractions_deletions
|
|
93
|
+
from itertools import combinations
|
|
94
|
+
from sage.rings.integer import Integer
|
|
95
|
+
from sage.sets.disjoint_set cimport DisjointSet_of_hashables
|
|
96
|
+
|
|
97
|
+
cdef class GraphicMatroid(Matroid):
|
|
98
|
+
r"""
|
|
99
|
+
The graphic matroid class.
|
|
100
|
+
|
|
101
|
+
INPUT:
|
|
102
|
+
|
|
103
|
+
- ``G`` -- :class:`Graph`
|
|
104
|
+
- ``groundset`` -- list (optional); in 1-1 correspondence with ``G.edge_iterator()``
|
|
105
|
+
|
|
106
|
+
OUTPUT: :class:`GraphicMatroid` where the groundset elements are the edges of `G`
|
|
107
|
+
|
|
108
|
+
.. NOTE::
|
|
109
|
+
|
|
110
|
+
If a disconnected graph is given as input, the instance of :class:`GraphicMatroid`
|
|
111
|
+
will connect the graph components and store this as its graph.
|
|
112
|
+
|
|
113
|
+
EXAMPLES::
|
|
114
|
+
|
|
115
|
+
sage: from sage.matroids.advanced import *
|
|
116
|
+
sage: M = GraphicMatroid(graphs.BullGraph()); M
|
|
117
|
+
Graphic matroid of rank 4 on 5 elements
|
|
118
|
+
sage: N = GraphicMatroid(graphs.CompleteBipartiteGraph(3,3)); N
|
|
119
|
+
Graphic matroid of rank 5 on 9 elements
|
|
120
|
+
|
|
121
|
+
A disconnected input will get converted to a connected graph internally::
|
|
122
|
+
|
|
123
|
+
sage: G1 = graphs.CycleGraph(3); G2 = graphs.DiamondGraph()
|
|
124
|
+
sage: G = G1.disjoint_union(G2)
|
|
125
|
+
sage: len(G)
|
|
126
|
+
7
|
|
127
|
+
sage: G.is_connected()
|
|
128
|
+
False
|
|
129
|
+
sage: M = GraphicMatroid(G)
|
|
130
|
+
sage: M
|
|
131
|
+
Graphic matroid of rank 5 on 8 elements
|
|
132
|
+
sage: H = M.graph()
|
|
133
|
+
sage: H
|
|
134
|
+
Looped multi-graph on 6 vertices
|
|
135
|
+
sage: H.is_connected()
|
|
136
|
+
True
|
|
137
|
+
sage: M.is_connected()
|
|
138
|
+
False
|
|
139
|
+
|
|
140
|
+
You can still locate an edge using the vertices of the input graph::
|
|
141
|
+
|
|
142
|
+
sage: G1 = graphs.CycleGraph(3); G2 = graphs.DiamondGraph()
|
|
143
|
+
sage: G = G1.disjoint_union(G2)
|
|
144
|
+
sage: M = Matroid(G)
|
|
145
|
+
sage: H = M.graph()
|
|
146
|
+
sage: vm = M.vertex_map()
|
|
147
|
+
sage: (u, v, l) = G.random_edge()
|
|
148
|
+
sage: H.has_edge(vm[u], vm[v])
|
|
149
|
+
True
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
# necessary (__init__, groundset, _rank)
|
|
153
|
+
|
|
154
|
+
def __init__(self, G, groundset=None):
|
|
155
|
+
"""
|
|
156
|
+
See the class definition for full documentation.
|
|
157
|
+
|
|
158
|
+
EXAMPLES::
|
|
159
|
+
|
|
160
|
+
sage: from sage.matroids.advanced import *
|
|
161
|
+
sage: G1 = graphs.CycleGraph(3); G2 = graphs.DiamondGraph()
|
|
162
|
+
sage: G = G1.disjoint_union(G2)
|
|
163
|
+
sage: M = GraphicMatroid(G); M
|
|
164
|
+
Graphic matroid of rank 5 on 8 elements
|
|
165
|
+
sage: M.graph()
|
|
166
|
+
Looped multi-graph on 6 vertices
|
|
167
|
+
sage: M.graph().is_connected()
|
|
168
|
+
True
|
|
169
|
+
sage: M.is_connected()
|
|
170
|
+
False
|
|
171
|
+
|
|
172
|
+
TESTS::
|
|
173
|
+
|
|
174
|
+
sage: TestSuite(M).run(verbose=True)
|
|
175
|
+
running ._test_category() . . . pass
|
|
176
|
+
running ._test_new() . . . pass
|
|
177
|
+
running ._test_not_implemented_methods() . . . pass
|
|
178
|
+
running ._test_pickling() . . . pass
|
|
179
|
+
"""
|
|
180
|
+
from sage.graphs.graph import Graph
|
|
181
|
+
|
|
182
|
+
if groundset is None:
|
|
183
|
+
# Try to construct a groundset based on the edge labels.
|
|
184
|
+
# If that fails, use range() to come up with a groundset.
|
|
185
|
+
groundset = G.edge_labels()
|
|
186
|
+
|
|
187
|
+
groundset_set = frozenset(groundset)
|
|
188
|
+
|
|
189
|
+
# if the provided groundset is incomplete, it gets overwritten
|
|
190
|
+
# invalidate ``None`` as label
|
|
191
|
+
if None in groundset_set or len(groundset_set) != G.num_edges():
|
|
192
|
+
groundset = range(G.num_edges())
|
|
193
|
+
groundset_set = frozenset(groundset)
|
|
194
|
+
|
|
195
|
+
self._groundset = groundset_set
|
|
196
|
+
|
|
197
|
+
# Map vertices on input graph to vertices in self._G
|
|
198
|
+
self._vertex_map = {v: v for v in G.vertex_iterator()}
|
|
199
|
+
comps = G.connected_components(sort=False)
|
|
200
|
+
while len(comps) > 1:
|
|
201
|
+
comp = comps.pop()
|
|
202
|
+
v1 = comps[-1][-1]
|
|
203
|
+
v2 = comp[0]
|
|
204
|
+
self._vertex_map[v2] = v1
|
|
205
|
+
comps[-1].extend(comp)
|
|
206
|
+
|
|
207
|
+
# Construct a graph and assign edge labels corresponding to the groundset
|
|
208
|
+
edge_list = []
|
|
209
|
+
for i, e in enumerate(G.edge_iterator()):
|
|
210
|
+
# the ordering from edge_labels() respects edge_iterator() and not edges()
|
|
211
|
+
edge_list.append((self._vertex_map[e[0]],
|
|
212
|
+
self._vertex_map[e[1]], groundset[i]))
|
|
213
|
+
# If the matroid is empty, have the internal graph be a single vertex
|
|
214
|
+
if edge_list:
|
|
215
|
+
self._G = Graph(edge_list, loops=True, multiedges=True,
|
|
216
|
+
weighted=True, data_structure='static_sparse')
|
|
217
|
+
else:
|
|
218
|
+
self._G = Graph(1, loops=True, multiedges=True,
|
|
219
|
+
weighted=True, data_structure='static_sparse')
|
|
220
|
+
# Map groundset elements to graph edges:
|
|
221
|
+
# The edge labels should already be the elements.
|
|
222
|
+
self._groundset_edge_map = ({l: (u, v) for (u, v, l) in self._G.edge_iterator()})
|
|
223
|
+
|
|
224
|
+
cpdef frozenset groundset(self):
|
|
225
|
+
"""
|
|
226
|
+
Return the groundset of the matroid as a frozenset.
|
|
227
|
+
|
|
228
|
+
EXAMPLES::
|
|
229
|
+
|
|
230
|
+
sage: M = Matroid(graphs.DiamondGraph())
|
|
231
|
+
sage: sorted(M.groundset())
|
|
232
|
+
[(0, 1), (0, 2), (1, 2), (1, 3), (2, 3)]
|
|
233
|
+
sage: G = graphs.CompleteGraph(3).disjoint_union(graphs.CompleteGraph(4))
|
|
234
|
+
sage: M = Matroid(range(G.num_edges()), G); sorted(M.groundset())
|
|
235
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8]
|
|
236
|
+
sage: M = Matroid(Graph([(0, 1, 'a'), (0, 2, 'b'), (0, 3, 'c')]))
|
|
237
|
+
sage: sorted(M.groundset())
|
|
238
|
+
['a', 'b', 'c']
|
|
239
|
+
"""
|
|
240
|
+
return self._groundset
|
|
241
|
+
|
|
242
|
+
cpdef int _rank(self, frozenset X) except? -1:
|
|
243
|
+
"""
|
|
244
|
+
Return the rank of a set ``X``.
|
|
245
|
+
|
|
246
|
+
This method does no checking on ``X``, and ``X`` may be assumed to have
|
|
247
|
+
the same interface as ``frozenset``.
|
|
248
|
+
|
|
249
|
+
INPUT:
|
|
250
|
+
|
|
251
|
+
- ``X`` -- an object with Python's ``frozenset`` interface
|
|
252
|
+
|
|
253
|
+
OUTPUT: the rank of `X` in the matroid
|
|
254
|
+
|
|
255
|
+
EXAMPLES::
|
|
256
|
+
|
|
257
|
+
sage: from sage.matroids.advanced import *
|
|
258
|
+
sage: edgelist = [(0,0,0), (0,1,1), (0,2,2), (0,3,3), (1,2,4), (1,3,5)]
|
|
259
|
+
sage: M = GraphicMatroid(Graph(edgelist, loops=True, multiedges=True))
|
|
260
|
+
sage: M.rank([0])
|
|
261
|
+
0
|
|
262
|
+
sage: M.rank([1,2])
|
|
263
|
+
2
|
|
264
|
+
sage: M.rank([1,2,4])
|
|
265
|
+
2
|
|
266
|
+
sage: M.rank(M.groundset())
|
|
267
|
+
3
|
|
268
|
+
sage: edgelist = [(0,0,0), (1,2,1), (1,2,2), (2,3,3)]
|
|
269
|
+
sage: M = GraphicMatroid(Graph(edgelist, loops=True, multiedges=True))
|
|
270
|
+
sage: M.rank(M.groundset())
|
|
271
|
+
2
|
|
272
|
+
sage: M.rank([0,3])
|
|
273
|
+
1
|
|
274
|
+
"""
|
|
275
|
+
cdef DisjointSet_of_hashables DS_vertices
|
|
276
|
+
cdef list edges = self.groundset_to_edges(X)
|
|
277
|
+
cdef set vertices = set([u for (u, v, l) in edges]).union([v for (u, v, l) in edges])
|
|
278
|
+
# This counts components:
|
|
279
|
+
DS_vertices = DisjointSet_of_hashables(vertices)
|
|
280
|
+
for (u, v, l) in edges:
|
|
281
|
+
DS_vertices.union(u, v)
|
|
282
|
+
return (len(vertices) - DS_vertices.number_of_subsets())
|
|
283
|
+
|
|
284
|
+
# representation:
|
|
285
|
+
|
|
286
|
+
def _repr_(self):
|
|
287
|
+
"""
|
|
288
|
+
Return a string representation of the matroid.
|
|
289
|
+
|
|
290
|
+
EXAMPLES::
|
|
291
|
+
|
|
292
|
+
sage: M = Matroid(graphs.CompleteGraph(5)); M
|
|
293
|
+
Graphic matroid of rank 4 on 10 elements
|
|
294
|
+
sage: G = Graph([(0, 0), (0, 1), (0, 2), (1, 1), (2, 2)], loops=True)
|
|
295
|
+
sage: M = Matroid(G); M
|
|
296
|
+
Graphic matroid of rank 2 on 5 elements
|
|
297
|
+
"""
|
|
298
|
+
r = self._rank(self._groundset)
|
|
299
|
+
n = len(self._groundset)
|
|
300
|
+
return f'Graphic matroid of rank {r} on {n} elements'
|
|
301
|
+
|
|
302
|
+
# comparison:
|
|
303
|
+
|
|
304
|
+
cpdef _vertex_stars(self):
|
|
305
|
+
"""
|
|
306
|
+
Compute the set of edge labels around each vertex.
|
|
307
|
+
|
|
308
|
+
Internal method for hashing purposes.
|
|
309
|
+
|
|
310
|
+
OUTPUT: a ``frozenset`` of frozensets containing the edge labels
|
|
311
|
+
around each vertex
|
|
312
|
+
|
|
313
|
+
EXAMPLES::
|
|
314
|
+
|
|
315
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
316
|
+
sage: sorted(M._vertex_stars(), key=str)
|
|
317
|
+
[frozenset({0, 1}),
|
|
318
|
+
frozenset({0, 2, 3}),
|
|
319
|
+
frozenset({1, 2, 4}),
|
|
320
|
+
frozenset({3, 4})]
|
|
321
|
+
|
|
322
|
+
sage: N = Matroid(range(5), graphs.BullGraph())
|
|
323
|
+
sage: sorted(N._vertex_stars(), key=str)
|
|
324
|
+
[frozenset({0, 1}),
|
|
325
|
+
frozenset({0, 2, 3}),
|
|
326
|
+
frozenset({1, 2, 4}),
|
|
327
|
+
frozenset({3}),
|
|
328
|
+
frozenset({4})]
|
|
329
|
+
"""
|
|
330
|
+
star_list = []
|
|
331
|
+
for v in self._G.vertices(sort=False):
|
|
332
|
+
star = [l for (_, _, l) in self._G.edges_incident(v)]
|
|
333
|
+
star_list.append(frozenset(star))
|
|
334
|
+
return frozenset(star_list)
|
|
335
|
+
|
|
336
|
+
def __hash__(self):
|
|
337
|
+
r"""
|
|
338
|
+
Return an invariant of the matroid.
|
|
339
|
+
|
|
340
|
+
This function is called when matroids are added to a set. It is very
|
|
341
|
+
desirable to override it so it can distinguish matroids on the same
|
|
342
|
+
groundset, which is a very typical use case!
|
|
343
|
+
|
|
344
|
+
.. WARNING::
|
|
345
|
+
|
|
346
|
+
This method is linked to ``__richcmp__`` (in Cython) and ``__cmp__``
|
|
347
|
+
or ``__eq__``/``__ne__`` (in Python). If you override one, you
|
|
348
|
+
should (and, in Cython, \emph{must}) override the other!
|
|
349
|
+
|
|
350
|
+
EXAMPLES::
|
|
351
|
+
|
|
352
|
+
sage: M = Matroid(graphs.CompleteGraph(3))
|
|
353
|
+
sage: N = Matroid(graphs.CycleGraph(3))
|
|
354
|
+
sage: O = Matroid(graphs.ButterflyGraph())
|
|
355
|
+
sage: hash(M) == hash(N)
|
|
356
|
+
True
|
|
357
|
+
sage: hash(O) == hash(N)
|
|
358
|
+
False
|
|
359
|
+
sage: P = Matroid(Graph([(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'c')]))
|
|
360
|
+
sage: hash(P) == hash(M)
|
|
361
|
+
False
|
|
362
|
+
"""
|
|
363
|
+
return hash(self._vertex_stars())
|
|
364
|
+
|
|
365
|
+
def __eq__(self, other):
|
|
366
|
+
"""
|
|
367
|
+
Compare two matroids.
|
|
368
|
+
|
|
369
|
+
For two graphic matroids to be equal, all attributes of the underlying
|
|
370
|
+
graphs must be equal.
|
|
371
|
+
|
|
372
|
+
INPUT:
|
|
373
|
+
|
|
374
|
+
- ``other`` -- matroid
|
|
375
|
+
|
|
376
|
+
OUTPUT: ``True`` if ``self`` and ``other`` have the same graph;
|
|
377
|
+
``False`` otherwise
|
|
378
|
+
|
|
379
|
+
EXAMPLES::
|
|
380
|
+
|
|
381
|
+
sage: M = Matroid(graphs.CompleteGraph(3))
|
|
382
|
+
sage: N = Matroid(graphs.CycleGraph(3))
|
|
383
|
+
sage: O = Matroid(graphs.ButterflyGraph())
|
|
384
|
+
sage: P = Matroid(Graph([(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'c')]))
|
|
385
|
+
sage: M == N
|
|
386
|
+
True
|
|
387
|
+
sage: M == O
|
|
388
|
+
False
|
|
389
|
+
sage: M == P
|
|
390
|
+
False
|
|
391
|
+
|
|
392
|
+
A more subtle example where the vertex labels differ::
|
|
393
|
+
|
|
394
|
+
sage: G1 = Graph([(0,1,0),(0,2,1),(1,2,2)])
|
|
395
|
+
sage: G2 = Graph([(3,4,3),(3,5,4),(4,5,5),(4,6,6),(5,6,7)])
|
|
396
|
+
sage: G = G1.disjoint_union(G2)
|
|
397
|
+
sage: H = G2.disjoint_union(G1)
|
|
398
|
+
sage: Matroid(G) == Matroid(H)
|
|
399
|
+
False
|
|
400
|
+
sage: Matroid(G).equals(Matroid(H))
|
|
401
|
+
True
|
|
402
|
+
|
|
403
|
+
Same except for vertex labels::
|
|
404
|
+
|
|
405
|
+
sage: G1 = Graph([(0,1,0),(1,2,1),(2,0,2)])
|
|
406
|
+
sage: G2 = Graph([(3,4,0),(4,5,1),(5,3,2)])
|
|
407
|
+
sage: Matroid(G1) == Matroid(G2)
|
|
408
|
+
False
|
|
409
|
+
"""
|
|
410
|
+
# Graph.__eq__() will ignore edge labels unless we turn on weighted()
|
|
411
|
+
# This will be done in __init__()
|
|
412
|
+
if not isinstance(other, GraphicMatroid):
|
|
413
|
+
return False
|
|
414
|
+
return (self._G == other._G)
|
|
415
|
+
|
|
416
|
+
def __ne__(self, other):
|
|
417
|
+
"""
|
|
418
|
+
Compare two matroids.
|
|
419
|
+
|
|
420
|
+
INPUT:
|
|
421
|
+
|
|
422
|
+
- ``other`` -- matroid
|
|
423
|
+
|
|
424
|
+
OUTPUT: ``False`` if ``self`` and ``other`` have the same graph;
|
|
425
|
+
``True`` otherwise
|
|
426
|
+
|
|
427
|
+
EXAMPLES::
|
|
428
|
+
|
|
429
|
+
sage: M = Matroid(range(4), graphs.CycleGraph(4))
|
|
430
|
+
sage: N = Matroid(range(4), graphs.CompleteBipartiteGraph(2,2))
|
|
431
|
+
sage: O = Matroid(graphs.PetersenGraph())
|
|
432
|
+
sage: M != N
|
|
433
|
+
True
|
|
434
|
+
sage: M.equals(N)
|
|
435
|
+
True
|
|
436
|
+
sage: M != O
|
|
437
|
+
True
|
|
438
|
+
"""
|
|
439
|
+
return (not self == other)
|
|
440
|
+
|
|
441
|
+
# copying, loading, saving
|
|
442
|
+
|
|
443
|
+
def __reduce__(self):
|
|
444
|
+
"""
|
|
445
|
+
Save the matroid for later reloading.
|
|
446
|
+
|
|
447
|
+
EXAMPLES::
|
|
448
|
+
|
|
449
|
+
sage: M = Matroid(graphs.PetersenGraph())
|
|
450
|
+
sage: M == loads(dumps(M))
|
|
451
|
+
True
|
|
452
|
+
sage: loads(dumps(M))
|
|
453
|
+
Graphic matroid of rank 9 on 15 elements
|
|
454
|
+
"""
|
|
455
|
+
from sage.matroids.unpickling import unpickle_graphic_matroid
|
|
456
|
+
data = (self._G, self.get_custom_name())
|
|
457
|
+
version = 0
|
|
458
|
+
return unpickle_graphic_matroid, (version, data)
|
|
459
|
+
|
|
460
|
+
# overrides
|
|
461
|
+
|
|
462
|
+
cpdef _minor(self, contractions, deletions):
|
|
463
|
+
"""
|
|
464
|
+
Return a minor.
|
|
465
|
+
|
|
466
|
+
INPUT:
|
|
467
|
+
|
|
468
|
+
- ``contractions`` -- frozenset; subset of ``self.groundset()`` to be contracted
|
|
469
|
+
- ``deletions`` -- frozenset; subset of ``self.groundset()`` to be deleted
|
|
470
|
+
|
|
471
|
+
Assumptions: contractions are independent, deletions are coindependent,
|
|
472
|
+
contractions and deletions are disjoint.
|
|
473
|
+
|
|
474
|
+
OUTPUT: :class:`GraphicMatroid`
|
|
475
|
+
|
|
476
|
+
EXAMPLES::
|
|
477
|
+
|
|
478
|
+
sage: M = matroids.CompleteGraphic(5)
|
|
479
|
+
sage: M._minor(deletions=frozenset([0,1,2]), contractions=frozenset())
|
|
480
|
+
Graphic matroid of rank 4 on 7 elements
|
|
481
|
+
sage: M._minor(deletions=frozenset(), contractions=frozenset([0,1,2]))
|
|
482
|
+
Graphic matroid of rank 1 on 7 elements
|
|
483
|
+
sage: M = Matroid(range(15), graphs.PetersenGraph())
|
|
484
|
+
sage: N = M._minor(deletions=frozenset([0, 3, 5, 9]),
|
|
485
|
+
....: contractions=frozenset([1, 2, 11]))
|
|
486
|
+
sage: N
|
|
487
|
+
Graphic matroid of rank 6 on 8 elements
|
|
488
|
+
"""
|
|
489
|
+
cdef object g = self.graph()
|
|
490
|
+
cdef list cont_edges = self._groundset_to_edges(contractions)
|
|
491
|
+
cdef list del_edges = self._groundset_to_edges(deletions)
|
|
492
|
+
# deletions first so contractions don't mess up the vertices
|
|
493
|
+
g.delete_edges(del_edges)
|
|
494
|
+
g.contract_edges(cont_edges)
|
|
495
|
+
return GraphicMatroid(g)
|
|
496
|
+
|
|
497
|
+
cpdef _has_minor(self, N, bint certificate=False):
|
|
498
|
+
"""
|
|
499
|
+
Check if the matroid has a minor isomorphic to `M(H)`.
|
|
500
|
+
|
|
501
|
+
INPUT:
|
|
502
|
+
|
|
503
|
+
- ``N`` -- matroid
|
|
504
|
+
- ``certificate`` -- boolean (default: ``False``); if ``True``, returns
|
|
505
|
+
the certificate isomorphism from the minor of ``self`` to ``N``
|
|
506
|
+
|
|
507
|
+
OUTPUT:
|
|
508
|
+
|
|
509
|
+
boolean, or tuple if the ``certificate`` option is used. If
|
|
510
|
+
``certificate`` is ``True``, then the output will either be
|
|
511
|
+
``False, None`` or ``True, (X, Y, dic) where ``N`` is isomorphic to
|
|
512
|
+
``self.minor(X, Y)``, and ``dic`` is an isomorphism between ``N`` and
|
|
513
|
+
``self.minor(X, Y)``.
|
|
514
|
+
|
|
515
|
+
EXAMPLES::
|
|
516
|
+
|
|
517
|
+
sage: # needs sage.numerical.mip
|
|
518
|
+
sage: M = Matroid(range(9), graphs.CompleteBipartiteGraph(3, 3))
|
|
519
|
+
sage: N = Matroid(range(3), graphs.CycleGraph(3))
|
|
520
|
+
sage: N1 = Matroid(range(3), graph=graphs.CycleGraph(3),
|
|
521
|
+
....: regular=True)
|
|
522
|
+
sage: _, cert = M._has_minor(N1, certificate=True)
|
|
523
|
+
sage: Mp = M.minor(cert[0], cert[1])
|
|
524
|
+
sage: N.is_isomorphism(Mp, cert[2])
|
|
525
|
+
True
|
|
526
|
+
sage: M._has_minor(N)
|
|
527
|
+
True
|
|
528
|
+
sage: M._has_minor(N1)
|
|
529
|
+
True
|
|
530
|
+
sage: _, cert = M._has_minor(N, certificate=True)
|
|
531
|
+
sage: Mp = M.minor(cert[0], cert[1])
|
|
532
|
+
sage: N.is_isomorphism(Mp, cert[2])
|
|
533
|
+
True
|
|
534
|
+
|
|
535
|
+
::
|
|
536
|
+
|
|
537
|
+
sage: # needs sage.numerical.mip
|
|
538
|
+
sage: M = matroids.CompleteGraphic(6)
|
|
539
|
+
sage: N = Matroid(range(8), graphs.WheelGraph(5))
|
|
540
|
+
sage: M._has_minor(N)
|
|
541
|
+
True
|
|
542
|
+
sage: _, cert = M._has_minor(N, certificate=True)
|
|
543
|
+
sage: Mp = M.minor(cert[0], cert[1])
|
|
544
|
+
sage: N.is_isomorphism(Mp, cert[2])
|
|
545
|
+
True
|
|
546
|
+
sage: N.has_minor(M)
|
|
547
|
+
False
|
|
548
|
+
sage: N.has_minor(M, certificate=True)
|
|
549
|
+
(False, None)
|
|
550
|
+
|
|
551
|
+
If the matroids are not 3-connected, then the default matroid
|
|
552
|
+
algorithms are used::
|
|
553
|
+
|
|
554
|
+
sage: # needs sage.numerical.mip
|
|
555
|
+
sage: M = matroids.CompleteGraphic(6)
|
|
556
|
+
sage: N = Matroid(graphs.CycleGraph(4))
|
|
557
|
+
sage: M.has_minor(N)
|
|
558
|
+
True
|
|
559
|
+
sage: N.has_minor(M)
|
|
560
|
+
False
|
|
561
|
+
"""
|
|
562
|
+
# The graph minor algorithm is faster but it doesn't make sense
|
|
563
|
+
# to use it if M(H) is not 3-connected, because of all the possible
|
|
564
|
+
# Whitney switches or 1-sums that will give the same matroid.
|
|
565
|
+
if isinstance(N, GraphicMatroid) and N.is_3connected():
|
|
566
|
+
# Graph.minor() does not work with multigraphs
|
|
567
|
+
G = self.graph()
|
|
568
|
+
G.allow_loops(False)
|
|
569
|
+
G.allow_multiple_edges(False)
|
|
570
|
+
H = N.graph()
|
|
571
|
+
H.allow_loops(False)
|
|
572
|
+
H.allow_multiple_edges(False)
|
|
573
|
+
|
|
574
|
+
try:
|
|
575
|
+
# Graph.minor() returns a certificate if there is one
|
|
576
|
+
# and a ValueError if there isn't.
|
|
577
|
+
cert = G.minor(H)
|
|
578
|
+
except ValueError:
|
|
579
|
+
if certificate:
|
|
580
|
+
return (False, None)
|
|
581
|
+
else:
|
|
582
|
+
return False
|
|
583
|
+
|
|
584
|
+
if certificate:
|
|
585
|
+
# This is where it gets complicated.
|
|
586
|
+
# The Graph.minor() method gives a dictionary of vertices
|
|
587
|
+
# as its certificate. There is currently no easy way to
|
|
588
|
+
# determine the edges.
|
|
589
|
+
# From the dictionary, we can get an idea of what the
|
|
590
|
+
# contractions are, and what vertices are not used.
|
|
591
|
+
# So we'll merge the appropriate vertices, delete the
|
|
592
|
+
# unused vertices, and pass to Matroid._has_minor().
|
|
593
|
+
|
|
594
|
+
# Determine contractions:
|
|
595
|
+
vertices_for_minor = cert.values()
|
|
596
|
+
contractions = []
|
|
597
|
+
for vertex_list in vertices_for_minor:
|
|
598
|
+
S = G.subgraph(vertex_list)
|
|
599
|
+
X = S.edge_labels()
|
|
600
|
+
contractions.extend(self.max_independent(X))
|
|
601
|
+
|
|
602
|
+
# determine deletions:
|
|
603
|
+
from itertools import chain
|
|
604
|
+
deletions = []
|
|
605
|
+
big_vertex_list = list(chain.from_iterable(vertices_for_minor))
|
|
606
|
+
for v in G.vertices(sort=False):
|
|
607
|
+
if v not in big_vertex_list:
|
|
608
|
+
deletions.extend([l for (u0, v0, l) in G.edges_incident(v)])
|
|
609
|
+
|
|
610
|
+
# take contractions and deletions with what we have so far
|
|
611
|
+
# then use method from abstract matroid class
|
|
612
|
+
conset, delset = sanitize_contractions_deletions(self, contractions, deletions)
|
|
613
|
+
M = self._minor(contractions=conset, deletions=delset)
|
|
614
|
+
_, elements = Matroid._has_minor(M, N, certificate=True)
|
|
615
|
+
|
|
616
|
+
# elements is a tuple (contractions, deletions, dict)
|
|
617
|
+
# There should be no more contractions
|
|
618
|
+
delset = set(delset)
|
|
619
|
+
delset.update(elements[1])
|
|
620
|
+
return (True, (conset, frozenset(delset), elements[2]))
|
|
621
|
+
|
|
622
|
+
else:
|
|
623
|
+
return True
|
|
624
|
+
else:
|
|
625
|
+
# otherwise send it to regular matroids
|
|
626
|
+
M = self.regular_matroid()
|
|
627
|
+
if isinstance(N, GraphicMatroid):
|
|
628
|
+
N = N.regular_matroid()
|
|
629
|
+
return M._has_minor(N, certificate=certificate)
|
|
630
|
+
|
|
631
|
+
cpdef int _corank(self, frozenset X) noexcept:
|
|
632
|
+
"""
|
|
633
|
+
Return the corank of the set `X` in the matroid.
|
|
634
|
+
|
|
635
|
+
Internal version that does no input checking.
|
|
636
|
+
|
|
637
|
+
INPUT:
|
|
638
|
+
|
|
639
|
+
- ``X`` -- an iterable container of groundset elements
|
|
640
|
+
|
|
641
|
+
OUTPUT: integer
|
|
642
|
+
|
|
643
|
+
EXAMPLES::
|
|
644
|
+
|
|
645
|
+
sage: M = Matroid(range(9), graphs.CompleteBipartiteGraph(3,3))
|
|
646
|
+
sage: M._corank(frozenset([0,1,2]))
|
|
647
|
+
2
|
|
648
|
+
sage: M._corank(frozenset([1,2,3]))
|
|
649
|
+
3
|
|
650
|
+
"""
|
|
651
|
+
cdef DisjointSet_of_hashables DS_vertices
|
|
652
|
+
cdef list all_vertices = self._G.vertices(sort=False)
|
|
653
|
+
cdef list not_our_edges = self.groundset_to_edges(self._groundset.difference(X))
|
|
654
|
+
DS_vertices = DisjointSet_of_hashables(all_vertices)
|
|
655
|
+
for u, v, l in not_our_edges:
|
|
656
|
+
DS_vertices.union(u, v)
|
|
657
|
+
return len(X) - (DS_vertices.number_of_subsets() - 1)
|
|
658
|
+
|
|
659
|
+
cpdef bint _is_circuit(self, frozenset X) noexcept:
|
|
660
|
+
"""
|
|
661
|
+
Test if input is a circuit.
|
|
662
|
+
|
|
663
|
+
INPUT:
|
|
664
|
+
|
|
665
|
+
- ``X`` -- an iterable container of groundset elements
|
|
666
|
+
|
|
667
|
+
OUTPUT: boolean
|
|
668
|
+
|
|
669
|
+
EXAMPLES::
|
|
670
|
+
|
|
671
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
672
|
+
sage: M._is_circuit(frozenset([0,1,2]))
|
|
673
|
+
True
|
|
674
|
+
sage: M._is_circuit(frozenset([0,1,2,3]))
|
|
675
|
+
False
|
|
676
|
+
sage: M._is_circuit(frozenset([0,1,3]))
|
|
677
|
+
False
|
|
678
|
+
"""
|
|
679
|
+
cdef object g = self._subgraph_from_set(X)
|
|
680
|
+
return g.is_cycle()
|
|
681
|
+
|
|
682
|
+
cpdef frozenset _closure(self, frozenset X):
|
|
683
|
+
"""
|
|
684
|
+
Return the closure of a set.
|
|
685
|
+
|
|
686
|
+
INPUT:
|
|
687
|
+
|
|
688
|
+
- ``X`` -- an iterable container of groundset elements
|
|
689
|
+
|
|
690
|
+
OUTPUT: a subset of the groundset as a :class:`frozenset`
|
|
691
|
+
|
|
692
|
+
EXAMPLES::
|
|
693
|
+
|
|
694
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
695
|
+
sage: sorted(M._closure(frozenset([0])))
|
|
696
|
+
[0]
|
|
697
|
+
sage: sorted(M._closure(frozenset([0,1])))
|
|
698
|
+
[0, 1, 2]
|
|
699
|
+
sage: sorted(M._closure(M.groundset()))
|
|
700
|
+
[0, 1, 2, 3, 4]
|
|
701
|
+
|
|
702
|
+
TESTS:
|
|
703
|
+
|
|
704
|
+
Make sure the closure gets loops::
|
|
705
|
+
|
|
706
|
+
sage: edgelist = [(0, 0), (0, 1), (0, 2), (0, 3), (1, 2), (1, 2)]
|
|
707
|
+
sage: M = Matroid(range(6), Graph(edgelist, loops=True, multiedges=True))
|
|
708
|
+
sage: M.graph().edges(sort=True)
|
|
709
|
+
[(0, 0, 0), (0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 2, 4), (1, 2, 5)]
|
|
710
|
+
sage: sorted(M._closure(frozenset([4])))
|
|
711
|
+
[0, 4, 5]
|
|
712
|
+
"""
|
|
713
|
+
cdef set XX = set(X)
|
|
714
|
+
cdef frozenset Y = self.groundset().difference(XX)
|
|
715
|
+
cdef list edgelist = self._groundset_to_edges(Y)
|
|
716
|
+
cdef object g = self._subgraph_from_set(XX)
|
|
717
|
+
cdef list V = g.vertices(sort=False)
|
|
718
|
+
cdef int components = g.connected_components_number()
|
|
719
|
+
for e in edgelist:
|
|
720
|
+
# a non-loop edge is in the closure iff both its vertices are
|
|
721
|
+
# in the induced subgraph, and the edge doesn't connect components
|
|
722
|
+
if e[0] in V and e[1] in V:
|
|
723
|
+
g.add_edge(e)
|
|
724
|
+
if g.connected_components_number() >= components:
|
|
725
|
+
XX.add(e[2])
|
|
726
|
+
else:
|
|
727
|
+
g.delete_edge(e)
|
|
728
|
+
# add all loops
|
|
729
|
+
XX.update(set([l for (u, v, l) in self._G.loops()]))
|
|
730
|
+
return frozenset(XX)
|
|
731
|
+
|
|
732
|
+
cpdef frozenset _max_independent(self, frozenset X):
|
|
733
|
+
"""
|
|
734
|
+
Compute a maximal independent subset.
|
|
735
|
+
|
|
736
|
+
INPUT:
|
|
737
|
+
|
|
738
|
+
- ``X`` -- an object with Python's ``frozenset`` interface containing
|
|
739
|
+
a subset of ``self.groundset()``
|
|
740
|
+
|
|
741
|
+
OUTPUT: a subset of the groundset as a :class:`frozenset`
|
|
742
|
+
|
|
743
|
+
EXAMPLES::
|
|
744
|
+
|
|
745
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
746
|
+
sage: sorted(M._max_independent(M.groundset()))
|
|
747
|
+
[0, 1, 3]
|
|
748
|
+
sage: sorted(M._max_independent(frozenset([0,1,2])))
|
|
749
|
+
[0, 1]
|
|
750
|
+
sage: sorted(M._max_independent(frozenset([3,4])))
|
|
751
|
+
[3, 4]
|
|
752
|
+
sage: sorted(M._max_independent(frozenset([3])))
|
|
753
|
+
[3]
|
|
754
|
+
sage: N = M.graphic_extension(0, element='a')
|
|
755
|
+
sage: sorted(N._max_independent(frozenset(['a'])))
|
|
756
|
+
[]
|
|
757
|
+
"""
|
|
758
|
+
cdef DisjointSet_of_hashables DS_vertices
|
|
759
|
+
cdef list edges = self.groundset_to_edges(X)
|
|
760
|
+
cdef set vertices = set([u for (u, v, l) in edges])
|
|
761
|
+
vertices.update([v for (u, v, l) in edges])
|
|
762
|
+
|
|
763
|
+
cdef set our_set = set()
|
|
764
|
+
DS_vertices = DisjointSet_of_hashables(vertices)
|
|
765
|
+
for (u, v, l) in edges:
|
|
766
|
+
if DS_vertices.find(u) != DS_vertices.find(v):
|
|
767
|
+
DS_vertices.union(u, v)
|
|
768
|
+
our_set.add(l)
|
|
769
|
+
return frozenset(our_set)
|
|
770
|
+
|
|
771
|
+
cpdef frozenset _max_coindependent(self, frozenset X):
|
|
772
|
+
"""
|
|
773
|
+
Compute a maximal coindependent subset.
|
|
774
|
+
|
|
775
|
+
INPUT:
|
|
776
|
+
|
|
777
|
+
- ``X`` -- an iterable container of groundset elements
|
|
778
|
+
|
|
779
|
+
OUTPUT: a subset of the groundset as a :class:`frozenset`
|
|
780
|
+
|
|
781
|
+
EXAMPLES::
|
|
782
|
+
|
|
783
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
784
|
+
sage: sorted(M._max_coindependent(M.groundset()))
|
|
785
|
+
[2, 4]
|
|
786
|
+
sage: sorted(M._max_coindependent(frozenset([2,3,4])))
|
|
787
|
+
[2, 4]
|
|
788
|
+
sage: N = M.graphic_extension(0, element=5)
|
|
789
|
+
sage: sorted(N.max_coindependent(frozenset([0,1,2,5])))
|
|
790
|
+
[1, 2, 5]
|
|
791
|
+
"""
|
|
792
|
+
cdef DisjointSet_of_hashables DS_vertices
|
|
793
|
+
cdef list edges = self.groundset_to_edges(X)
|
|
794
|
+
cdef list all_vertices = self._G.vertices(sort=False)
|
|
795
|
+
cdef list not_our_edges = self.groundset_to_edges(self._groundset.difference(X))
|
|
796
|
+
|
|
797
|
+
cdef set our_set = set()
|
|
798
|
+
DS_vertices = DisjointSet_of_hashables(all_vertices)
|
|
799
|
+
for (u, v, l) in not_our_edges:
|
|
800
|
+
DS_vertices.union(u, v)
|
|
801
|
+
|
|
802
|
+
for (u, v, l) in edges:
|
|
803
|
+
if DS_vertices.find(u) == DS_vertices.find(v):
|
|
804
|
+
our_set.add(l)
|
|
805
|
+
else:
|
|
806
|
+
DS_vertices.union(u, v)
|
|
807
|
+
return frozenset(our_set)
|
|
808
|
+
|
|
809
|
+
cpdef frozenset _circuit(self, frozenset X):
|
|
810
|
+
"""
|
|
811
|
+
Return a minimal dependent subset.
|
|
812
|
+
|
|
813
|
+
INPUT:
|
|
814
|
+
|
|
815
|
+
- ``X`` -- an iterable container of groundset elements
|
|
816
|
+
|
|
817
|
+
OUTPUT: ``frozenset`` instance containing a subset of ``X``;
|
|
818
|
+
a :exc:`ValueError` is raised if the set contains no circuit
|
|
819
|
+
|
|
820
|
+
EXAMPLES::
|
|
821
|
+
|
|
822
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
823
|
+
sage: sorted(M._circuit(M.groundset()))
|
|
824
|
+
[0, 1, 2]
|
|
825
|
+
sage: N = Matroid(range(9), graphs.CompleteBipartiteGraph(3,3))
|
|
826
|
+
sage: sorted(N._circuit(frozenset([0, 1, 2, 6, 7, 8])))
|
|
827
|
+
[0, 1, 6, 7]
|
|
828
|
+
sage: N._circuit(frozenset([0, 1, 2]))
|
|
829
|
+
Traceback (most recent call last):
|
|
830
|
+
...
|
|
831
|
+
ValueError: no circuit in independent set
|
|
832
|
+
|
|
833
|
+
TESTS:
|
|
834
|
+
|
|
835
|
+
With two disjoint cycles in the graph::
|
|
836
|
+
|
|
837
|
+
sage: edgelist = [(5,6), (0,1), (3,4), (1,2), (4,5), (2,0), (5,3)]
|
|
838
|
+
sage: M = Matroid(range(7), Graph(edgelist))
|
|
839
|
+
sage: M
|
|
840
|
+
Graphic matroid of rank 5 on 7 elements
|
|
841
|
+
sage: sorted(M._circuit(M.groundset()))
|
|
842
|
+
[0, 1, 2]
|
|
843
|
+
|
|
844
|
+
Giving it a long path before it finds a cycle::
|
|
845
|
+
|
|
846
|
+
sage: edgelist = [(0,1), (1,2), (2,3), (3,4), (4,5), (4,5)]
|
|
847
|
+
sage: M = Matroid(Graph(edgelist, multiedges=True))
|
|
848
|
+
sage: M.graph().edges(sort=True)
|
|
849
|
+
[(0, 1, 0), (1, 2, 1), (2, 3, 2), (3, 4, 3), (4, 5, 4), (4, 5, 5)]
|
|
850
|
+
sage: sorted(M._circuit(M.groundset()))
|
|
851
|
+
[4, 5]
|
|
852
|
+
"""
|
|
853
|
+
cdef list edges = self.groundset_to_edges(X)
|
|
854
|
+
cdef set vertices = set()
|
|
855
|
+
cdef list vertex_list = []
|
|
856
|
+
cdef list leaves
|
|
857
|
+
cdef tuple leaf
|
|
858
|
+
cdef set edge_set = set()
|
|
859
|
+
cdef DisjointSet_of_hashables DS_vertices
|
|
860
|
+
|
|
861
|
+
for (u, v, l) in edges:
|
|
862
|
+
vertices.add(u)
|
|
863
|
+
vertices.add(v)
|
|
864
|
+
DS_vertices = DisjointSet_of_hashables(vertices)
|
|
865
|
+
for (u, v, l) in edges:
|
|
866
|
+
edge_set.add((u, v, l))
|
|
867
|
+
if DS_vertices.find(u) != DS_vertices.find(v):
|
|
868
|
+
DS_vertices.union(u, v)
|
|
869
|
+
else:
|
|
870
|
+
break
|
|
871
|
+
else:
|
|
872
|
+
raise ValueError("no circuit in independent set")
|
|
873
|
+
|
|
874
|
+
for (u, v, l) in edge_set:
|
|
875
|
+
vertex_list.extend([u, v])
|
|
876
|
+
leaves = [(u, v, l) for (u, v, l) in edge_set
|
|
877
|
+
if vertex_list.count(u) == 1 or vertex_list.count(v) == 1]
|
|
878
|
+
while leaves:
|
|
879
|
+
for leaf in leaves:
|
|
880
|
+
edge_set.remove(leaf)
|
|
881
|
+
vertex_list.remove(leaf[0])
|
|
882
|
+
vertex_list.remove(leaf[1])
|
|
883
|
+
leaves = [(u, v, l) for (u, v, l) in edge_set
|
|
884
|
+
if vertex_list.count(u) == 1 or vertex_list.count(v) == 1]
|
|
885
|
+
|
|
886
|
+
return frozenset([l for (u, v, l) in edge_set])
|
|
887
|
+
|
|
888
|
+
cpdef frozenset _coclosure(self, frozenset X):
|
|
889
|
+
"""
|
|
890
|
+
Return the coclosure of a set.
|
|
891
|
+
|
|
892
|
+
INPUT:
|
|
893
|
+
|
|
894
|
+
- ``X`` -- an iterable container of groundset elements
|
|
895
|
+
|
|
896
|
+
OUTPUT: a subset of the groundset as a :class:`frozenset`
|
|
897
|
+
|
|
898
|
+
EXAMPLES::
|
|
899
|
+
|
|
900
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
901
|
+
sage: sorted(M._coclosure(frozenset([0])))
|
|
902
|
+
[0, 1]
|
|
903
|
+
sage: sorted(M._coclosure(frozenset([0,1])))
|
|
904
|
+
[0, 1]
|
|
905
|
+
sage: N = M.graphic_extension(0, element=5)
|
|
906
|
+
sage: sorted(N._coclosure(frozenset([3])))
|
|
907
|
+
[3, 4]
|
|
908
|
+
sage: N = M.graphic_coextension(0, element=5)
|
|
909
|
+
sage: sorted(N._coclosure(frozenset([3])))
|
|
910
|
+
[3, 4, 5]
|
|
911
|
+
"""
|
|
912
|
+
cdef object g = self.graph()
|
|
913
|
+
g.delete_edges(self._groundset_to_edges(X))
|
|
914
|
+
cdef int components = g.connected_components_number()
|
|
915
|
+
cdef set XX = set(X)
|
|
916
|
+
cdef frozenset Y = self.groundset().difference(XX)
|
|
917
|
+
for e in self._groundset_to_edges(Y):
|
|
918
|
+
g.delete_edge(e)
|
|
919
|
+
if g.connected_components_number() > components:
|
|
920
|
+
XX.add(e[2])
|
|
921
|
+
g.add_edge(e)
|
|
922
|
+
return frozenset(XX)
|
|
923
|
+
|
|
924
|
+
cpdef bint _is_closed(self, frozenset X) noexcept:
|
|
925
|
+
"""
|
|
926
|
+
Test if input is a closed set.
|
|
927
|
+
|
|
928
|
+
INPUT:
|
|
929
|
+
|
|
930
|
+
- ``X`` -- an object with Python's ``frozenset`` interface containing
|
|
931
|
+
a subset of ``self.groundset()``
|
|
932
|
+
|
|
933
|
+
OUTPUT: boolean
|
|
934
|
+
|
|
935
|
+
EXAMPLES::
|
|
936
|
+
|
|
937
|
+
sage: edgelist = [(0, 0), (0, 1), (0, 2), (0, 3), (1, 2), (1, 2)]
|
|
938
|
+
sage: M = Matroid(range(len(edgelist)), Graph(edgelist, loops=True,
|
|
939
|
+
....: multiedges=True))
|
|
940
|
+
sage: M._is_closed(frozenset([0,4,5]))
|
|
941
|
+
True
|
|
942
|
+
sage: M._is_closed(frozenset([0,4]))
|
|
943
|
+
False
|
|
944
|
+
sage: M._is_closed(frozenset([1, 2, 3, 4 ,5]))
|
|
945
|
+
False
|
|
946
|
+
"""
|
|
947
|
+
# Take the set of vertices of the edges corresponding to the elements,
|
|
948
|
+
# and check if there are other edges incident with two of those vertices.
|
|
949
|
+
# Also, there must not be loops outside of X.
|
|
950
|
+
cdef set XX = set(X)
|
|
951
|
+
cdef set loop_labels = set([l for (u, v, l) in self._G.loops()])
|
|
952
|
+
if not loop_labels.issubset(XX):
|
|
953
|
+
return False
|
|
954
|
+
|
|
955
|
+
# Remove loops from input since we don't want to count them as
|
|
956
|
+
# components
|
|
957
|
+
XX.difference_update(loop_labels)
|
|
958
|
+
cdef list edge_list = self._groundset_to_edges(XX)
|
|
959
|
+
|
|
960
|
+
cdef set vertex_set = set()
|
|
961
|
+
cdef frozenset Y = self.groundset().difference(XX)
|
|
962
|
+
cdef list edge_list2 = self._groundset_to_edges(Y)
|
|
963
|
+
for e in edge_list:
|
|
964
|
+
vertex_set.add(e[0])
|
|
965
|
+
vertex_set.add(e[1])
|
|
966
|
+
for e in edge_list2:
|
|
967
|
+
if e[0] in vertex_set and e[1] in vertex_set:
|
|
968
|
+
return False
|
|
969
|
+
return True
|
|
970
|
+
|
|
971
|
+
cpdef _is_isomorphic(self, other, certificate=False):
|
|
972
|
+
"""
|
|
973
|
+
Test if ``self`` is isomorphic to ``other``.
|
|
974
|
+
|
|
975
|
+
INPUT:
|
|
976
|
+
|
|
977
|
+
- ``other`` -- matroid
|
|
978
|
+
- ``certificate`` -- boolean
|
|
979
|
+
|
|
980
|
+
OUTPUT:
|
|
981
|
+
|
|
982
|
+
- If ``certificate`` is ``False``, boolean
|
|
983
|
+
- If ``certificate`` is ``True``, a tuple containing a boolean and a dictionary
|
|
984
|
+
giving the isomorphism or None
|
|
985
|
+
|
|
986
|
+
EXAMPLES::
|
|
987
|
+
|
|
988
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
989
|
+
sage: N = Matroid(graph=graphs.DiamondGraph(), regular=True)
|
|
990
|
+
sage: M._is_isomorphic(N, certificate=True)
|
|
991
|
+
(True, {0: (0, 1), 1: (0, 2), 2: (1, 2), 3: (1, 3), 4: (2, 3)})
|
|
992
|
+
sage: O = Matroid(graphs.WheelGraph(5))
|
|
993
|
+
sage: M._is_isomorphic(O, certificate=True)
|
|
994
|
+
(False, None)
|
|
995
|
+
|
|
996
|
+
::
|
|
997
|
+
|
|
998
|
+
sage: M1 = Matroid(range(4), graphs.CycleGraph(4))
|
|
999
|
+
sage: M2 = Matroid(range(4), graphs.CompleteBipartiteGraph(2,2))
|
|
1000
|
+
sage: M3 = matroids.Uniform(3,4)
|
|
1001
|
+
sage: M1._is_isomorphic(M2)
|
|
1002
|
+
True
|
|
1003
|
+
sage: M1._is_isomorphic(M3)
|
|
1004
|
+
True
|
|
1005
|
+
|
|
1006
|
+
::
|
|
1007
|
+
|
|
1008
|
+
sage: edgelist = [(0, 1, 'a'), (0, 2, 'b'), (0, 3, 'c'),
|
|
1009
|
+
....: (1, 2, 'd'), (1, 3, 'e'), (2, 3, 'f')]
|
|
1010
|
+
sage: M = Matroid(Graph(edgelist))
|
|
1011
|
+
sage: N = Matroid(range(6), graphs.WheelGraph(4))
|
|
1012
|
+
sage: M._is_isomorphic(N, certificate=True)
|
|
1013
|
+
(True, {'a': 2, 'b': 4, 'c': 5, 'd': 0, 'e': 1, 'f': 3})
|
|
1014
|
+
sage: N._is_isomorphic(M, certificate=True)
|
|
1015
|
+
(True, {0: 'd', 1: 'e', 2: 'a', 3: 'f', 4: 'b', 5: 'c'})
|
|
1016
|
+
sage: O = Matroid(range(6), graphs.CycleGraph(6))
|
|
1017
|
+
sage: M._is_isomorphic(O)
|
|
1018
|
+
False
|
|
1019
|
+
"""
|
|
1020
|
+
# Check for 3-connectivity so we don't have to worry about Whitney twists
|
|
1021
|
+
if isinstance(other, GraphicMatroid) and other.is_3connected():
|
|
1022
|
+
G = self.graph()
|
|
1023
|
+
H = other.graph()
|
|
1024
|
+
G.allow_loops(False)
|
|
1025
|
+
G.allow_multiple_edges(False)
|
|
1026
|
+
H.allow_loops(False)
|
|
1027
|
+
H.allow_multiple_edges(False)
|
|
1028
|
+
|
|
1029
|
+
result = G.is_isomorphic(H, certificate=certificate)
|
|
1030
|
+
if not certificate or result[0] is False:
|
|
1031
|
+
return result
|
|
1032
|
+
# If they are isomorphic and the user wants a certificate,
|
|
1033
|
+
# result[1] is a dictionary of vertices.
|
|
1034
|
+
# We need to translate this to edge labels.
|
|
1035
|
+
vertex_certif = result[1]
|
|
1036
|
+
elt_certif = {}
|
|
1037
|
+
for (u, v, l) in G.edge_iterator():
|
|
1038
|
+
l_maps_to = H.edge_label(vertex_certif[u], vertex_certif[v])
|
|
1039
|
+
elt_certif[l] = l_maps_to
|
|
1040
|
+
return (True, elt_certif)
|
|
1041
|
+
|
|
1042
|
+
else:
|
|
1043
|
+
M = self.regular_matroid()
|
|
1044
|
+
if isinstance(other, GraphicMatroid):
|
|
1045
|
+
other = other.regular_matroid()
|
|
1046
|
+
if certificate:
|
|
1047
|
+
# iso0: isomorphism from M and self -- in this order,
|
|
1048
|
+
# to prevent an infinite recursion.
|
|
1049
|
+
iso0 = M._is_isomorphic(self, certificate=certificate)[1]
|
|
1050
|
+
# Now invert iso0 to get iso1, an isomorphism from self to M.
|
|
1051
|
+
iso1 = {iso0[e]: e for e in iso0}
|
|
1052
|
+
# iso2: isomorphism from M and other.
|
|
1053
|
+
isomorphic, iso2 = M._is_isomorphic(other, certificate=certificate)
|
|
1054
|
+
if not isomorphic:
|
|
1055
|
+
return (False, None)
|
|
1056
|
+
# Compose iso1 and iso2, to go from self to other.
|
|
1057
|
+
return (True, {e: iso2[iso1[e]] for e in iso1})
|
|
1058
|
+
return M._is_isomorphic(other)
|
|
1059
|
+
|
|
1060
|
+
cpdef _isomorphism(self, other):
|
|
1061
|
+
"""
|
|
1062
|
+
Return isomorphism from ``self`` to ``other``, if such an isomorphism
|
|
1063
|
+
exists.
|
|
1064
|
+
|
|
1065
|
+
Internal version that performs no checks on input.
|
|
1066
|
+
|
|
1067
|
+
INPUT:
|
|
1068
|
+
|
|
1069
|
+
- ``other`` -- matroid
|
|
1070
|
+
|
|
1071
|
+
OUTPUT: dictionary or ``None``
|
|
1072
|
+
|
|
1073
|
+
EXAMPLES::
|
|
1074
|
+
|
|
1075
|
+
sage: M1 = Matroid(range(4), graphs.CycleGraph(4))
|
|
1076
|
+
sage: M2 = Matroid(range(4), graphs.CompleteBipartiteGraph(2,2))
|
|
1077
|
+
sage: M1._isomorphism(matroids.catalog.BetsyRoss())
|
|
1078
|
+
sage: M1._isomorphism(M2)
|
|
1079
|
+
{0: 0, 1: 1, 2: 2, 3: 3}
|
|
1080
|
+
sage: M3 = matroids.Uniform(3,4)
|
|
1081
|
+
sage: M1._isomorphism(M3)
|
|
1082
|
+
{0: 0, 1: 1, 2: 2, 3: 3}
|
|
1083
|
+
|
|
1084
|
+
::
|
|
1085
|
+
|
|
1086
|
+
sage: edgelist = [(0, 1, 'a'), (0, 2, 'b'), (0, 3, 'c'),
|
|
1087
|
+
....: (1, 2, 'd'), (1, 3, 'e'), (2, 3, 'f')]
|
|
1088
|
+
sage: M = Matroid(Graph(edgelist))
|
|
1089
|
+
sage: N = Matroid(range(6), graphs.WheelGraph(4))
|
|
1090
|
+
sage: M._isomorphism(N)
|
|
1091
|
+
{'a': 2, 'b': 4, 'c': 5, 'd': 0, 'e': 1, 'f': 3}
|
|
1092
|
+
sage: O = Matroid(Graph(edgelist), regular=True)
|
|
1093
|
+
sage: iso = M._isomorphism(O)
|
|
1094
|
+
sage: M.is_isomorphism(O, iso)
|
|
1095
|
+
True
|
|
1096
|
+
"""
|
|
1097
|
+
return self.is_isomorphic(other, certificate=True)[1]
|
|
1098
|
+
|
|
1099
|
+
cpdef is_valid(self, certificate=False):
|
|
1100
|
+
"""
|
|
1101
|
+
Test if the data obey the matroid axioms.
|
|
1102
|
+
|
|
1103
|
+
Since a graph is used for the data, this is always the case.
|
|
1104
|
+
|
|
1105
|
+
INPUT:
|
|
1106
|
+
|
|
1107
|
+
- ``certificate`` -- boolean (default: ``False``)
|
|
1108
|
+
|
|
1109
|
+
OUTPUT: ``True``, or ``(True, {})``
|
|
1110
|
+
|
|
1111
|
+
EXAMPLES::
|
|
1112
|
+
|
|
1113
|
+
sage: M = matroids.CompleteGraphic(4); M
|
|
1114
|
+
M(K4): Graphic matroid of rank 3 on 6 elements
|
|
1115
|
+
sage: M.is_valid()
|
|
1116
|
+
True
|
|
1117
|
+
"""
|
|
1118
|
+
return True if not certificate else (True, {})
|
|
1119
|
+
|
|
1120
|
+
cpdef bint is_graphic(self, algorithm=None) except -1:
|
|
1121
|
+
r"""
|
|
1122
|
+
Return if ``self`` is graphic.
|
|
1123
|
+
|
|
1124
|
+
This is trivially ``True`` for a :class:`GraphicMatroid`.
|
|
1125
|
+
|
|
1126
|
+
EXAMPLES::
|
|
1127
|
+
|
|
1128
|
+
sage: M = Matroid(graphs.PetersenGraph())
|
|
1129
|
+
sage: M.is_graphic()
|
|
1130
|
+
True
|
|
1131
|
+
"""
|
|
1132
|
+
return True
|
|
1133
|
+
|
|
1134
|
+
cpdef bint is_regular(self, algorithm=None) except -1:
|
|
1135
|
+
r"""
|
|
1136
|
+
Return if ``self`` is regular.
|
|
1137
|
+
|
|
1138
|
+
This is always ``True`` for a :class:`GraphicMatroid`.
|
|
1139
|
+
|
|
1140
|
+
EXAMPLES::
|
|
1141
|
+
|
|
1142
|
+
sage: M = Matroid(graphs.DesarguesGraph())
|
|
1143
|
+
sage: M.is_regular()
|
|
1144
|
+
True
|
|
1145
|
+
"""
|
|
1146
|
+
return True
|
|
1147
|
+
|
|
1148
|
+
# graphic methods
|
|
1149
|
+
|
|
1150
|
+
cpdef graph(self):
|
|
1151
|
+
"""
|
|
1152
|
+
Return the graph that represents the matroid.
|
|
1153
|
+
|
|
1154
|
+
The graph will always have loops and multiedges enabled.
|
|
1155
|
+
|
|
1156
|
+
OUTPUT: graph
|
|
1157
|
+
|
|
1158
|
+
EXAMPLES::
|
|
1159
|
+
|
|
1160
|
+
sage: M = Matroid(Graph([(0, 1, 'a'), (0, 2, 'b'), (0, 3, 'c')]))
|
|
1161
|
+
sage: M.graph().edges(sort=True)
|
|
1162
|
+
[(0, 1, 'a'), (0, 2, 'b'), (0, 3, 'c')]
|
|
1163
|
+
sage: M = Matroid(graphs.CompleteGraph(5))
|
|
1164
|
+
sage: M.graph()
|
|
1165
|
+
Looped multi-graph on 5 vertices
|
|
1166
|
+
"""
|
|
1167
|
+
# Return a mutable graph
|
|
1168
|
+
return self._G.copy(data_structure='sparse')
|
|
1169
|
+
|
|
1170
|
+
cpdef vertex_map(self):
|
|
1171
|
+
"""
|
|
1172
|
+
Return a dictionary mapping the input vertices to the current vertices.
|
|
1173
|
+
|
|
1174
|
+
The graph for the matroid is always connected. If the constructor is
|
|
1175
|
+
given a graph with multiple components, it will connect them. The
|
|
1176
|
+
Python dictionary given by this method has the vertices from the
|
|
1177
|
+
input graph as keys, and the corresponding vertex label after any
|
|
1178
|
+
merging as values.
|
|
1179
|
+
|
|
1180
|
+
OUTPUT: dictionary
|
|
1181
|
+
|
|
1182
|
+
EXAMPLES::
|
|
1183
|
+
|
|
1184
|
+
sage: G = Graph([(0, 1), (0, 2), (1, 2), (3, 4), (3, 5), (4, 5),
|
|
1185
|
+
....: (6, 7), (6, 8), (7, 8), (8, 8), (7, 8)], multiedges=True, loops=True)
|
|
1186
|
+
sage: M = Matroid(range(G.num_edges()), G)
|
|
1187
|
+
sage: M.graph().edges(sort=True)
|
|
1188
|
+
[(0, 1, 0),
|
|
1189
|
+
(0, 2, 1),
|
|
1190
|
+
(1, 2, 2),
|
|
1191
|
+
(1, 4, 3),
|
|
1192
|
+
(1, 5, 4),
|
|
1193
|
+
(4, 5, 5),
|
|
1194
|
+
(4, 7, 6),
|
|
1195
|
+
(4, 8, 7),
|
|
1196
|
+
(7, 8, 8),
|
|
1197
|
+
(7, 8, 9),
|
|
1198
|
+
(8, 8, 10)]
|
|
1199
|
+
sage: M.vertex_map()
|
|
1200
|
+
{0: 0, 1: 1, 2: 2, 3: 1, 4: 4, 5: 5, 6: 4, 7: 7, 8: 8}
|
|
1201
|
+
"""
|
|
1202
|
+
return copy(self._vertex_map)
|
|
1203
|
+
|
|
1204
|
+
cpdef list groundset_to_edges(self, X):
|
|
1205
|
+
"""
|
|
1206
|
+
Return a list of edges corresponding to a set of groundset elements.
|
|
1207
|
+
|
|
1208
|
+
INPUT:
|
|
1209
|
+
|
|
1210
|
+
- ``X`` -- subset of the groundset
|
|
1211
|
+
|
|
1212
|
+
OUTPUT: list of graph edges
|
|
1213
|
+
|
|
1214
|
+
EXAMPLES::
|
|
1215
|
+
|
|
1216
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
1217
|
+
sage: M.groundset_to_edges([2, 3, 4])
|
|
1218
|
+
[(1, 2, 2), (1, 3, 3), (2, 3, 4)]
|
|
1219
|
+
sage: M.groundset_to_edges([2, 3, 4, 5])
|
|
1220
|
+
Traceback (most recent call last):
|
|
1221
|
+
...
|
|
1222
|
+
ValueError: input must be a subset of the groundset
|
|
1223
|
+
"""
|
|
1224
|
+
for x in X:
|
|
1225
|
+
if x not in self._groundset:
|
|
1226
|
+
raise ValueError("input must be a subset of the groundset")
|
|
1227
|
+
return self._groundset_to_edges(X)
|
|
1228
|
+
|
|
1229
|
+
cpdef _groundset_to_edges(self, X):
|
|
1230
|
+
"""
|
|
1231
|
+
Return a list of edges corresponding to a set of groundset elements.
|
|
1232
|
+
|
|
1233
|
+
INPUT:
|
|
1234
|
+
|
|
1235
|
+
- ``X`` -- subset of the groundset
|
|
1236
|
+
|
|
1237
|
+
OUTPUT: list of graph edges
|
|
1238
|
+
|
|
1239
|
+
EXAMPLES::
|
|
1240
|
+
|
|
1241
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
1242
|
+
sage: M._groundset_to_edges([2, 3, 4])
|
|
1243
|
+
[(1, 2, 2), (1, 3, 3), (2, 3, 4)]
|
|
1244
|
+
"""
|
|
1245
|
+
return [(self._groundset_edge_map[x][0], self._groundset_edge_map[x][1], x) for x in X]
|
|
1246
|
+
|
|
1247
|
+
cpdef subgraph_from_set(self, X):
|
|
1248
|
+
"""
|
|
1249
|
+
Return the subgraph corresponding to the matroid restricted to `X`.
|
|
1250
|
+
|
|
1251
|
+
INPUT:
|
|
1252
|
+
|
|
1253
|
+
- ``X`` -- subset of the groundset
|
|
1254
|
+
|
|
1255
|
+
OUTPUT: graph
|
|
1256
|
+
|
|
1257
|
+
EXAMPLES::
|
|
1258
|
+
|
|
1259
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
1260
|
+
sage: M.subgraph_from_set([0,1,2])
|
|
1261
|
+
Looped multi-graph on 3 vertices
|
|
1262
|
+
sage: M.subgraph_from_set([3,4,5])
|
|
1263
|
+
Traceback (most recent call last):
|
|
1264
|
+
...
|
|
1265
|
+
ValueError: input must be a subset of the groundset
|
|
1266
|
+
"""
|
|
1267
|
+
for x in X:
|
|
1268
|
+
if x not in self._groundset:
|
|
1269
|
+
raise ValueError("input must be a subset of the groundset")
|
|
1270
|
+
return self._subgraph_from_set(X)
|
|
1271
|
+
|
|
1272
|
+
cpdef _subgraph_from_set(self, X):
|
|
1273
|
+
"""
|
|
1274
|
+
Return the subgraph corresponding to `M` restricted to `X`.
|
|
1275
|
+
|
|
1276
|
+
INPUT:
|
|
1277
|
+
|
|
1278
|
+
- ``X`` -- subset of the groundset
|
|
1279
|
+
|
|
1280
|
+
OUTPUT: graph
|
|
1281
|
+
|
|
1282
|
+
EXAMPLES::
|
|
1283
|
+
|
|
1284
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
1285
|
+
sage: M._subgraph_from_set([0, 1, 2])
|
|
1286
|
+
Looped multi-graph on 3 vertices
|
|
1287
|
+
"""
|
|
1288
|
+
from sage.graphs.graph import Graph
|
|
1289
|
+
edge_list = self._groundset_to_edges(X)
|
|
1290
|
+
return Graph(edge_list, loops=True, multiedges=True)
|
|
1291
|
+
|
|
1292
|
+
cpdef graphic_extension(self, u, v=None, element=None):
|
|
1293
|
+
"""
|
|
1294
|
+
Return a graphic matroid extended by a new element.
|
|
1295
|
+
|
|
1296
|
+
A new edge will be added between ``u`` and ``v``. If ``v`` is not
|
|
1297
|
+
specified, then a loop is added on ``u``.
|
|
1298
|
+
|
|
1299
|
+
INPUT:
|
|
1300
|
+
|
|
1301
|
+
- ``u`` -- vertex in the matroid's graph
|
|
1302
|
+
- ``v`` -- (optional) another vertex
|
|
1303
|
+
- ``element`` -- (optional) the label of the new element
|
|
1304
|
+
|
|
1305
|
+
OUTPUT:
|
|
1306
|
+
|
|
1307
|
+
A :class:`GraphicMatroid` with the specified element added. Note that if
|
|
1308
|
+
``v`` is not specified or if ``v`` is ``u``, then the new element will
|
|
1309
|
+
be a loop. If the new element's label is not specified, it will be
|
|
1310
|
+
generated automatically.
|
|
1311
|
+
|
|
1312
|
+
EXAMPLES::
|
|
1313
|
+
|
|
1314
|
+
sage: M = matroids.CompleteGraphic(4)
|
|
1315
|
+
sage: M1 = M.graphic_extension(0,1,'a'); M1
|
|
1316
|
+
Graphic matroid of rank 3 on 7 elements
|
|
1317
|
+
sage: list(M1.graph().edge_iterator())
|
|
1318
|
+
[(0, 1, 'a'), (0, 1, 0), (0, 2, 1), (0, 3, 2), (1, 2, 3), (1, 3, 4), (2, 3, 5)]
|
|
1319
|
+
sage: M2 = M1.graphic_extension(3); M2
|
|
1320
|
+
Graphic matroid of rank 3 on 8 elements
|
|
1321
|
+
|
|
1322
|
+
::
|
|
1323
|
+
|
|
1324
|
+
sage: M = Matroid(range(10), graphs.PetersenGraph())
|
|
1325
|
+
sage: sorted(M.graphic_extension(0, 'b', 'c').graph().vertex_iterator(), key=str)
|
|
1326
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'b']
|
|
1327
|
+
sage: M.graphic_extension('a', 'b', 'c').graph().vertices(sort=False)
|
|
1328
|
+
Traceback (most recent call last):
|
|
1329
|
+
...
|
|
1330
|
+
ValueError: u must be an existing vertex
|
|
1331
|
+
|
|
1332
|
+
TESTS::
|
|
1333
|
+
|
|
1334
|
+
sage: M = Matroid(graphs.EmptyGraph())
|
|
1335
|
+
sage: M.graphic_extension(0)
|
|
1336
|
+
Graphic matroid of rank 0 on 1 elements
|
|
1337
|
+
sage: M.graphic_extension(0, 1, 'a')
|
|
1338
|
+
Graphic matroid of rank 1 on 1 elements
|
|
1339
|
+
"""
|
|
1340
|
+
# This will possibly make a coloop if v is a new vertex
|
|
1341
|
+
if element is None:
|
|
1342
|
+
element = newlabel(self.groundset())
|
|
1343
|
+
elif element in self.groundset():
|
|
1344
|
+
raise ValueError("cannot extend by element already in groundset")
|
|
1345
|
+
if v is None:
|
|
1346
|
+
v = u
|
|
1347
|
+
G = self.graph()
|
|
1348
|
+
if u not in G:
|
|
1349
|
+
raise ValueError("u must be an existing vertex")
|
|
1350
|
+
G.add_edge(u, v, element)
|
|
1351
|
+
return GraphicMatroid(G)
|
|
1352
|
+
|
|
1353
|
+
def graphic_extensions(self, element=None, vertices=None, simple=False):
|
|
1354
|
+
"""
|
|
1355
|
+
Return an iterable containing the graphic extensions.
|
|
1356
|
+
|
|
1357
|
+
This method iterates over the vertices in the input. If
|
|
1358
|
+
``simple == False``, it first extends by a loop. It will then add an
|
|
1359
|
+
edge between every pair of vertices in the input, skipping pairs of
|
|
1360
|
+
vertices with an edge already between them if ``simple == True``.
|
|
1361
|
+
|
|
1362
|
+
This method only considers the current graph presentation, and
|
|
1363
|
+
does not take 2-isomorphism into account. Use
|
|
1364
|
+
:meth:`twist <sage.matroids.graphic_matroid.GraphicMatroid.twist>` or
|
|
1365
|
+
:meth:`one_sum <sage.matroids.graphic_matroid.GraphicMatroid.one_sum>`
|
|
1366
|
+
if you wish to change the graph presentation.
|
|
1367
|
+
|
|
1368
|
+
INPUT:
|
|
1369
|
+
|
|
1370
|
+
- ``element`` -- (optional) the name of the newly added element in
|
|
1371
|
+
each extension
|
|
1372
|
+
- ``vertices`` -- (optional) a set of vertices over which the extension
|
|
1373
|
+
may be taken
|
|
1374
|
+
- ``simple`` -- boolean (default: ``False``); if ``True``, extensions
|
|
1375
|
+
by loops and parallel elements are not taken
|
|
1376
|
+
|
|
1377
|
+
OUTPUT:
|
|
1378
|
+
|
|
1379
|
+
An iterable containing instances of :class:`GraphicMatroid`. If
|
|
1380
|
+
``vertices`` is not specified, every vertex is used.
|
|
1381
|
+
|
|
1382
|
+
.. NOTE::
|
|
1383
|
+
|
|
1384
|
+
The extension by a loop will always occur unless
|
|
1385
|
+
``simple == True``. The extension by a coloop will never occur.
|
|
1386
|
+
|
|
1387
|
+
EXAMPLES::
|
|
1388
|
+
|
|
1389
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
1390
|
+
sage: I = M.graphic_extensions('a')
|
|
1391
|
+
sage: for N in I:
|
|
1392
|
+
....: list(N.graph().edge_iterator())
|
|
1393
|
+
[(0, 0, 'a'), (0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 3, 3), (2, 3, 4)]
|
|
1394
|
+
[(0, 1, 'a'), (0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 3, 3), (2, 3, 4)]
|
|
1395
|
+
[(0, 1, 0), (0, 2, 'a'), (0, 2, 1), (1, 2, 2), (1, 3, 3), (2, 3, 4)]
|
|
1396
|
+
[(0, 1, 0), (0, 2, 1), (0, 3, 'a'), (1, 2, 2), (1, 3, 3), (2, 3, 4)]
|
|
1397
|
+
[(0, 1, 0), (0, 2, 1), (1, 2, 'a'), (1, 2, 2), (1, 3, 3), (2, 3, 4)]
|
|
1398
|
+
[(0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 3, 'a'), (1, 3, 3), (2, 3, 4)]
|
|
1399
|
+
[(0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 3, 3), (2, 3, 'a'), (2, 3, 4)]
|
|
1400
|
+
|
|
1401
|
+
::
|
|
1402
|
+
|
|
1403
|
+
sage: M = Matroid(graphs.CompleteBipartiteGraph(3,3))
|
|
1404
|
+
sage: I = M.graphic_extensions(simple=True)
|
|
1405
|
+
sage: sum (1 for i in I)
|
|
1406
|
+
6
|
|
1407
|
+
sage: I = M.graphic_extensions(vertices=[0,1,2])
|
|
1408
|
+
sage: sum (1 for i in I)
|
|
1409
|
+
4
|
|
1410
|
+
"""
|
|
1411
|
+
G = self.graph()
|
|
1412
|
+
if element is None:
|
|
1413
|
+
element = newlabel(self.groundset())
|
|
1414
|
+
elif element in self.groundset():
|
|
1415
|
+
raise ValueError("cannot extend by element already in groundset")
|
|
1416
|
+
if vertices is None:
|
|
1417
|
+
vertices = self._G.vertices(sort=False)
|
|
1418
|
+
elif not set(vertices).issubset(self._G.vertices(sort=False)):
|
|
1419
|
+
raise ValueError("vertices are not all in the graph")
|
|
1420
|
+
|
|
1421
|
+
# First extend by a loop, then consider every pair of vertices.
|
|
1422
|
+
# Put the loop on the first vertex.
|
|
1423
|
+
if not simple:
|
|
1424
|
+
G.add_edge(vertices[0], vertices[0], element)
|
|
1425
|
+
yield GraphicMatroid(G)
|
|
1426
|
+
G.delete_edge(vertices[0], vertices[0], element)
|
|
1427
|
+
|
|
1428
|
+
pairs = combinations(vertices, 2)
|
|
1429
|
+
for p in pairs:
|
|
1430
|
+
if not simple or not G.has_edge(p[0], p[1]):
|
|
1431
|
+
G.add_edge(p[0], p[1], element)
|
|
1432
|
+
yield GraphicMatroid(G)
|
|
1433
|
+
G.delete_edge(p[0], p[1], element)
|
|
1434
|
+
|
|
1435
|
+
cpdef graphic_coextension(self, u, v=None, X=None, element=None):
|
|
1436
|
+
"""
|
|
1437
|
+
Return a matroid coextended by a new element.
|
|
1438
|
+
|
|
1439
|
+
A coextension in a graphic matroid is the opposite of contracting an
|
|
1440
|
+
edge; that is, a vertex is split, and a new edge is added between the
|
|
1441
|
+
resulting vertices. This method will create a new vertex `v` adjacent
|
|
1442
|
+
to `u`, and move the edges indicated by `X` from `u` to `v`.
|
|
1443
|
+
|
|
1444
|
+
INPUT:
|
|
1445
|
+
|
|
1446
|
+
- ``u`` -- the vertex to be split
|
|
1447
|
+
- ``v`` -- (optional) the name of the new vertex after splitting
|
|
1448
|
+
- ``X`` -- (optional) a list of the matroid elements corresponding to
|
|
1449
|
+
edges incident to ``u`` that move to the new vertex after splitting
|
|
1450
|
+
- ``element`` -- (optional) the name of the newly added element
|
|
1451
|
+
|
|
1452
|
+
OUTPUT:
|
|
1453
|
+
|
|
1454
|
+
An instance of :class:`GraphicMatroid` coextended by the new element.
|
|
1455
|
+
If ``X`` is not specified, the new element will be a coloop.
|
|
1456
|
+
|
|
1457
|
+
.. NOTE::
|
|
1458
|
+
|
|
1459
|
+
A loop on ``u`` will stay a loop unless it is in ``X``.
|
|
1460
|
+
|
|
1461
|
+
EXAMPLES::
|
|
1462
|
+
|
|
1463
|
+
sage: G = Graph([(0, 1, 0), (0, 2, 1), (0, 3, 2), (0, 4, 3),
|
|
1464
|
+
....: (1, 2, 4), (1, 4, 5), (2, 3, 6), (3, 4, 7)])
|
|
1465
|
+
sage: M = Matroid(G)
|
|
1466
|
+
sage: M1 = M.graphic_coextension(0, X=[1,2], element='a')
|
|
1467
|
+
sage: M1.graph().edges(sort=True)
|
|
1468
|
+
[(0, 1, 0),
|
|
1469
|
+
(0, 4, 3),
|
|
1470
|
+
(0, 5, 'a'),
|
|
1471
|
+
(1, 2, 4),
|
|
1472
|
+
(1, 4, 5),
|
|
1473
|
+
(2, 3, 6),
|
|
1474
|
+
(2, 5, 1),
|
|
1475
|
+
(3, 4, 7),
|
|
1476
|
+
(3, 5, 2)]
|
|
1477
|
+
|
|
1478
|
+
TESTS::
|
|
1479
|
+
|
|
1480
|
+
sage: M = Matroid(range(3), graphs.CycleGraph(3))
|
|
1481
|
+
sage: M = M.graphic_extension(0, element='a')
|
|
1482
|
+
sage: M.graph().edges(sort=True)
|
|
1483
|
+
[(0, 0, 'a'), (0, 1, 0), (0, 2, 1), (1, 2, 2)]
|
|
1484
|
+
sage: M1 = M.graphic_coextension(0, X=[1], element='b')
|
|
1485
|
+
sage: M1.graph().edges(sort=True)
|
|
1486
|
+
[(0, 0, 'a'), (0, 1, 0), (0, 3, 'b'), (1, 2, 2), (2, 3, 1)]
|
|
1487
|
+
sage: M2 = M.graphic_coextension(0, X=[1, 'a'], element='b')
|
|
1488
|
+
sage: M2.graph().edges(sort=True)
|
|
1489
|
+
[(0, 1, 0), (0, 3, 'a'), (0, 3, 'b'), (1, 2, 2), (2, 3, 1)]
|
|
1490
|
+
|
|
1491
|
+
::
|
|
1492
|
+
|
|
1493
|
+
sage: M = Matroid(graphs.CycleGraph(3))
|
|
1494
|
+
sage: M = M.graphic_coextension(u=2, element='a')
|
|
1495
|
+
sage: M.graph()
|
|
1496
|
+
Looped multi-graph on 4 vertices
|
|
1497
|
+
sage: M.graph().loops()
|
|
1498
|
+
[]
|
|
1499
|
+
sage: M = M.graphic_coextension(u=2, element='a')
|
|
1500
|
+
Traceback (most recent call last):
|
|
1501
|
+
...
|
|
1502
|
+
ValueError: cannot extend by element already in groundset
|
|
1503
|
+
sage: M = M.graphic_coextension(u=4)
|
|
1504
|
+
Traceback (most recent call last):
|
|
1505
|
+
...
|
|
1506
|
+
ValueError: u must be an existing vertex
|
|
1507
|
+
|
|
1508
|
+
TESTS::
|
|
1509
|
+
|
|
1510
|
+
sage: M = Matroid(graphs.EmptyGraph())
|
|
1511
|
+
sage: M.graphic_coextension(u=0)
|
|
1512
|
+
Graphic matroid of rank 1 on 1 elements
|
|
1513
|
+
|
|
1514
|
+
sage: M = Matroid(graphs.DiamondGraph())
|
|
1515
|
+
sage: N = M.graphic_coextension(0,'q')
|
|
1516
|
+
sage: list(N.graph().vertex_iterator())
|
|
1517
|
+
['q', 0, 1, 2, 3]
|
|
1518
|
+
|
|
1519
|
+
::
|
|
1520
|
+
|
|
1521
|
+
sage: M = Matroid(range(5), graphs.DiamondGraph())
|
|
1522
|
+
sage: N = M.graphic_coextension(u=3, v=5, element='a')
|
|
1523
|
+
sage: N.graph().edges(sort=True)
|
|
1524
|
+
[(0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 3, 3), (2, 3, 4), (3, 5, 'a')]
|
|
1525
|
+
sage: N = M.graphic_coextension(u=3, element='a')
|
|
1526
|
+
sage: N.graph().edges(sort=True)
|
|
1527
|
+
[(0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 3, 3), (2, 3, 4), (3, 4, 'a')]
|
|
1528
|
+
sage: N = M.graphic_coextension(u=3, v=3, element='a')
|
|
1529
|
+
Traceback (most recent call last):
|
|
1530
|
+
...
|
|
1531
|
+
ValueError: u and v must be distinct
|
|
1532
|
+
"""
|
|
1533
|
+
if element is None:
|
|
1534
|
+
element = newlabel(self.groundset())
|
|
1535
|
+
else:
|
|
1536
|
+
if element in self.groundset():
|
|
1537
|
+
raise ValueError("cannot extend by element already in groundset")
|
|
1538
|
+
|
|
1539
|
+
if u not in self._G.vertices(sort=False):
|
|
1540
|
+
raise ValueError("u must be an existing vertex")
|
|
1541
|
+
if v == u:
|
|
1542
|
+
raise ValueError("u and v must be distinct")
|
|
1543
|
+
# To prevent an error for iterating over None:
|
|
1544
|
+
if X is None:
|
|
1545
|
+
X = []
|
|
1546
|
+
|
|
1547
|
+
G = self.graph()
|
|
1548
|
+
vertices = G.vertices(sort=False)
|
|
1549
|
+
if v is None:
|
|
1550
|
+
v = G.add_vertex()
|
|
1551
|
+
|
|
1552
|
+
elif v in G:
|
|
1553
|
+
raise ValueError("vertex is already in the graph")
|
|
1554
|
+
if u not in vertices:
|
|
1555
|
+
G.add_edge(u, v, element)
|
|
1556
|
+
return GraphicMatroid(G)
|
|
1557
|
+
|
|
1558
|
+
edgelist = self.groundset_to_edges(X)
|
|
1559
|
+
|
|
1560
|
+
split_vertex(G, u, v, edgelist)
|
|
1561
|
+
G.add_edge(u, v, element)
|
|
1562
|
+
|
|
1563
|
+
return GraphicMatroid(G)
|
|
1564
|
+
|
|
1565
|
+
def graphic_coextensions(self, vertices=None, v=None, element=None, cosimple=False):
|
|
1566
|
+
"""
|
|
1567
|
+
Return an iterator of graphic coextensions.
|
|
1568
|
+
|
|
1569
|
+
This method iterates over the vertices in the input. If
|
|
1570
|
+
``cosimple == False``, it first coextends by a coloop and series edge
|
|
1571
|
+
for every edge incident with the vertices. For vertices of degree four
|
|
1572
|
+
or higher, it will consider the ways to partition the vertex into two
|
|
1573
|
+
sets of cardinality at least two, and these will be the edges incident
|
|
1574
|
+
with the vertices after splitting.
|
|
1575
|
+
|
|
1576
|
+
At most one series coextension will be taken for each series class.
|
|
1577
|
+
|
|
1578
|
+
INPUT:
|
|
1579
|
+
|
|
1580
|
+
- ``vertices`` -- (optional) the vertices to be split
|
|
1581
|
+
- ``v`` -- (optional) the name of the new vertex
|
|
1582
|
+
- ``element`` -- (optional) the name of the new element
|
|
1583
|
+
- ``cosimple`` -- boolean (default: ``False``); if ``True``, coextensions
|
|
1584
|
+
by a coloop or series elements will not be taken
|
|
1585
|
+
|
|
1586
|
+
OUTPUT:
|
|
1587
|
+
|
|
1588
|
+
An iterable containing instances of :class:`GraphicMatroid`. If
|
|
1589
|
+
``vertices`` is not specified, the method iterates over all vertices.
|
|
1590
|
+
|
|
1591
|
+
EXAMPLES::
|
|
1592
|
+
|
|
1593
|
+
sage: G = Graph([(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 4), (2, 3), (3, 4)])
|
|
1594
|
+
sage: M = Matroid(range(8), G)
|
|
1595
|
+
sage: I = M.graphic_coextensions(vertices=[0], element='a')
|
|
1596
|
+
sage: sorted([N.graph().edges_incident(0, sort=True) for N in I], key=str)
|
|
1597
|
+
[[(0, 1, 0), (0, 2, 1), (0, 3, 2), (0, 4, 3), (0, 5, 'a')],
|
|
1598
|
+
[(0, 1, 0), (0, 2, 1), (0, 3, 2), (0, 5, 'a')],
|
|
1599
|
+
[(0, 1, 0), (0, 2, 1), (0, 4, 3), (0, 5, 'a')],
|
|
1600
|
+
[(0, 1, 0), (0, 2, 1), (0, 5, 'a')],
|
|
1601
|
+
[(0, 1, 0), (0, 3, 2), (0, 4, 3), (0, 5, 'a')],
|
|
1602
|
+
[(0, 1, 0), (0, 3, 2), (0, 5, 'a')],
|
|
1603
|
+
[(0, 2, 1), (0, 3, 2), (0, 4, 3), (0, 5, 'a')],
|
|
1604
|
+
[(0, 2, 1), (0, 3, 2), (0, 5, 'a')]]
|
|
1605
|
+
|
|
1606
|
+
::
|
|
1607
|
+
|
|
1608
|
+
sage: N = Matroid(range(4), graphs.CycleGraph(4))
|
|
1609
|
+
sage: I = N.graphic_coextensions(element='a')
|
|
1610
|
+
sage: for N1 in I: # random
|
|
1611
|
+
....: N1.graph().edges(sort=True)
|
|
1612
|
+
[(0, 1, 0), (0, 3, 1), (0, 4, 'a'), (1, 2, 2), (2, 3, 3)]
|
|
1613
|
+
[(0, 1, 0), (0, 3, 1), (1, 4, 2), (2, 3, 3), (2, 4, 'a')]
|
|
1614
|
+
sage: sum(1 for n in N.graphic_coextensions(cosimple=True))
|
|
1615
|
+
0
|
|
1616
|
+
|
|
1617
|
+
TESTS::
|
|
1618
|
+
|
|
1619
|
+
sage: M = Matroid(graphs.EmptyGraph())
|
|
1620
|
+
sage: M.graphic_coextension(0)
|
|
1621
|
+
Graphic matroid of rank 1 on 1 elements
|
|
1622
|
+
sage: I = M.graphic_coextensions(element='a')
|
|
1623
|
+
sage: for m in I:
|
|
1624
|
+
....: m.graph().edges(sort=True)
|
|
1625
|
+
[(0, 1, 'a')]
|
|
1626
|
+
sage: N = Matroid(graphs.CycleGraph(4))
|
|
1627
|
+
sage: I = N.graphic_coextensions(vertices=[3, 4], element='a')
|
|
1628
|
+
sage: next(I)
|
|
1629
|
+
Traceback (most recent call last):
|
|
1630
|
+
...
|
|
1631
|
+
ValueError: vertices are not all in the graph
|
|
1632
|
+
|
|
1633
|
+
We expect 136 graphic coextensions of an 8-spoked wheel: 128 extensions
|
|
1634
|
+
from the center vertex because there are (256/2) ways to put the 8
|
|
1635
|
+
center edges into 2 sets, and then 8 more for series extensions of the
|
|
1636
|
+
rims::
|
|
1637
|
+
|
|
1638
|
+
sage: M = Matroid(graphs.WheelGraph(9))
|
|
1639
|
+
sage: I = M.graphic_coextensions()
|
|
1640
|
+
sage: sum(1 for N in I)
|
|
1641
|
+
136
|
|
1642
|
+
sage: I = M.graphic_coextensions(cosimple=True)
|
|
1643
|
+
sage: sum(1 for N in I)
|
|
1644
|
+
119
|
|
1645
|
+
sage: sum(1 for N in Matroid(graphs.WheelGraph(8)).graphic_coextensions())
|
|
1646
|
+
71
|
|
1647
|
+
|
|
1648
|
+
This graph has max degree 3, so the only series extensions should be
|
|
1649
|
+
non-cosimple, ie. a coloop and one for every coseries class.
|
|
1650
|
+
12 total::
|
|
1651
|
+
|
|
1652
|
+
sage: edgedict = {0: [1, 2, 3], 1: [2, 4], 2: [3], 3: [6],
|
|
1653
|
+
....: 4: [5, 7], 5: [6, 7], 6: [7]}
|
|
1654
|
+
sage: M = Matroid(range(12), Graph(edgedict))
|
|
1655
|
+
sage: sorted(M.coclosure([4]))
|
|
1656
|
+
[4, 6]
|
|
1657
|
+
sage: sum(1 for N in M.graphic_coextensions())
|
|
1658
|
+
12
|
|
1659
|
+
sage: sum(1 for N in M.graphic_coextensions(cosimple=True))
|
|
1660
|
+
0
|
|
1661
|
+
"""
|
|
1662
|
+
G = self.graph()
|
|
1663
|
+
if element is None:
|
|
1664
|
+
element = newlabel(self.groundset())
|
|
1665
|
+
elif element in self.groundset():
|
|
1666
|
+
raise ValueError("cannot extend by element already in groundset")
|
|
1667
|
+
if vertices is None:
|
|
1668
|
+
vertices = self._G.vertices(sort=False)
|
|
1669
|
+
elif not set(vertices).issubset(self._G.vertices(sort=False)):
|
|
1670
|
+
raise ValueError("vertices are not all in the graph")
|
|
1671
|
+
|
|
1672
|
+
if v is None:
|
|
1673
|
+
# we just need to know what the vertex's name will be
|
|
1674
|
+
v = G.add_vertex()
|
|
1675
|
+
G.delete_vertex(v)
|
|
1676
|
+
elif v in G:
|
|
1677
|
+
raise ValueError("vertex is already in the graph")
|
|
1678
|
+
|
|
1679
|
+
if not cosimple:
|
|
1680
|
+
# First extend by a coloop on the first vertex.
|
|
1681
|
+
G.add_edge(vertices[0], v, element)
|
|
1682
|
+
yield GraphicMatroid(G)
|
|
1683
|
+
G.delete_vertex(v)
|
|
1684
|
+
|
|
1685
|
+
# Next add an edge in series, for every series class in the input
|
|
1686
|
+
edges = set(G.edges_incident(vertices))
|
|
1687
|
+
while edges:
|
|
1688
|
+
u0, v0, l = edges.pop()
|
|
1689
|
+
G.delete_edge(u0, v0, l)
|
|
1690
|
+
# place the new element on v0 if v0 is a vertex from input
|
|
1691
|
+
if v0 in vertices:
|
|
1692
|
+
G.add_edge(u0, v, l)
|
|
1693
|
+
G.add_edge(v, v0, element)
|
|
1694
|
+
else:
|
|
1695
|
+
G.add_edge(u0, v, element)
|
|
1696
|
+
G.add_edge(v, v0, l)
|
|
1697
|
+
yield GraphicMatroid(G)
|
|
1698
|
+
G.delete_vertex(v)
|
|
1699
|
+
G.add_edge(u0, v0, l)
|
|
1700
|
+
|
|
1701
|
+
edges.difference_update(self.groundset_to_edges(self.coclosure([l])))
|
|
1702
|
+
|
|
1703
|
+
# If a vertex has degree 1, or 2, or 3, we already handled it.
|
|
1704
|
+
for u in vertices:
|
|
1705
|
+
if G.degree(u) > 3:
|
|
1706
|
+
elts_incident = [l for _, _, l in G.edges_incident(u)]
|
|
1707
|
+
x = elts_incident.pop()
|
|
1708
|
+
for i in range(1, len(elts_incident) - 1):
|
|
1709
|
+
groups = combinations(elts_incident, i)
|
|
1710
|
+
for g in groups:
|
|
1711
|
+
g = list(g)
|
|
1712
|
+
g.append(x)
|
|
1713
|
+
yield self.graphic_coextension(
|
|
1714
|
+
X=g, u=u, v=v, element=element)
|
|
1715
|
+
|
|
1716
|
+
cpdef twist(self, X):
|
|
1717
|
+
"""
|
|
1718
|
+
Perform a Whitney twist on the graph.
|
|
1719
|
+
|
|
1720
|
+
`X` must be part of a 2-separation.
|
|
1721
|
+
The connectivity of `X` must be 1, and the subgraph induced by `X` must
|
|
1722
|
+
intersect the subgraph induced by the rest of the elements on exactly
|
|
1723
|
+
two vertices.
|
|
1724
|
+
|
|
1725
|
+
INPUT:
|
|
1726
|
+
|
|
1727
|
+
- ``X`` -- the set of elements to be twisted with respect
|
|
1728
|
+
to the rest of the matroid
|
|
1729
|
+
|
|
1730
|
+
OUTPUT: :class:`GraphicMatroid` isomorphic to this matroid but
|
|
1731
|
+
with a graph that is not necessarily isomorphic
|
|
1732
|
+
|
|
1733
|
+
EXAMPLES::
|
|
1734
|
+
|
|
1735
|
+
sage: edgelist = [(0, 1, 0), (1, 2, 1), (1, 2, 2), (2, 3, 3),
|
|
1736
|
+
....: (2, 3, 4), (2, 3, 5), (3, 0, 6)]
|
|
1737
|
+
sage: M = Matroid(Graph(edgelist, multiedges=True))
|
|
1738
|
+
sage: M1 = M.twist([0, 1, 2]); M1.graph().edges(sort=True)
|
|
1739
|
+
[(0, 1, 1), (0, 1, 2), (0, 3, 6), (1, 2, 0), (2, 3, 3), (2, 3, 4), (2, 3, 5)]
|
|
1740
|
+
sage: M2 = M.twist([0, 1, 3])
|
|
1741
|
+
Traceback (most recent call last):
|
|
1742
|
+
...
|
|
1743
|
+
ValueError: the input must display a 2-separation that is not a 1-separation
|
|
1744
|
+
|
|
1745
|
+
TESTS::
|
|
1746
|
+
|
|
1747
|
+
sage: edgedict = {0: [1, 2], 1: [2, 3], 2: [3], 3: [4, 5], 4: [5]}
|
|
1748
|
+
sage: M = Matroid(range(8), Graph(edgedict))
|
|
1749
|
+
sage: M.graph().edges(sort=True)
|
|
1750
|
+
[(0, 1, 0),
|
|
1751
|
+
(0, 2, 1),
|
|
1752
|
+
(1, 2, 2),
|
|
1753
|
+
(1, 3, 3),
|
|
1754
|
+
(2, 3, 4),
|
|
1755
|
+
(3, 4, 5),
|
|
1756
|
+
(3, 5, 6),
|
|
1757
|
+
(4, 5, 7)]
|
|
1758
|
+
sage: M1 = M.twist([0, 1]); M1.graph().edges(sort=True)
|
|
1759
|
+
[(0, 1, 1),
|
|
1760
|
+
(0, 2, 0),
|
|
1761
|
+
(1, 2, 2),
|
|
1762
|
+
(1, 3, 3),
|
|
1763
|
+
(2, 3, 4),
|
|
1764
|
+
(3, 4, 5),
|
|
1765
|
+
(3, 5, 6),
|
|
1766
|
+
(4, 5, 7)]
|
|
1767
|
+
sage: M2 = M1.twist([0, 1, 2]); M2.graph().edges(sort=True)
|
|
1768
|
+
[(0, 1, 0),
|
|
1769
|
+
(0, 2, 1),
|
|
1770
|
+
(1, 2, 2),
|
|
1771
|
+
(1, 3, 3),
|
|
1772
|
+
(2, 3, 4),
|
|
1773
|
+
(3, 4, 5),
|
|
1774
|
+
(3, 5, 6),
|
|
1775
|
+
(4, 5, 7)]
|
|
1776
|
+
sage: M1 == M
|
|
1777
|
+
False
|
|
1778
|
+
sage: M2 == M
|
|
1779
|
+
True
|
|
1780
|
+
sage: M2.twist([3, 4])
|
|
1781
|
+
Traceback (most recent call last):
|
|
1782
|
+
...
|
|
1783
|
+
ValueError: too many vertices in the intersection
|
|
1784
|
+
"""
|
|
1785
|
+
# We require two things:
|
|
1786
|
+
# (1) The connectivity of X is 1,
|
|
1787
|
+
# (2) X intersects the rest of the graph on 2 vertices
|
|
1788
|
+
if not set(X).issubset(self.groundset()):
|
|
1789
|
+
raise ValueError("X must be a subset of the groundset")
|
|
1790
|
+
connectivity = self.connectivity(X)
|
|
1791
|
+
if connectivity != 1:
|
|
1792
|
+
raise ValueError("the input must display a 2-separation "
|
|
1793
|
+
"that is not a 1-separation")
|
|
1794
|
+
|
|
1795
|
+
# Determine the vertices
|
|
1796
|
+
X_edges = self.groundset_to_edges(X)
|
|
1797
|
+
X_vertices = set([e[0] for e in X_edges]).union(
|
|
1798
|
+
[e[1] for e in X_edges])
|
|
1799
|
+
Y_edges = self.groundset_to_edges(self.groundset().difference(set(X)))
|
|
1800
|
+
Y_vertices = set([e[0] for e in Y_edges]).union(
|
|
1801
|
+
[e[1] for e in Y_edges])
|
|
1802
|
+
vertices = X_vertices.intersection(Y_vertices)
|
|
1803
|
+
if len(vertices) != 2:
|
|
1804
|
+
raise ValueError("too many vertices in the intersection")
|
|
1805
|
+
a = list(vertices)[0]
|
|
1806
|
+
b = list(vertices)[1]
|
|
1807
|
+
|
|
1808
|
+
edges = [(u, v, l) for (u, v, l) in X_edges
|
|
1809
|
+
if u in vertices or v in vertices]
|
|
1810
|
+
G = self.graph()
|
|
1811
|
+
for (u, v, l) in edges:
|
|
1812
|
+
G.delete_edge(u, v, l)
|
|
1813
|
+
if u == a:
|
|
1814
|
+
u = b
|
|
1815
|
+
elif u == b:
|
|
1816
|
+
u = a
|
|
1817
|
+
if v == a:
|
|
1818
|
+
v = b
|
|
1819
|
+
elif v == b:
|
|
1820
|
+
v = a
|
|
1821
|
+
G.add_edge(u, v, l)
|
|
1822
|
+
return GraphicMatroid(G)
|
|
1823
|
+
|
|
1824
|
+
cpdef one_sum(self, X, u, v):
|
|
1825
|
+
"""
|
|
1826
|
+
Arrange matroid components in the graph.
|
|
1827
|
+
|
|
1828
|
+
The matroid's graph must be connected even if the matroid is not
|
|
1829
|
+
connected, but if there are multiple matroid components, the user may
|
|
1830
|
+
choose how they are arranged in the graph. This method will take the
|
|
1831
|
+
block of the graph that represents `X` and attach it by vertex `u` to
|
|
1832
|
+
another vertex `v` in the graph.
|
|
1833
|
+
|
|
1834
|
+
INPUT:
|
|
1835
|
+
|
|
1836
|
+
- ``X`` -- subset of the groundset
|
|
1837
|
+
- ``u`` -- vertex spanned by the edges of the elements in ``X``
|
|
1838
|
+
- ``v`` -- vertex spanned by the edges of the elements not in ``X``
|
|
1839
|
+
|
|
1840
|
+
OUTPUT: :class:`GraphicMatroid` isomorphic to this matroid but
|
|
1841
|
+
with a graph that is not necessarily isomorphic
|
|
1842
|
+
|
|
1843
|
+
EXAMPLES::
|
|
1844
|
+
|
|
1845
|
+
sage: edgedict = {0:[1, 2], 1:[2, 3], 2:[3], 3:[4, 5], 6:[4, 5]}
|
|
1846
|
+
sage: M = Matroid(range(9), Graph(edgedict))
|
|
1847
|
+
sage: M.graph().edges(sort=True)
|
|
1848
|
+
[(0, 1, 0),
|
|
1849
|
+
(0, 2, 1),
|
|
1850
|
+
(1, 2, 2),
|
|
1851
|
+
(1, 3, 3),
|
|
1852
|
+
(2, 3, 4),
|
|
1853
|
+
(3, 4, 5),
|
|
1854
|
+
(3, 5, 6),
|
|
1855
|
+
(4, 6, 7),
|
|
1856
|
+
(5, 6, 8)]
|
|
1857
|
+
sage: M1 = M.one_sum(u=3, v=1, X=[5, 6, 7, 8])
|
|
1858
|
+
sage: M1.graph().edges(sort=True)
|
|
1859
|
+
[(0, 1, 0),
|
|
1860
|
+
(0, 2, 1),
|
|
1861
|
+
(1, 2, 2),
|
|
1862
|
+
(1, 3, 3),
|
|
1863
|
+
(1, 4, 5),
|
|
1864
|
+
(1, 5, 6),
|
|
1865
|
+
(2, 3, 4),
|
|
1866
|
+
(4, 6, 7),
|
|
1867
|
+
(5, 6, 8)]
|
|
1868
|
+
sage: M2 = M.one_sum(u=4, v=3, X=[5, 6, 7, 8])
|
|
1869
|
+
sage: M2.graph().edges(sort=True)
|
|
1870
|
+
[(0, 1, 0),
|
|
1871
|
+
(0, 2, 1),
|
|
1872
|
+
(1, 2, 2),
|
|
1873
|
+
(1, 3, 3),
|
|
1874
|
+
(2, 3, 4),
|
|
1875
|
+
(3, 6, 7),
|
|
1876
|
+
(3, 7, 5),
|
|
1877
|
+
(5, 6, 8),
|
|
1878
|
+
(5, 7, 6)]
|
|
1879
|
+
|
|
1880
|
+
TESTS::
|
|
1881
|
+
|
|
1882
|
+
sage: M = matroids.CompleteGraphic(4)
|
|
1883
|
+
sage: M.one_sum(u=1, v=2, X=[0,1])
|
|
1884
|
+
Traceback (most recent call last):
|
|
1885
|
+
...
|
|
1886
|
+
ValueError: the input must display a 1-separation
|
|
1887
|
+
|
|
1888
|
+
::
|
|
1889
|
+
|
|
1890
|
+
sage: M = Matroid(range(5), graphs.BullGraph())
|
|
1891
|
+
sage: M.graph().edges(sort=True)
|
|
1892
|
+
[(0, 1, 0), (0, 2, 1), (1, 2, 2), (1, 3, 3), (2, 4, 4)]
|
|
1893
|
+
sage: M1 = M.one_sum(u=3, v=0, X=[3,4])
|
|
1894
|
+
Traceback (most recent call last):
|
|
1895
|
+
...
|
|
1896
|
+
ValueError: too many vertices in the intersection
|
|
1897
|
+
|
|
1898
|
+
sage: M1 = M.one_sum(u=3, v=2, X=[3])
|
|
1899
|
+
sage: M1.graph().edges(sort=True)
|
|
1900
|
+
[(0, 1, 0), (0, 2, 1), (1, 2, 2), (2, 4, 4), (2, 5, 3)]
|
|
1901
|
+
|
|
1902
|
+
sage: M2 = M1.one_sum(u=5, v=0, X=[3,4])
|
|
1903
|
+
sage: M2.graph().edges(sort=True)
|
|
1904
|
+
[(0, 1, 0), (0, 2, 1), (0, 3, 3), (1, 2, 2), (3, 4, 4)]
|
|
1905
|
+
|
|
1906
|
+
sage: M = Matroid(range(5), graphs.BullGraph())
|
|
1907
|
+
sage: M.one_sum(u=0, v=1, X=[3])
|
|
1908
|
+
Traceback (most recent call last):
|
|
1909
|
+
...
|
|
1910
|
+
ValueError: first vertex must be spanned by the input
|
|
1911
|
+
|
|
1912
|
+
sage: M.one_sum(u=1, v=3, X=[3])
|
|
1913
|
+
Traceback (most recent call last):
|
|
1914
|
+
...
|
|
1915
|
+
ValueError: second vertex must be spanned by the rest of the graph
|
|
1916
|
+
"""
|
|
1917
|
+
# We require two things:
|
|
1918
|
+
# (1) The connectivity of X is 0,
|
|
1919
|
+
# (2) X intersects the rest of the graph on 1 vertex
|
|
1920
|
+
if not set(X).issubset(self.groundset()):
|
|
1921
|
+
raise ValueError("X must be a subset of the groundset")
|
|
1922
|
+
connectivity = self.connectivity(X)
|
|
1923
|
+
if connectivity != 0:
|
|
1924
|
+
raise ValueError("the input must display a 1-separation")
|
|
1925
|
+
G = self.graph()
|
|
1926
|
+
if u not in G or v not in G:
|
|
1927
|
+
raise ValueError("the vertices must already be in the graph")
|
|
1928
|
+
|
|
1929
|
+
# Determine the vertex
|
|
1930
|
+
X_edges = self.groundset_to_edges(X)
|
|
1931
|
+
X_vertices = set([e[0] for e in X_edges]).union(
|
|
1932
|
+
[e[1] for e in X_edges])
|
|
1933
|
+
if u not in X_vertices:
|
|
1934
|
+
raise ValueError("first vertex must be spanned by the input")
|
|
1935
|
+
Y_edges = self.groundset_to_edges(self.groundset().difference(set(X)))
|
|
1936
|
+
Y_vertices = set([e[0] for e in Y_edges]).union(
|
|
1937
|
+
[e[1] for e in Y_edges])
|
|
1938
|
+
if v not in Y_vertices:
|
|
1939
|
+
raise ValueError("second vertex must be spanned by the rest of the graph")
|
|
1940
|
+
vertices = X_vertices.intersection(Y_vertices)
|
|
1941
|
+
if len(vertices) != 1:
|
|
1942
|
+
raise ValueError("too many vertices in the intersection")
|
|
1943
|
+
a = vertices.pop()
|
|
1944
|
+
b = G.add_vertex()
|
|
1945
|
+
|
|
1946
|
+
edgeset = set(X_edges).intersection(set(G.edges_incident(a)))
|
|
1947
|
+
split_vertex(G, a, b, edgeset)
|
|
1948
|
+
# If u was the cut vertex, u is now detached from our component
|
|
1949
|
+
# so we merge the new vertex. Otherwise we can merge u
|
|
1950
|
+
if u == a:
|
|
1951
|
+
G.merge_vertices([v, b])
|
|
1952
|
+
else:
|
|
1953
|
+
G.merge_vertices([v, u])
|
|
1954
|
+
|
|
1955
|
+
return GraphicMatroid(G)
|
|
1956
|
+
|
|
1957
|
+
cpdef regular_matroid(self):
|
|
1958
|
+
"""
|
|
1959
|
+
Return an instance of :class:`RegularMatroid` isomorphic to this
|
|
1960
|
+
:class:`GraphicMatroid`.
|
|
1961
|
+
|
|
1962
|
+
EXAMPLES::
|
|
1963
|
+
|
|
1964
|
+
sage: M = matroids.CompleteGraphic(5); M
|
|
1965
|
+
M(K5): Graphic matroid of rank 4 on 10 elements
|
|
1966
|
+
sage: N = M.regular_matroid(); N
|
|
1967
|
+
Regular matroid of rank 4 on 10 elements with 125 bases
|
|
1968
|
+
sage: M.equals(N)
|
|
1969
|
+
True
|
|
1970
|
+
sage: M == N
|
|
1971
|
+
False
|
|
1972
|
+
|
|
1973
|
+
TESTS:
|
|
1974
|
+
|
|
1975
|
+
Check that :issue:`28482` is fixed::
|
|
1976
|
+
|
|
1977
|
+
sage: G = Graph([[3, 4], [4, 1], [1, 2], [2, 3], [3, 5], [5, 6], [6, 3]])
|
|
1978
|
+
sage: M = Matroid(G)
|
|
1979
|
+
sage: R = M.regular_matroid()
|
|
1980
|
+
sage: set(M.circuits()) == set(R.circuits())
|
|
1981
|
+
True
|
|
1982
|
+
"""
|
|
1983
|
+
from sage.matroids.constructor import Matroid as ConstructorMatroid
|
|
1984
|
+
X = [l for u, v, l in self._G.edge_iterator()]
|
|
1985
|
+
return ConstructorMatroid(groundset=X, graph=self._G, regular=True)
|
|
1986
|
+
|
|
1987
|
+
cpdef relabel(self, mapping):
|
|
1988
|
+
r"""
|
|
1989
|
+
Return an isomorphic matroid with relabeled groundset.
|
|
1990
|
+
|
|
1991
|
+
The output is obtained by relabeling each element `e` by
|
|
1992
|
+
``mapping[e]``, where ``mapping`` is a given injective map. If
|
|
1993
|
+
``mapping[e]`` is not defined, then the identity map is assumed.
|
|
1994
|
+
|
|
1995
|
+
INPUT:
|
|
1996
|
+
|
|
1997
|
+
- ``mapping`` -- a Python object such that ``mapping[e]`` is the new
|
|
1998
|
+
label of `e`
|
|
1999
|
+
|
|
2000
|
+
OUTPUT: matroid
|
|
2001
|
+
|
|
2002
|
+
EXAMPLES::
|
|
2003
|
+
|
|
2004
|
+
sage: M = matroids.CompleteGraphic(4)
|
|
2005
|
+
sage: sorted(M.groundset())
|
|
2006
|
+
[0, 1, 2, 3, 4, 5]
|
|
2007
|
+
sage: N = M.relabel({0: 6, 5: 'e'})
|
|
2008
|
+
sage: sorted(N.groundset(), key=str)
|
|
2009
|
+
[1, 2, 3, 4, 6, 'e']
|
|
2010
|
+
sage: N.is_isomorphic(M)
|
|
2011
|
+
True
|
|
2012
|
+
|
|
2013
|
+
TESTS::
|
|
2014
|
+
|
|
2015
|
+
sage: M = matroids.CompleteGraphic(4)
|
|
2016
|
+
sage: f = {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g'}
|
|
2017
|
+
sage: N = M.relabel(f)
|
|
2018
|
+
sage: for S in powerset(M.groundset()):
|
|
2019
|
+
....: assert M.rank(S) == N.rank([f[x] for x in S])
|
|
2020
|
+
"""
|
|
2021
|
+
d = self._relabel_map(mapping)
|
|
2022
|
+
E = [d[x] for x in self.groundset()]
|
|
2023
|
+
M = GraphicMatroid(self.graph(), groundset=E)
|
|
2024
|
+
return M
|