passagemath-combinat 10.6.42__cp314-cp314-musllinux_1_2_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.
- passagemath_combinat/__init__.py +3 -0
- passagemath_combinat-10.6.42.dist-info/METADATA +160 -0
- passagemath_combinat-10.6.42.dist-info/RECORD +400 -0
- passagemath_combinat-10.6.42.dist-info/WHEEL +5 -0
- passagemath_combinat-10.6.42.dist-info/top_level.txt +3 -0
- passagemath_combinat.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- passagemath_combinat.libs/libsymmetrica-81fe8739.so.3.0.0 +0 -0
- sage/algebras/affine_nil_temperley_lieb.py +263 -0
- sage/algebras/all.py +24 -0
- sage/algebras/all__sagemath_combinat.py +35 -0
- sage/algebras/askey_wilson.py +935 -0
- sage/algebras/associated_graded.py +345 -0
- sage/algebras/cellular_basis.py +350 -0
- sage/algebras/cluster_algebra.py +2766 -0
- sage/algebras/down_up_algebra.py +860 -0
- sage/algebras/free_algebra.py +1698 -0
- sage/algebras/free_algebra_element.py +345 -0
- sage/algebras/free_algebra_quotient.py +405 -0
- sage/algebras/free_algebra_quotient_element.py +295 -0
- sage/algebras/free_zinbiel_algebra.py +885 -0
- sage/algebras/hall_algebra.py +783 -0
- sage/algebras/hecke_algebras/all.py +4 -0
- sage/algebras/hecke_algebras/ariki_koike_algebra.py +1796 -0
- sage/algebras/hecke_algebras/ariki_koike_specht_modules.py +475 -0
- sage/algebras/hecke_algebras/cubic_hecke_algebra.py +3520 -0
- sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +1473 -0
- sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +1079 -0
- sage/algebras/iwahori_hecke_algebra.py +3095 -0
- sage/algebras/jordan_algebra.py +1773 -0
- sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +113 -0
- sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +156 -0
- sage/algebras/lie_conformal_algebras/all.py +18 -0
- sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +134 -0
- sage/algebras/lie_conformal_algebras/examples.py +43 -0
- sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +131 -0
- sage/algebras/lie_conformal_algebras/finitely_freely_generated_lca.py +139 -0
- sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +174 -0
- sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +167 -0
- sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py +107 -0
- sage/algebras/lie_conformal_algebras/graded_lie_conformal_algebra.py +135 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +353 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_element.py +236 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_basis.py +78 -0
- sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +328 -0
- sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +117 -0
- sage/algebras/lie_conformal_algebras/neveu_schwarz_lie_conformal_algebra.py +86 -0
- sage/algebras/lie_conformal_algebras/virasoro_lie_conformal_algebra.py +82 -0
- sage/algebras/lie_conformal_algebras/weyl_lie_conformal_algebra.py +205 -0
- sage/algebras/nil_coxeter_algebra.py +191 -0
- sage/algebras/q_commuting_polynomials.py +673 -0
- sage/algebras/q_system.py +608 -0
- sage/algebras/quantum_clifford.py +959 -0
- sage/algebras/quantum_groups/ace_quantum_onsager.py +693 -0
- sage/algebras/quantum_groups/all.py +9 -0
- sage/algebras/quantum_groups/fock_space.py +2219 -0
- sage/algebras/quantum_groups/q_numbers.py +207 -0
- sage/algebras/quantum_groups/quantum_group_gap.py +2695 -0
- sage/algebras/quantum_groups/representations.py +591 -0
- sage/algebras/quantum_matrix_coordinate_algebra.py +1006 -0
- sage/algebras/quantum_oscillator.py +623 -0
- sage/algebras/quaternion_algebra.py +20 -0
- sage/algebras/quaternion_algebra_element.py +55 -0
- sage/algebras/rational_cherednik_algebra.py +525 -0
- sage/algebras/schur_algebra.py +670 -0
- sage/algebras/shuffle_algebra.py +1011 -0
- sage/algebras/splitting_algebra.py +779 -0
- sage/algebras/tensor_algebra.py +709 -0
- sage/algebras/yangian.py +1082 -0
- sage/algebras/yokonuma_hecke_algebra.py +1018 -0
- sage/all__sagemath_combinat.py +35 -0
- sage/combinat/SJT.py +255 -0
- sage/combinat/affine_permutation.py +2405 -0
- sage/combinat/algebraic_combinatorics.py +55 -0
- sage/combinat/all.py +53 -0
- sage/combinat/all__sagemath_combinat.py +195 -0
- sage/combinat/alternating_sign_matrix.py +2063 -0
- sage/combinat/baxter_permutations.py +346 -0
- sage/combinat/bijectionist.py +3220 -0
- sage/combinat/binary_recurrence_sequences.py +1180 -0
- sage/combinat/blob_algebra.py +685 -0
- sage/combinat/catalog_partitions.py +27 -0
- sage/combinat/chas/all.py +23 -0
- sage/combinat/chas/fsym.py +1180 -0
- sage/combinat/chas/wqsym.py +2601 -0
- sage/combinat/cluster_complex.py +326 -0
- sage/combinat/colored_permutations.py +2039 -0
- sage/combinat/colored_permutations_representations.py +964 -0
- sage/combinat/composition_signed.py +142 -0
- sage/combinat/composition_tableau.py +855 -0
- sage/combinat/constellation.py +1729 -0
- sage/combinat/core.py +751 -0
- sage/combinat/counting.py +12 -0
- sage/combinat/crystals/affine.py +742 -0
- sage/combinat/crystals/affine_factorization.py +518 -0
- sage/combinat/crystals/affinization.py +331 -0
- sage/combinat/crystals/alcove_path.py +2013 -0
- sage/combinat/crystals/all.py +22 -0
- sage/combinat/crystals/bkk_crystals.py +141 -0
- sage/combinat/crystals/catalog.py +115 -0
- sage/combinat/crystals/catalog_elementary_crystals.py +18 -0
- sage/combinat/crystals/catalog_infinity_crystals.py +33 -0
- sage/combinat/crystals/catalog_kirillov_reshetikhin.py +18 -0
- sage/combinat/crystals/crystals.py +257 -0
- sage/combinat/crystals/direct_sum.py +260 -0
- sage/combinat/crystals/elementary_crystals.py +1251 -0
- sage/combinat/crystals/fast_crystals.py +441 -0
- sage/combinat/crystals/fully_commutative_stable_grothendieck.py +1205 -0
- sage/combinat/crystals/generalized_young_walls.py +1076 -0
- sage/combinat/crystals/highest_weight_crystals.py +436 -0
- sage/combinat/crystals/induced_structure.py +695 -0
- sage/combinat/crystals/infinity_crystals.py +730 -0
- sage/combinat/crystals/kac_modules.py +863 -0
- sage/combinat/crystals/kirillov_reshetikhin.py +4196 -0
- sage/combinat/crystals/kyoto_path_model.py +497 -0
- sage/combinat/crystals/letters.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/letters.pxd +79 -0
- sage/combinat/crystals/letters.pyx +3056 -0
- sage/combinat/crystals/littelmann_path.py +1518 -0
- sage/combinat/crystals/monomial_crystals.py +1262 -0
- sage/combinat/crystals/multisegments.py +462 -0
- sage/combinat/crystals/mv_polytopes.py +467 -0
- sage/combinat/crystals/pbw_crystal.py +511 -0
- sage/combinat/crystals/pbw_datum.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/pbw_datum.pxd +4 -0
- sage/combinat/crystals/pbw_datum.pyx +487 -0
- sage/combinat/crystals/polyhedral_realization.py +372 -0
- sage/combinat/crystals/spins.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/spins.pxd +21 -0
- sage/combinat/crystals/spins.pyx +756 -0
- sage/combinat/crystals/star_crystal.py +290 -0
- sage/combinat/crystals/subcrystal.py +464 -0
- sage/combinat/crystals/tensor_product.py +1177 -0
- sage/combinat/crystals/tensor_product_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/crystals/tensor_product_element.pxd +35 -0
- sage/combinat/crystals/tensor_product_element.pyx +1870 -0
- sage/combinat/crystals/virtual_crystal.py +420 -0
- sage/combinat/cyclic_sieving_phenomenon.py +204 -0
- sage/combinat/debruijn_sequence.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/debruijn_sequence.pyx +355 -0
- sage/combinat/decorated_permutation.py +270 -0
- sage/combinat/degree_sequences.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/degree_sequences.pyx +588 -0
- sage/combinat/derangements.py +527 -0
- sage/combinat/descent_algebra.py +1008 -0
- sage/combinat/diagram.py +1551 -0
- sage/combinat/diagram_algebras.py +5886 -0
- sage/combinat/dyck_word.py +4349 -0
- sage/combinat/e_one_star.py +1623 -0
- sage/combinat/enumerated_sets.py +123 -0
- sage/combinat/expnums.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/expnums.pyx +148 -0
- sage/combinat/fast_vector_partitions.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/fast_vector_partitions.pyx +346 -0
- sage/combinat/fqsym.py +1977 -0
- sage/combinat/free_dendriform_algebra.py +954 -0
- sage/combinat/free_prelie_algebra.py +1141 -0
- sage/combinat/fully_commutative_elements.py +1077 -0
- sage/combinat/fully_packed_loop.py +1523 -0
- sage/combinat/gelfand_tsetlin_patterns.py +1409 -0
- sage/combinat/gray_codes.py +311 -0
- sage/combinat/grossman_larson_algebras.py +667 -0
- sage/combinat/growth.py +4352 -0
- sage/combinat/hall_polynomial.py +188 -0
- sage/combinat/hillman_grassl.py +866 -0
- sage/combinat/integer_matrices.py +329 -0
- sage/combinat/integer_vectors_mod_permgroup.py +1238 -0
- sage/combinat/k_tableau.py +4564 -0
- sage/combinat/kazhdan_lusztig.py +215 -0
- sage/combinat/key_polynomial.py +885 -0
- sage/combinat/knutson_tao_puzzles.py +2286 -0
- sage/combinat/lr_tableau.py +311 -0
- sage/combinat/matrices/all.py +24 -0
- sage/combinat/matrices/hadamard_matrix.py +3790 -0
- sage/combinat/matrices/latin.py +2912 -0
- sage/combinat/misc.py +401 -0
- sage/combinat/multiset_partition_into_sets_ordered.py +3541 -0
- sage/combinat/ncsf_qsym/all.py +21 -0
- sage/combinat/ncsf_qsym/combinatorics.py +317 -0
- sage/combinat/ncsf_qsym/generic_basis_code.py +1427 -0
- sage/combinat/ncsf_qsym/ncsf.py +5637 -0
- sage/combinat/ncsf_qsym/qsym.py +4053 -0
- sage/combinat/ncsf_qsym/tutorial.py +447 -0
- sage/combinat/ncsym/all.py +21 -0
- sage/combinat/ncsym/bases.py +855 -0
- sage/combinat/ncsym/dual.py +593 -0
- sage/combinat/ncsym/ncsym.py +2076 -0
- sage/combinat/necklace.py +551 -0
- sage/combinat/non_decreasing_parking_function.py +634 -0
- sage/combinat/nu_dyck_word.py +1474 -0
- sage/combinat/output.py +861 -0
- sage/combinat/parallelogram_polyomino.py +4326 -0
- sage/combinat/parking_functions.py +1602 -0
- sage/combinat/partition_algebra.py +1998 -0
- sage/combinat/partition_kleshchev.py +1982 -0
- sage/combinat/partition_shifting_algebras.py +584 -0
- sage/combinat/partition_tuple.py +3114 -0
- sage/combinat/path_tableaux/all.py +13 -0
- sage/combinat/path_tableaux/catalog.py +29 -0
- sage/combinat/path_tableaux/dyck_path.py +380 -0
- sage/combinat/path_tableaux/frieze.py +476 -0
- sage/combinat/path_tableaux/path_tableau.py +728 -0
- sage/combinat/path_tableaux/semistandard.py +510 -0
- sage/combinat/perfect_matching.py +779 -0
- sage/combinat/plane_partition.py +3300 -0
- sage/combinat/q_bernoulli.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/q_bernoulli.pyx +128 -0
- sage/combinat/quickref.py +81 -0
- sage/combinat/recognizable_series.py +2051 -0
- sage/combinat/regular_sequence.py +4316 -0
- sage/combinat/regular_sequence_bounded.py +543 -0
- sage/combinat/restricted_growth.py +81 -0
- sage/combinat/ribbon.py +20 -0
- sage/combinat/ribbon_shaped_tableau.py +489 -0
- sage/combinat/ribbon_tableau.py +1180 -0
- sage/combinat/rigged_configurations/all.py +46 -0
- sage/combinat/rigged_configurations/bij_abstract_class.py +548 -0
- sage/combinat/rigged_configurations/bij_infinity.py +370 -0
- sage/combinat/rigged_configurations/bij_type_A.py +163 -0
- sage/combinat/rigged_configurations/bij_type_A2_dual.py +338 -0
- sage/combinat/rigged_configurations/bij_type_A2_even.py +218 -0
- sage/combinat/rigged_configurations/bij_type_A2_odd.py +199 -0
- sage/combinat/rigged_configurations/bij_type_B.py +900 -0
- sage/combinat/rigged_configurations/bij_type_C.py +267 -0
- sage/combinat/rigged_configurations/bij_type_D.py +771 -0
- sage/combinat/rigged_configurations/bij_type_D_tri.py +392 -0
- sage/combinat/rigged_configurations/bij_type_D_twisted.py +576 -0
- sage/combinat/rigged_configurations/bij_type_E67.py +402 -0
- sage/combinat/rigged_configurations/bijection.py +143 -0
- sage/combinat/rigged_configurations/kleber_tree.py +1475 -0
- sage/combinat/rigged_configurations/kr_tableaux.py +1898 -0
- sage/combinat/rigged_configurations/rc_crystal.py +461 -0
- sage/combinat/rigged_configurations/rc_infinity.py +540 -0
- sage/combinat/rigged_configurations/rigged_configuration_element.py +2403 -0
- sage/combinat/rigged_configurations/rigged_configurations.py +1918 -0
- sage/combinat/rigged_configurations/rigged_partition.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/rigged_configurations/rigged_partition.pxd +15 -0
- sage/combinat/rigged_configurations/rigged_partition.pyx +680 -0
- sage/combinat/rigged_configurations/tensor_product_kr_tableaux.py +499 -0
- sage/combinat/rigged_configurations/tensor_product_kr_tableaux_element.py +428 -0
- sage/combinat/rsk.py +3438 -0
- sage/combinat/schubert_polynomial.py +508 -0
- sage/combinat/set_partition.py +3318 -0
- sage/combinat/set_partition_iterator.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/set_partition_iterator.pyx +136 -0
- sage/combinat/set_partition_ordered.py +1590 -0
- sage/combinat/sf/abreu_nigro.py +346 -0
- sage/combinat/sf/all.py +52 -0
- sage/combinat/sf/character.py +576 -0
- sage/combinat/sf/classical.py +319 -0
- sage/combinat/sf/dual.py +996 -0
- sage/combinat/sf/elementary.py +549 -0
- sage/combinat/sf/hall_littlewood.py +1028 -0
- sage/combinat/sf/hecke.py +336 -0
- sage/combinat/sf/homogeneous.py +464 -0
- sage/combinat/sf/jack.py +1428 -0
- sage/combinat/sf/k_dual.py +1458 -0
- sage/combinat/sf/kfpoly.py +447 -0
- sage/combinat/sf/llt.py +789 -0
- sage/combinat/sf/macdonald.py +2019 -0
- sage/combinat/sf/monomial.py +525 -0
- sage/combinat/sf/multiplicative.py +113 -0
- sage/combinat/sf/new_kschur.py +1786 -0
- sage/combinat/sf/ns_macdonald.py +964 -0
- sage/combinat/sf/orthogonal.py +246 -0
- sage/combinat/sf/orthotriang.py +355 -0
- sage/combinat/sf/powersum.py +963 -0
- sage/combinat/sf/schur.py +880 -0
- sage/combinat/sf/sf.py +1653 -0
- sage/combinat/sf/sfa.py +7053 -0
- sage/combinat/sf/symplectic.py +253 -0
- sage/combinat/sf/witt.py +721 -0
- sage/combinat/shifted_primed_tableau.py +2735 -0
- sage/combinat/shuffle.py +830 -0
- sage/combinat/sidon_sets.py +146 -0
- sage/combinat/similarity_class_type.py +1721 -0
- sage/combinat/sine_gordon.py +618 -0
- sage/combinat/six_vertex_model.py +784 -0
- sage/combinat/skew_partition.py +2053 -0
- sage/combinat/skew_tableau.py +2989 -0
- sage/combinat/sloane_functions.py +8935 -0
- sage/combinat/specht_module.py +1403 -0
- sage/combinat/species/all.py +48 -0
- sage/combinat/species/characteristic_species.py +321 -0
- sage/combinat/species/composition_species.py +273 -0
- sage/combinat/species/cycle_species.py +284 -0
- sage/combinat/species/empty_species.py +155 -0
- sage/combinat/species/functorial_composition_species.py +148 -0
- sage/combinat/species/generating_series.py +673 -0
- sage/combinat/species/library.py +148 -0
- sage/combinat/species/linear_order_species.py +169 -0
- sage/combinat/species/misc.py +83 -0
- sage/combinat/species/partition_species.py +290 -0
- sage/combinat/species/permutation_species.py +268 -0
- sage/combinat/species/product_species.py +423 -0
- sage/combinat/species/recursive_species.py +476 -0
- sage/combinat/species/set_species.py +192 -0
- sage/combinat/species/species.py +820 -0
- sage/combinat/species/structure.py +539 -0
- sage/combinat/species/subset_species.py +243 -0
- sage/combinat/species/sum_species.py +225 -0
- sage/combinat/subword.py +564 -0
- sage/combinat/subword_complex.py +2122 -0
- sage/combinat/subword_complex_c.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/subword_complex_c.pyx +119 -0
- sage/combinat/super_tableau.py +821 -0
- sage/combinat/superpartition.py +1154 -0
- sage/combinat/symmetric_group_algebra.py +3774 -0
- sage/combinat/symmetric_group_representations.py +1830 -0
- sage/combinat/t_sequences.py +877 -0
- sage/combinat/tableau.py +9506 -0
- sage/combinat/tableau_residues.py +860 -0
- sage/combinat/tableau_tuple.py +5353 -0
- sage/combinat/tiling.py +2432 -0
- sage/combinat/triangles_FHM.py +777 -0
- sage/combinat/tutorial.py +1857 -0
- sage/combinat/vector_partition.py +337 -0
- sage/combinat/words/abstract_word.py +1722 -0
- sage/combinat/words/all.py +59 -0
- sage/combinat/words/alphabet.py +268 -0
- sage/combinat/words/finite_word.py +7201 -0
- sage/combinat/words/infinite_word.py +113 -0
- sage/combinat/words/lyndon_word.py +652 -0
- sage/combinat/words/morphic.py +351 -0
- sage/combinat/words/morphism.py +3878 -0
- sage/combinat/words/paths.py +2932 -0
- sage/combinat/words/shuffle_product.py +278 -0
- sage/combinat/words/suffix_trees.py +1873 -0
- sage/combinat/words/word.py +769 -0
- sage/combinat/words/word_char.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/words/word_char.pyx +847 -0
- sage/combinat/words/word_datatypes.cpython-314-x86_64-linux-musl.so +0 -0
- sage/combinat/words/word_datatypes.pxd +4 -0
- sage/combinat/words/word_datatypes.pyx +1067 -0
- sage/combinat/words/word_generators.py +2026 -0
- sage/combinat/words/word_infinite_datatypes.py +1218 -0
- sage/combinat/words/word_options.py +99 -0
- sage/combinat/words/words.py +2396 -0
- sage/data_structures/all__sagemath_combinat.py +1 -0
- sage/databases/all__sagemath_combinat.py +13 -0
- sage/databases/findstat.py +4897 -0
- sage/databases/oeis.py +2058 -0
- sage/databases/sloane.py +393 -0
- sage/dynamics/all__sagemath_combinat.py +14 -0
- sage/dynamics/cellular_automata/all.py +7 -0
- sage/dynamics/cellular_automata/catalog.py +34 -0
- sage/dynamics/cellular_automata/elementary.py +612 -0
- sage/dynamics/cellular_automata/glca.py +477 -0
- sage/dynamics/cellular_automata/solitons.py +1463 -0
- sage/dynamics/finite_dynamical_system.py +1249 -0
- sage/dynamics/finite_dynamical_system_catalog.py +382 -0
- sage/games/all.py +7 -0
- sage/games/hexad.py +704 -0
- sage/games/quantumino.py +591 -0
- sage/games/sudoku.py +889 -0
- sage/games/sudoku_backtrack.cpython-314-x86_64-linux-musl.so +0 -0
- sage/games/sudoku_backtrack.pyx +189 -0
- sage/groups/all__sagemath_combinat.py +1 -0
- sage/groups/indexed_free_group.py +489 -0
- sage/libs/all__sagemath_combinat.py +6 -0
- sage/libs/lrcalc/__init__.py +1 -0
- sage/libs/lrcalc/lrcalc.py +525 -0
- sage/libs/symmetrica/__init__.py +7 -0
- sage/libs/symmetrica/all.py +101 -0
- sage/libs/symmetrica/kostka.pxi +168 -0
- sage/libs/symmetrica/part.pxi +193 -0
- sage/libs/symmetrica/plet.pxi +42 -0
- sage/libs/symmetrica/sab.pxi +196 -0
- sage/libs/symmetrica/sb.pxi +332 -0
- sage/libs/symmetrica/sc.pxi +192 -0
- sage/libs/symmetrica/schur.pxi +956 -0
- sage/libs/symmetrica/symmetrica.cpython-314-x86_64-linux-musl.so +0 -0
- sage/libs/symmetrica/symmetrica.pxi +1172 -0
- sage/libs/symmetrica/symmetrica.pyx +39 -0
- sage/monoids/all.py +13 -0
- sage/monoids/automatic_semigroup.py +1054 -0
- sage/monoids/free_abelian_monoid.py +315 -0
- sage/monoids/free_abelian_monoid_element.cpython-314-x86_64-linux-musl.so +0 -0
- sage/monoids/free_abelian_monoid_element.pxd +16 -0
- sage/monoids/free_abelian_monoid_element.pyx +397 -0
- sage/monoids/free_monoid.py +335 -0
- sage/monoids/free_monoid_element.py +431 -0
- sage/monoids/hecke_monoid.py +65 -0
- sage/monoids/string_monoid.py +817 -0
- sage/monoids/string_monoid_element.py +547 -0
- sage/monoids/string_ops.py +143 -0
- sage/monoids/trace_monoid.py +972 -0
- sage/rings/all__sagemath_combinat.py +2 -0
- sage/sat/all.py +4 -0
- sage/sat/boolean_polynomials.py +405 -0
- sage/sat/converters/__init__.py +6 -0
- sage/sat/converters/anf2cnf.py +14 -0
- sage/sat/converters/polybori.py +611 -0
- sage/sat/solvers/__init__.py +5 -0
- sage/sat/solvers/cryptominisat.py +287 -0
- sage/sat/solvers/dimacs.py +783 -0
- sage/sat/solvers/picosat.py +228 -0
- sage/sat/solvers/sat_lp.py +156 -0
- sage/sat/solvers/satsolver.cpython-314-x86_64-linux-musl.so +0 -0
- sage/sat/solvers/satsolver.pxd +3 -0
- sage/sat/solvers/satsolver.pyx +405 -0
|
@@ -0,0 +1,779 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
|
|
3
|
+
r"""
|
|
4
|
+
Perfect matchings
|
|
5
|
+
|
|
6
|
+
A perfect matching of a set `S` is a partition into 2-element sets. If `S` is
|
|
7
|
+
the set `\{1,...,n\}`, it is equivalent to fixpoint-free involutions. These
|
|
8
|
+
simple combinatorial objects appear in different domains such as combinatorics
|
|
9
|
+
of orthogonal polynomials and of the hyperoctaedral groups (see [MV]_, [McD]_
|
|
10
|
+
and also [CM]_):
|
|
11
|
+
|
|
12
|
+
AUTHOR:
|
|
13
|
+
|
|
14
|
+
- Valentin Feray, 2010 : initial version
|
|
15
|
+
- Martin Rubey, 2017: inherit from SetPartition, move crossings
|
|
16
|
+
and nestings to SetPartition
|
|
17
|
+
|
|
18
|
+
EXAMPLES:
|
|
19
|
+
|
|
20
|
+
Create a perfect matching::
|
|
21
|
+
|
|
22
|
+
sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]);m
|
|
23
|
+
[('a', 'e'), ('b', 'c'), ('d', 'f')]
|
|
24
|
+
|
|
25
|
+
Count its crossings, if the ground set is totally ordered::
|
|
26
|
+
|
|
27
|
+
sage: n = PerfectMatching([3,8,1,7,6,5,4,2]); n
|
|
28
|
+
[(1, 3), (2, 8), (4, 7), (5, 6)]
|
|
29
|
+
sage: n.number_of_crossings()
|
|
30
|
+
1
|
|
31
|
+
|
|
32
|
+
List the perfect matchings of a given ground set::
|
|
33
|
+
|
|
34
|
+
sage: PerfectMatchings(4).list()
|
|
35
|
+
[[(1, 2), (3, 4)], [(1, 3), (2, 4)], [(1, 4), (2, 3)]]
|
|
36
|
+
|
|
37
|
+
REFERENCES:
|
|
38
|
+
|
|
39
|
+
.. [MV] combinatorics of orthogonal polynomials (A. de Medicis et
|
|
40
|
+
X.Viennot, Moments des q-polynômes de Laguerre et la bijection de
|
|
41
|
+
Foata-Zeilberger, Adv. Appl. Math., 15 (1994), 262-304)
|
|
42
|
+
|
|
43
|
+
.. [McD] combinatorics of hyperoctahedral group, double coset algebra and
|
|
44
|
+
zonal polynomials (I. G. Macdonald, Symmetric functions and Hall
|
|
45
|
+
polynomials, Oxford University Press, second edition, 1995, chapter
|
|
46
|
+
VII).
|
|
47
|
+
|
|
48
|
+
.. [CM] Benoit Collins, Sho Matsumoto, *On some properties of
|
|
49
|
+
orthogonal Weingarten functions*, :arxiv:`0903.5143`.
|
|
50
|
+
"""
|
|
51
|
+
# ****************************************************************************
|
|
52
|
+
# Copyright (C) 2010 Valentin Feray <feray@labri.fr>
|
|
53
|
+
#
|
|
54
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
55
|
+
# https://www.gnu.org/licenses/
|
|
56
|
+
# ****************************************************************************
|
|
57
|
+
|
|
58
|
+
from sage.misc.cachefunc import cached_method
|
|
59
|
+
from sage.rings.integer import Integer
|
|
60
|
+
from sage.combinat.permutation import Permutation, Permutations
|
|
61
|
+
from sage.sets.set import Set
|
|
62
|
+
from sage.structure.list_clone import ClonableArray
|
|
63
|
+
from sage.combinat.partition import Partition
|
|
64
|
+
from sage.misc.misc_c import prod
|
|
65
|
+
from sage.misc.lazy_import import lazy_import
|
|
66
|
+
from sage.combinat.set_partition import SetPartition, SetPartitions_set
|
|
67
|
+
from sage.combinat.combinat_cython import perfect_matchings_iterator
|
|
68
|
+
from sage.rings.infinity import infinity
|
|
69
|
+
|
|
70
|
+
lazy_import('sage.matrix.constructor', 'matrix')
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class PerfectMatching(SetPartition):
|
|
74
|
+
r"""
|
|
75
|
+
A perfect matching.
|
|
76
|
+
|
|
77
|
+
A *perfect matching* of a set `X` is a set partition of `X` where
|
|
78
|
+
all parts have size 2.
|
|
79
|
+
|
|
80
|
+
A perfect matching can be created from a list of pairs or from a
|
|
81
|
+
fixed point-free involution as follows::
|
|
82
|
+
|
|
83
|
+
sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]);m
|
|
84
|
+
[('a', 'e'), ('b', 'c'), ('d', 'f')]
|
|
85
|
+
sage: n = PerfectMatching([3,8,1,7,6,5,4,2]);n
|
|
86
|
+
[(1, 3), (2, 8), (4, 7), (5, 6)]
|
|
87
|
+
sage: isinstance(m,PerfectMatching)
|
|
88
|
+
True
|
|
89
|
+
|
|
90
|
+
The parent, which is the set of perfect matchings of the ground set, is
|
|
91
|
+
automatically created::
|
|
92
|
+
|
|
93
|
+
sage: n.parent()
|
|
94
|
+
Perfect matchings of {1, 2, 3, 4, 5, 6, 7, 8}
|
|
95
|
+
|
|
96
|
+
If the ground set is ordered, one can, for example, ask if the matching is
|
|
97
|
+
non crossing::
|
|
98
|
+
|
|
99
|
+
sage: PerfectMatching([(1, 4), (2, 3), (5, 6)]).is_noncrossing()
|
|
100
|
+
True
|
|
101
|
+
|
|
102
|
+
TESTS::
|
|
103
|
+
|
|
104
|
+
sage: m = PerfectMatching([]); m
|
|
105
|
+
[]
|
|
106
|
+
sage: m.parent()
|
|
107
|
+
Perfect matchings of {}
|
|
108
|
+
"""
|
|
109
|
+
@staticmethod
|
|
110
|
+
def __classcall_private__(cls, parts):
|
|
111
|
+
"""
|
|
112
|
+
Create a perfect matching from ``parts`` with the appropriate parent.
|
|
113
|
+
|
|
114
|
+
This function tries to recognize the input (it can be either a list or
|
|
115
|
+
a tuple of pairs, or a fix-point free involution given as a list or as
|
|
116
|
+
a permutation), constructs the parent (enumerated set of
|
|
117
|
+
PerfectMatchings of the ground set) and calls the __init__ function to
|
|
118
|
+
construct our object.
|
|
119
|
+
|
|
120
|
+
EXAMPLES::
|
|
121
|
+
|
|
122
|
+
sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')]);m
|
|
123
|
+
[('a', 'e'), ('b', 'c'), ('d', 'f')]
|
|
124
|
+
sage: isinstance(m, PerfectMatching)
|
|
125
|
+
True
|
|
126
|
+
sage: n = PerfectMatching([3, 8, 1, 7, 6, 5, 4, 2]);n
|
|
127
|
+
[(1, 3), (2, 8), (4, 7), (5, 6)]
|
|
128
|
+
sage: n.parent()
|
|
129
|
+
Perfect matchings of {1, 2, 3, 4, 5, 6, 7, 8}
|
|
130
|
+
sage: PerfectMatching([(1, 4), (2, 3), (5, 6)]).is_noncrossing()
|
|
131
|
+
True
|
|
132
|
+
|
|
133
|
+
The function checks that the given list or permutation is
|
|
134
|
+
a valid perfect matching (i.e. a list of pairs with pairwise
|
|
135
|
+
disjoint elements or a fix point free involution) and raises
|
|
136
|
+
a :exc:`ValueError` otherwise::
|
|
137
|
+
|
|
138
|
+
sage: PerfectMatching([(1, 2, 3), (4, 5)])
|
|
139
|
+
Traceback (most recent call last):
|
|
140
|
+
...
|
|
141
|
+
ValueError: [(1, 2, 3), (4, 5)] is not an element of
|
|
142
|
+
Perfect matchings of {1, 2, 3, 4, 5}
|
|
143
|
+
|
|
144
|
+
TESTS::
|
|
145
|
+
|
|
146
|
+
sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')])
|
|
147
|
+
sage: TestSuite(m).run()
|
|
148
|
+
sage: m = PerfectMatching([])
|
|
149
|
+
sage: TestSuite(m).run()
|
|
150
|
+
sage: PerfectMatching(6)
|
|
151
|
+
Traceback (most recent call last):
|
|
152
|
+
...
|
|
153
|
+
TypeError: 'sage.rings.integer.Integer' object is not iterable
|
|
154
|
+
sage: PerfectMatching([(1,2,3)])
|
|
155
|
+
Traceback (most recent call last):
|
|
156
|
+
...
|
|
157
|
+
ValueError: [(1, 2, 3)] is not an element of
|
|
158
|
+
Perfect matchings of {1, 2, 3}
|
|
159
|
+
|
|
160
|
+
sage: PerfectMatching([(1,1)])
|
|
161
|
+
Traceback (most recent call last):
|
|
162
|
+
...
|
|
163
|
+
ValueError: [(1)] is not an element of Perfect matchings of {1}
|
|
164
|
+
|
|
165
|
+
sage: PerfectMatching(Permutation([4,2,1,3]))
|
|
166
|
+
Traceback (most recent call last):
|
|
167
|
+
...
|
|
168
|
+
ValueError: permutation p (= [4, 2, 1, 3]) is not a
|
|
169
|
+
fixed point free involution
|
|
170
|
+
"""
|
|
171
|
+
if ((isinstance(parts, list) and
|
|
172
|
+
all(isinstance(x, (int, Integer)) for x in parts))
|
|
173
|
+
or isinstance(parts, Permutation)):
|
|
174
|
+
s = Permutation(parts)
|
|
175
|
+
if not all(e == 2 for e in s.cycle_type()):
|
|
176
|
+
raise ValueError("permutation p (= {}) is not a "
|
|
177
|
+
"fixed point free involution".format(s))
|
|
178
|
+
parts = s.to_cycles()
|
|
179
|
+
|
|
180
|
+
base_set = frozenset(e for p in parts for e in p)
|
|
181
|
+
P = PerfectMatchings(base_set)
|
|
182
|
+
return P(parts)
|
|
183
|
+
|
|
184
|
+
def __init__(self, parent, s, check=True, sort=True):
|
|
185
|
+
"""
|
|
186
|
+
Initialize ``self``.
|
|
187
|
+
|
|
188
|
+
TESTS::
|
|
189
|
+
|
|
190
|
+
sage: PM = PerfectMatchings(6)
|
|
191
|
+
sage: x = PM.element_class(PM, [[5,6],[3,4],[1,2]])
|
|
192
|
+
|
|
193
|
+
Use the ``sort`` argument when you do not care if the result
|
|
194
|
+
is sorted. Be careful with its use as you can get inconsistent
|
|
195
|
+
results when then input is not sorted::
|
|
196
|
+
|
|
197
|
+
sage: y = PM.element_class(PM, [[5,6],[3,4],[1,2]], sort=False)
|
|
198
|
+
sage: y
|
|
199
|
+
[(5, 6), (3, 4), (1, 2)]
|
|
200
|
+
sage: x == y
|
|
201
|
+
False
|
|
202
|
+
"""
|
|
203
|
+
self._latex_options = {}
|
|
204
|
+
if sort:
|
|
205
|
+
data = sorted(map(frozenset, s), key=min)
|
|
206
|
+
else:
|
|
207
|
+
data = list(map(frozenset, s))
|
|
208
|
+
ClonableArray.__init__(self, parent, data, check=check)
|
|
209
|
+
|
|
210
|
+
def _repr_(self):
|
|
211
|
+
r"""
|
|
212
|
+
Return a string representation of the matching ``self``.
|
|
213
|
+
|
|
214
|
+
EXAMPLES::
|
|
215
|
+
|
|
216
|
+
sage: PerfectMatching([('a','e'), ('b','c'), ('d','f')])
|
|
217
|
+
[('a', 'e'), ('b', 'c'), ('d', 'f')]
|
|
218
|
+
sage: PerfectMatching([3,8,1,7,6,5,4,2])
|
|
219
|
+
[(1, 3), (2, 8), (4, 7), (5, 6)]
|
|
220
|
+
"""
|
|
221
|
+
return '[' + ', '.join('(' + repr(sorted(x))[1:-1] + ')' for x in self) + ']'
|
|
222
|
+
|
|
223
|
+
def _latex_(self):
|
|
224
|
+
r"""
|
|
225
|
+
A latex representation of ``self`` using the ``tikzpicture`` package.
|
|
226
|
+
|
|
227
|
+
EXAMPLES::
|
|
228
|
+
|
|
229
|
+
sage: P = PerfectMatching([(1,3),(2,5),(4,6)])
|
|
230
|
+
sage: latex(P) # random # needs sage.graphs sage.plot
|
|
231
|
+
\begin{tikzpicture}
|
|
232
|
+
...
|
|
233
|
+
\end{tikzpicture}
|
|
234
|
+
|
|
235
|
+
TESTS:
|
|
236
|
+
|
|
237
|
+
Above we added ``random`` since warnings might be displayed
|
|
238
|
+
once. The second time, there should be no warnings::
|
|
239
|
+
|
|
240
|
+
sage: print(P._latex_()) # needs sage.graphs sage.plot
|
|
241
|
+
\begin{tikzpicture}
|
|
242
|
+
...
|
|
243
|
+
\end{tikzpicture}
|
|
244
|
+
|
|
245
|
+
.. TODO::
|
|
246
|
+
|
|
247
|
+
This should probably call the latex method of
|
|
248
|
+
:class:`SetPartition` with appropriate defaults.
|
|
249
|
+
"""
|
|
250
|
+
G = self.to_graph()
|
|
251
|
+
G.set_pos(G.layout_circular())
|
|
252
|
+
G.set_latex_options(
|
|
253
|
+
vertex_size=0.4,
|
|
254
|
+
edge_thickness=0.04,
|
|
255
|
+
)
|
|
256
|
+
return G._latex_()
|
|
257
|
+
|
|
258
|
+
def standardization(self):
|
|
259
|
+
"""
|
|
260
|
+
Return the standardization of ``self``.
|
|
261
|
+
|
|
262
|
+
See :meth:`SetPartition.standardization` for details.
|
|
263
|
+
|
|
264
|
+
EXAMPLES::
|
|
265
|
+
|
|
266
|
+
sage: n = PerfectMatching([('c','b'),('d','f'),('e','a')])
|
|
267
|
+
sage: n.standardization()
|
|
268
|
+
[(1, 5), (2, 3), (4, 6)]
|
|
269
|
+
"""
|
|
270
|
+
P = PerfectMatchings(2 * len(self))
|
|
271
|
+
return P(SetPartition.standardization(self))
|
|
272
|
+
|
|
273
|
+
def partner(self, x):
|
|
274
|
+
r"""
|
|
275
|
+
Return the element in the same pair than ``x``
|
|
276
|
+
in the matching ``self``.
|
|
277
|
+
|
|
278
|
+
EXAMPLES::
|
|
279
|
+
|
|
280
|
+
sage: m = PerfectMatching([(-3, 1), (2, 4), (-2, 7)])
|
|
281
|
+
sage: m.partner(4)
|
|
282
|
+
2
|
|
283
|
+
sage: n = PerfectMatching([('c','b'),('d','f'),('e','a')])
|
|
284
|
+
sage: n.partner('c')
|
|
285
|
+
'b'
|
|
286
|
+
"""
|
|
287
|
+
for a, b in self:
|
|
288
|
+
if a == x:
|
|
289
|
+
return b
|
|
290
|
+
if b == x:
|
|
291
|
+
return a
|
|
292
|
+
raise ValueError("%s in not an element of the %s" % (x, self))
|
|
293
|
+
|
|
294
|
+
def loops_iterator(self, other=None):
|
|
295
|
+
r"""
|
|
296
|
+
Iterate through the loops of ``self``.
|
|
297
|
+
|
|
298
|
+
INPUT:
|
|
299
|
+
|
|
300
|
+
- ``other`` -- a perfect matching of the same set of ``self``
|
|
301
|
+
(if the second argument is empty, the method :meth:`an_element` is
|
|
302
|
+
called on the parent of the first)
|
|
303
|
+
|
|
304
|
+
OUTPUT:
|
|
305
|
+
|
|
306
|
+
If we draw the two perfect matchings simultaneously as edges of a
|
|
307
|
+
graph, the graph obtained is a union of cycles of even lengths.
|
|
308
|
+
The function returns an iterator for these cycles (each cycle is
|
|
309
|
+
given as a list).
|
|
310
|
+
|
|
311
|
+
EXAMPLES::
|
|
312
|
+
|
|
313
|
+
sage: o = PerfectMatching([(1, 7), (2, 4), (3, 8), (5, 6)])
|
|
314
|
+
sage: p = PerfectMatching([(1, 6), (2, 7), (3, 4), (5, 8)])
|
|
315
|
+
sage: it = o.loops_iterator(p)
|
|
316
|
+
sage: next(it)
|
|
317
|
+
[1, 7, 2, 4, 3, 8, 5, 6]
|
|
318
|
+
sage: next(it)
|
|
319
|
+
Traceback (most recent call last):
|
|
320
|
+
...
|
|
321
|
+
StopIteration
|
|
322
|
+
"""
|
|
323
|
+
if other is None:
|
|
324
|
+
other = self.parent().an_element()
|
|
325
|
+
elif self.parent() != other.parent():
|
|
326
|
+
raise ValueError("%s is not a matching of the ground set of %s" % (other, self))
|
|
327
|
+
remain = self.base_set().set()
|
|
328
|
+
while remain:
|
|
329
|
+
a = remain.pop()
|
|
330
|
+
b = self.partner(a)
|
|
331
|
+
remain.remove(b)
|
|
332
|
+
loop = [a, b]
|
|
333
|
+
c = other.partner(b)
|
|
334
|
+
while c != a:
|
|
335
|
+
b = self.partner(c)
|
|
336
|
+
remain.remove(c)
|
|
337
|
+
loop.append(c)
|
|
338
|
+
remain.remove(b)
|
|
339
|
+
loop.append(b)
|
|
340
|
+
c = other.partner(b)
|
|
341
|
+
yield loop
|
|
342
|
+
|
|
343
|
+
def loops(self, other=None):
|
|
344
|
+
r"""
|
|
345
|
+
Return the loops of ``self``.
|
|
346
|
+
|
|
347
|
+
INPUT:
|
|
348
|
+
|
|
349
|
+
- ``other`` -- a perfect matching of the same set of ``self``
|
|
350
|
+
(if the second argument is empty, the method :meth:`an_element` is
|
|
351
|
+
called on the parent of the first)
|
|
352
|
+
|
|
353
|
+
OUTPUT:
|
|
354
|
+
|
|
355
|
+
If we draw the two perfect matchings simultaneously as edges of a
|
|
356
|
+
graph, the graph obtained is a union of cycles of even lengths.
|
|
357
|
+
The function returns the list of these cycles (each cycle is given
|
|
358
|
+
as a list).
|
|
359
|
+
|
|
360
|
+
EXAMPLES::
|
|
361
|
+
|
|
362
|
+
sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')])
|
|
363
|
+
sage: n = PerfectMatching([('a','b'),('d','f'),('e','c')])
|
|
364
|
+
sage: loops = m.loops(n)
|
|
365
|
+
sage: loops # random
|
|
366
|
+
[['a', 'e', 'c', 'b'], ['d', 'f']]
|
|
367
|
+
|
|
368
|
+
sage: o = PerfectMatching([(1, 7), (2, 4), (3, 8), (5, 6)])
|
|
369
|
+
sage: p = PerfectMatching([(1, 6), (2, 7), (3, 4), (5, 8)])
|
|
370
|
+
sage: o.loops(p)
|
|
371
|
+
[[1, 7, 2, 4, 3, 8, 5, 6]]
|
|
372
|
+
|
|
373
|
+
TESTS:
|
|
374
|
+
|
|
375
|
+
Test whether the shorter element of ``loops`` is ``['d', 'f']``
|
|
376
|
+
and the longer element is the cycle ``['a', 'e', 'c', 'b']`` or
|
|
377
|
+
its reverse, or one of their cyclic permutations::
|
|
378
|
+
|
|
379
|
+
sage: loops = sorted(loops, key=len)
|
|
380
|
+
sage: sorted(loops[0])
|
|
381
|
+
['d', 'f']
|
|
382
|
+
sage: G = SymmetricGroup(4) # needs sage.groups
|
|
383
|
+
sage: g = G([(1,2,3,4)]) # needs sage.groups
|
|
384
|
+
sage: ((loops[1] in [permutation_action(g**i, ['a', 'e', 'c', 'b']) # needs sage.groups
|
|
385
|
+
....: for i in range(4)])
|
|
386
|
+
....: or (loops[1] in [permutation_action(g**i, ['a', 'b', 'c', 'e'])
|
|
387
|
+
....: for i in range(4)]))
|
|
388
|
+
True
|
|
389
|
+
"""
|
|
390
|
+
return list(self.loops_iterator(other))
|
|
391
|
+
|
|
392
|
+
def loop_type(self, other=None):
|
|
393
|
+
r"""
|
|
394
|
+
Return the loop type of ``self``.
|
|
395
|
+
|
|
396
|
+
INPUT:
|
|
397
|
+
|
|
398
|
+
- ``other`` -- a perfect matching of the same set of ``self``
|
|
399
|
+
(if the second argument is empty, the method :meth:`an_element` is
|
|
400
|
+
called on the parent of the first)
|
|
401
|
+
|
|
402
|
+
OUTPUT:
|
|
403
|
+
|
|
404
|
+
If we draw the two perfect matchings simultaneously as edges of a
|
|
405
|
+
graph, the graph obtained is a union of cycles of even
|
|
406
|
+
lengths. The function returns the ordered list of the semi-length
|
|
407
|
+
of these cycles (considered as a partition)
|
|
408
|
+
|
|
409
|
+
EXAMPLES::
|
|
410
|
+
|
|
411
|
+
sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')])
|
|
412
|
+
sage: n = PerfectMatching([('a','b'),('d','f'),('e','c')])
|
|
413
|
+
sage: m.loop_type(n)
|
|
414
|
+
[2, 1]
|
|
415
|
+
|
|
416
|
+
TESTS::
|
|
417
|
+
|
|
418
|
+
sage: m = PerfectMatching([]); m.loop_type()
|
|
419
|
+
[]
|
|
420
|
+
"""
|
|
421
|
+
return Partition(sorted((len(l) // 2
|
|
422
|
+
for l in self.loops_iterator(other)),
|
|
423
|
+
reverse=True))
|
|
424
|
+
|
|
425
|
+
def number_of_loops(self, other=None):
|
|
426
|
+
r"""
|
|
427
|
+
Return the number of loops of ``self``.
|
|
428
|
+
|
|
429
|
+
INPUT:
|
|
430
|
+
|
|
431
|
+
- ``other`` -- a perfect matching of the same set of ``self``
|
|
432
|
+
(if the second argument is empty, the method :meth:`an_element` is
|
|
433
|
+
called on the parent of the first)
|
|
434
|
+
|
|
435
|
+
OUTPUT:
|
|
436
|
+
|
|
437
|
+
If we draw the two perfect matchings simultaneously as edges of a
|
|
438
|
+
graph, the graph obtained is a union of cycles of even lengths.
|
|
439
|
+
The function returns their numbers.
|
|
440
|
+
|
|
441
|
+
EXAMPLES::
|
|
442
|
+
|
|
443
|
+
sage: m = PerfectMatching([('a','e'),('b','c'),('d','f')])
|
|
444
|
+
sage: n = PerfectMatching([('a','b'),('d','f'),('e','c')])
|
|
445
|
+
sage: m.number_of_loops(n)
|
|
446
|
+
2
|
|
447
|
+
"""
|
|
448
|
+
return Integer(len(list(self.loops_iterator(other))))
|
|
449
|
+
|
|
450
|
+
def Weingarten_function(self, d, other=None):
|
|
451
|
+
r"""
|
|
452
|
+
Return the Weingarten function of two pairings.
|
|
453
|
+
|
|
454
|
+
This function is the value of some integrals over the orthogonal
|
|
455
|
+
groups `O_N`. With the convention of [CM]_, the method returns
|
|
456
|
+
`Wg^{O(d)}(other,self)`.
|
|
457
|
+
|
|
458
|
+
EXAMPLES::
|
|
459
|
+
|
|
460
|
+
sage: var('N') # needs sage.symbolic
|
|
461
|
+
N
|
|
462
|
+
sage: m = PerfectMatching([(1,3),(2,4)])
|
|
463
|
+
sage: n = PerfectMatching([(1,2),(3,4)])
|
|
464
|
+
sage: factor(m.Weingarten_function(N, n)) # needs sage.symbolic
|
|
465
|
+
-1/((N + 2)*(N - 1)*N)
|
|
466
|
+
"""
|
|
467
|
+
if other is None:
|
|
468
|
+
other = self.parent().an_element()
|
|
469
|
+
W = self.parent().Weingarten_matrix(d)
|
|
470
|
+
return W[other.rank()][self.rank()]
|
|
471
|
+
|
|
472
|
+
def to_graph(self):
|
|
473
|
+
r"""
|
|
474
|
+
Return the graph corresponding to the perfect matching.
|
|
475
|
+
|
|
476
|
+
OUTPUT: the realization of ``self`` as a graph
|
|
477
|
+
|
|
478
|
+
EXAMPLES::
|
|
479
|
+
|
|
480
|
+
sage: PerfectMatching([[1,3], [4,2]]).to_graph().edges(sort=True, # needs sage.graphs
|
|
481
|
+
....: labels=False)
|
|
482
|
+
[(1, 3), (2, 4)]
|
|
483
|
+
sage: PerfectMatching([[1,4], [3,2]]).to_graph().edges(sort=True, # needs sage.graphs
|
|
484
|
+
....: labels=False)
|
|
485
|
+
[(1, 4), (2, 3)]
|
|
486
|
+
sage: PerfectMatching([]).to_graph().edges(sort=True, labels=False) # needs sage.graphs
|
|
487
|
+
[]
|
|
488
|
+
"""
|
|
489
|
+
from sage.graphs.graph import Graph
|
|
490
|
+
return Graph([list(p) for p in self], format='list_of_edges')
|
|
491
|
+
|
|
492
|
+
def to_noncrossing_set_partition(self):
|
|
493
|
+
r"""
|
|
494
|
+
Return the noncrossing set partition (on half as many elements)
|
|
495
|
+
corresponding to the perfect matching if the perfect matching is
|
|
496
|
+
noncrossing, and otherwise gives an error.
|
|
497
|
+
|
|
498
|
+
OUTPUT: the realization of ``self`` as a noncrossing set partition
|
|
499
|
+
|
|
500
|
+
EXAMPLES::
|
|
501
|
+
|
|
502
|
+
sage: PerfectMatching([[1,3], [4,2]]).to_noncrossing_set_partition()
|
|
503
|
+
Traceback (most recent call last):
|
|
504
|
+
...
|
|
505
|
+
ValueError: matching must be non-crossing
|
|
506
|
+
sage: PerfectMatching([[1,4], [3,2]]).to_noncrossing_set_partition()
|
|
507
|
+
{{1, 2}}
|
|
508
|
+
sage: PerfectMatching([]).to_noncrossing_set_partition()
|
|
509
|
+
{}
|
|
510
|
+
"""
|
|
511
|
+
if not self.is_noncrossing():
|
|
512
|
+
raise ValueError("matching must be non-crossing")
|
|
513
|
+
else:
|
|
514
|
+
perm = self.to_permutation()
|
|
515
|
+
perm2 = Permutation([perm[2 * i] // 2
|
|
516
|
+
for i in range(len(perm) // 2)])
|
|
517
|
+
return SetPartition(perm2.cycle_tuples())
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
class PerfectMatchings(SetPartitions_set):
|
|
521
|
+
r"""
|
|
522
|
+
Perfect matchings of a ground set.
|
|
523
|
+
|
|
524
|
+
INPUT:
|
|
525
|
+
|
|
526
|
+
- ``s`` -- an iterable of hashable objects or an integer
|
|
527
|
+
|
|
528
|
+
EXAMPLES:
|
|
529
|
+
|
|
530
|
+
If the argument ``s`` is an integer `n`, it will be transformed
|
|
531
|
+
into the set `\{1, \ldots, n\}`::
|
|
532
|
+
|
|
533
|
+
sage: M = PerfectMatchings(6); M
|
|
534
|
+
Perfect matchings of {1, 2, 3, 4, 5, 6}
|
|
535
|
+
sage: PerfectMatchings([-1, -3, 1, 2])
|
|
536
|
+
Perfect matchings of {1, 2, -3, -1}
|
|
537
|
+
|
|
538
|
+
One can ask for the list, the cardinality or an element of a set of
|
|
539
|
+
perfect matching::
|
|
540
|
+
|
|
541
|
+
sage: PerfectMatchings(4).list()
|
|
542
|
+
[[(1, 2), (3, 4)], [(1, 3), (2, 4)], [(1, 4), (2, 3)]]
|
|
543
|
+
sage: PerfectMatchings(8).cardinality()
|
|
544
|
+
105
|
|
545
|
+
sage: M = PerfectMatchings(('a', 'e', 'b', 'f', 'c', 'd'))
|
|
546
|
+
sage: x = M.an_element()
|
|
547
|
+
sage: x # random
|
|
548
|
+
[('a', 'c'), ('b', 'e'), ('d', 'f')]
|
|
549
|
+
sage: all(PerfectMatchings(i).an_element() in PerfectMatchings(i)
|
|
550
|
+
....: for i in range(2,11,2))
|
|
551
|
+
True
|
|
552
|
+
|
|
553
|
+
TESTS:
|
|
554
|
+
|
|
555
|
+
Test that ``x = M.an_element()`` is actually a perfect matching::
|
|
556
|
+
|
|
557
|
+
sage: set().union(*x) == M.base_set()
|
|
558
|
+
True
|
|
559
|
+
sage: sum([len(a) for a in x]) == M.base_set().cardinality()
|
|
560
|
+
True
|
|
561
|
+
|
|
562
|
+
sage: M = PerfectMatchings(6)
|
|
563
|
+
sage: TestSuite(M).run()
|
|
564
|
+
|
|
565
|
+
sage: M = PerfectMatchings([])
|
|
566
|
+
sage: M.list()
|
|
567
|
+
[[]]
|
|
568
|
+
sage: TestSuite(M).run()
|
|
569
|
+
|
|
570
|
+
sage: PerfectMatchings(0).list()
|
|
571
|
+
[[]]
|
|
572
|
+
|
|
573
|
+
sage: M = PerfectMatchings(5)
|
|
574
|
+
sage: M.list()
|
|
575
|
+
[]
|
|
576
|
+
sage: TestSuite(M).run()
|
|
577
|
+
|
|
578
|
+
::
|
|
579
|
+
|
|
580
|
+
sage: S = PerfectMatchings(4)
|
|
581
|
+
sage: elt = S([[1,3],[2,4]]); elt
|
|
582
|
+
[(1, 3), (2, 4)]
|
|
583
|
+
sage: S = PerfectMatchings([])
|
|
584
|
+
sage: S([])
|
|
585
|
+
[]
|
|
586
|
+
"""
|
|
587
|
+
@staticmethod
|
|
588
|
+
def __classcall_private__(cls, s):
|
|
589
|
+
"""
|
|
590
|
+
Normalize input to ensure a unique representation.
|
|
591
|
+
|
|
592
|
+
EXAMPLES::
|
|
593
|
+
|
|
594
|
+
sage: S = PerfectMatchings(4)
|
|
595
|
+
sage: T = PerfectMatchings([1,2,3,4])
|
|
596
|
+
sage: S is T
|
|
597
|
+
True
|
|
598
|
+
"""
|
|
599
|
+
if isinstance(s, (int, Integer)):
|
|
600
|
+
s = frozenset(range(1, s + 1))
|
|
601
|
+
else:
|
|
602
|
+
try:
|
|
603
|
+
if s.cardinality() == infinity:
|
|
604
|
+
raise ValueError("the set must be finite")
|
|
605
|
+
except AttributeError:
|
|
606
|
+
pass
|
|
607
|
+
s = frozenset(s)
|
|
608
|
+
return super().__classcall__(cls, s)
|
|
609
|
+
|
|
610
|
+
def _repr_(self):
|
|
611
|
+
"""
|
|
612
|
+
Return a description of ``self``.
|
|
613
|
+
|
|
614
|
+
TESTS::
|
|
615
|
+
|
|
616
|
+
sage: PerfectMatchings([-1, -3, 1, 2])
|
|
617
|
+
Perfect matchings of {1, 2, -3, -1}
|
|
618
|
+
"""
|
|
619
|
+
return "Perfect matchings of %s" % Set(self._set)
|
|
620
|
+
|
|
621
|
+
def __iter__(self):
|
|
622
|
+
"""
|
|
623
|
+
Iterate over ``self``.
|
|
624
|
+
|
|
625
|
+
EXAMPLES::
|
|
626
|
+
|
|
627
|
+
sage: PerfectMatchings(4).list()
|
|
628
|
+
[[(1, 2), (3, 4)], [(1, 3), (2, 4)], [(1, 4), (2, 3)]]
|
|
629
|
+
"""
|
|
630
|
+
s = list(self._set)
|
|
631
|
+
if len(s) % 2:
|
|
632
|
+
return
|
|
633
|
+
# The iterator from fixed-point-free involutions has the resulting
|
|
634
|
+
# list of pairs sorted by their minimal element.
|
|
635
|
+
for val in perfect_matchings_iterator(len(s) // 2):
|
|
636
|
+
yield self.element_class(self, ((s[a], s[b]) for a, b in val),
|
|
637
|
+
check=False, sort=False)
|
|
638
|
+
|
|
639
|
+
def __contains__(self, x):
|
|
640
|
+
"""
|
|
641
|
+
Test if ``x`` is an element of ``self``.
|
|
642
|
+
|
|
643
|
+
EXAMPLES::
|
|
644
|
+
|
|
645
|
+
sage: m = PerfectMatching([(1,2),(4,3)])
|
|
646
|
+
sage: m in PerfectMatchings(4)
|
|
647
|
+
True
|
|
648
|
+
sage: m in PerfectMatchings((0, 1, 2, 3))
|
|
649
|
+
False
|
|
650
|
+
sage: all(m in PerfectMatchings(6) for m in PerfectMatchings(6))
|
|
651
|
+
True
|
|
652
|
+
|
|
653
|
+
Note that the class of ``x`` does not need to be ``PerfectMatching``:
|
|
654
|
+
if the data defines a perfect matching of the good set, the function
|
|
655
|
+
returns ``True``::
|
|
656
|
+
|
|
657
|
+
sage: [(1, 4), (2, 3)] in PerfectMatchings(4)
|
|
658
|
+
True
|
|
659
|
+
sage: [(1, 3, 6), (2, 4), (5,)] in PerfectMatchings(6)
|
|
660
|
+
False
|
|
661
|
+
sage: [('a', 'b'), ('a', 'c')] in PerfectMatchings(
|
|
662
|
+
....: ('a', 'b', 'c', 'd'))
|
|
663
|
+
False
|
|
664
|
+
|
|
665
|
+
TESTS::
|
|
666
|
+
|
|
667
|
+
sage: SA = PerfectMatchings([1,2,3,7])
|
|
668
|
+
sage: Set([Set([1,2]),Set([3,7])]) in SA
|
|
669
|
+
True
|
|
670
|
+
sage: Set([Set([1,2]),Set([2,3])]) in SA
|
|
671
|
+
False
|
|
672
|
+
sage: Set([]) in SA
|
|
673
|
+
False
|
|
674
|
+
"""
|
|
675
|
+
if not all(len(p) == 2 for p in x):
|
|
676
|
+
return False
|
|
677
|
+
|
|
678
|
+
base_set = Set([e for p in x for e in p])
|
|
679
|
+
return len(base_set) == 2 * len(x) and base_set == Set(self._set)
|
|
680
|
+
|
|
681
|
+
def base_set(self):
|
|
682
|
+
"""
|
|
683
|
+
Return the base set of ``self``.
|
|
684
|
+
|
|
685
|
+
EXAMPLES::
|
|
686
|
+
|
|
687
|
+
sage: PerfectMatchings(3).base_set()
|
|
688
|
+
{1, 2, 3}
|
|
689
|
+
"""
|
|
690
|
+
return Set(self._set)
|
|
691
|
+
|
|
692
|
+
def base_set_cardinality(self):
|
|
693
|
+
"""
|
|
694
|
+
Return the cardinality of the base set of ``self``.
|
|
695
|
+
|
|
696
|
+
EXAMPLES::
|
|
697
|
+
|
|
698
|
+
sage: PerfectMatchings(3).base_set_cardinality()
|
|
699
|
+
3
|
|
700
|
+
"""
|
|
701
|
+
return len(self._set)
|
|
702
|
+
|
|
703
|
+
def cardinality(self):
|
|
704
|
+
"""
|
|
705
|
+
Return the cardinality of the set of perfect matchings ``self``.
|
|
706
|
+
|
|
707
|
+
This is `1*3*5*...*(2n-1)`, where `2n` is the size of the ground set.
|
|
708
|
+
|
|
709
|
+
EXAMPLES::
|
|
710
|
+
|
|
711
|
+
sage: PerfectMatchings(8).cardinality()
|
|
712
|
+
105
|
|
713
|
+
sage: PerfectMatchings([1,2,3,4]).cardinality()
|
|
714
|
+
3
|
|
715
|
+
sage: PerfectMatchings(3).cardinality()
|
|
716
|
+
0
|
|
717
|
+
sage: PerfectMatchings([]).cardinality()
|
|
718
|
+
1
|
|
719
|
+
"""
|
|
720
|
+
n = len(self._set)
|
|
721
|
+
if n % 2:
|
|
722
|
+
return Integer(0)
|
|
723
|
+
else:
|
|
724
|
+
return Integer(prod(range(1, n, 2)))
|
|
725
|
+
|
|
726
|
+
def random_element(self):
|
|
727
|
+
r"""
|
|
728
|
+
Return a random element of ``self``.
|
|
729
|
+
|
|
730
|
+
EXAMPLES::
|
|
731
|
+
|
|
732
|
+
sage: M = PerfectMatchings(('a', 'e', 'b', 'f', 'c', 'd'))
|
|
733
|
+
sage: x = M.random_element()
|
|
734
|
+
sage: x # random
|
|
735
|
+
[('a', 'b'), ('c', 'd'), ('e', 'f')]
|
|
736
|
+
|
|
737
|
+
TESTS::
|
|
738
|
+
|
|
739
|
+
sage: x in M
|
|
740
|
+
True
|
|
741
|
+
sage: p = PerfectMatchings(13).random_element()
|
|
742
|
+
Traceback (most recent call last):
|
|
743
|
+
...
|
|
744
|
+
ValueError: there is no perfect matching on an odd number of elements
|
|
745
|
+
"""
|
|
746
|
+
n = len(self._set)
|
|
747
|
+
|
|
748
|
+
if n % 2:
|
|
749
|
+
raise ValueError("there is no perfect matching on an odd number of elements")
|
|
750
|
+
|
|
751
|
+
k = n // 2
|
|
752
|
+
p = Permutations(n).random_element()
|
|
753
|
+
l = list(self._set)
|
|
754
|
+
return self.element_class(self, [(l[p[2 * i] - 1], l[p[2 * i + 1] - 1])
|
|
755
|
+
for i in range(k)],
|
|
756
|
+
check=False)
|
|
757
|
+
|
|
758
|
+
@cached_method
|
|
759
|
+
def Weingarten_matrix(self, N):
|
|
760
|
+
r"""
|
|
761
|
+
Return the Weingarten matrix corresponding to the set of
|
|
762
|
+
PerfectMatchings ``self``.
|
|
763
|
+
|
|
764
|
+
It is a useful theoretical tool to compute polynomial integrals
|
|
765
|
+
over the orthogonal group `O_N` (see [CM]_).
|
|
766
|
+
|
|
767
|
+
EXAMPLES::
|
|
768
|
+
|
|
769
|
+
sage: M = PerfectMatchings(4).Weingarten_matrix(var('N')) # needs sage.symbolic
|
|
770
|
+
sage: N*(N-1)*(N+2)*M.apply_map(factor) # needs sage.symbolic
|
|
771
|
+
[N + 1 -1 -1]
|
|
772
|
+
[ -1 N + 1 -1]
|
|
773
|
+
[ -1 -1 N + 1]
|
|
774
|
+
"""
|
|
775
|
+
G = matrix([[N**(p1.number_of_loops(p2)) for p1 in self]
|
|
776
|
+
for p2 in self])
|
|
777
|
+
return G**(-1)
|
|
778
|
+
|
|
779
|
+
Element = PerfectMatching
|