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,1998 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
# sage.doctest: needs sage.combinat sage.modules
|
|
3
|
+
r"""
|
|
4
|
+
Partition/diagram algebras
|
|
5
|
+
"""
|
|
6
|
+
# ****************************************************************************
|
|
7
|
+
# Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>,
|
|
8
|
+
#
|
|
9
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
10
|
+
#
|
|
11
|
+
# This code is distributed in the hope that it will be useful,
|
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
14
|
+
# General Public License for more details.
|
|
15
|
+
#
|
|
16
|
+
# The full text of the GPL is available at:
|
|
17
|
+
#
|
|
18
|
+
# https://www.gnu.org/licenses/
|
|
19
|
+
# ****************************************************************************
|
|
20
|
+
from sage.arith.misc import binomial, factorial, integer_ceil as ceil
|
|
21
|
+
from sage.categories.algebras_with_basis import AlgebrasWithBasis
|
|
22
|
+
from sage.combinat.combinat import catalan_number
|
|
23
|
+
from sage.combinat.free_module import CombinatorialFreeModule
|
|
24
|
+
from sage.combinat.permutation import Permutations
|
|
25
|
+
from sage.combinat.set_partition import SetPartition, SetPartitions, SetPartitions_set
|
|
26
|
+
from sage.combinat.subset import Subsets
|
|
27
|
+
from sage.misc.lazy_import import lazy_import
|
|
28
|
+
from sage.rings.integer_ring import ZZ
|
|
29
|
+
from sage.rings.rational_field import QQ
|
|
30
|
+
from sage.sets.set import Set, Set_generic
|
|
31
|
+
|
|
32
|
+
lazy_import('sage.graphs.graph', 'Graph')
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _int_or_half_int(k):
|
|
36
|
+
r"""
|
|
37
|
+
Check if ``k`` is an integer or half integer.
|
|
38
|
+
|
|
39
|
+
OUTPUT:
|
|
40
|
+
|
|
41
|
+
If ``k`` is not in `1/2 \ZZ`, then this raises a :exc:`ValueError`.
|
|
42
|
+
Otherwise, we return the pair:
|
|
43
|
+
|
|
44
|
+
- boolean; ``True`` if ``k`` is an integer and ``False`` if a half integer
|
|
45
|
+
- integer; the floor of ``k``
|
|
46
|
+
|
|
47
|
+
TESTS::
|
|
48
|
+
|
|
49
|
+
sage: from sage.combinat.partition_algebra import _int_or_half_int
|
|
50
|
+
sage: _int_or_half_int(2)
|
|
51
|
+
(True, 2)
|
|
52
|
+
sage: _int_or_half_int(3/2)
|
|
53
|
+
(False, 1)
|
|
54
|
+
sage: _int_or_half_int(1.5)
|
|
55
|
+
(False, 1)
|
|
56
|
+
sage: _int_or_half_int(2.)
|
|
57
|
+
(True, 2)
|
|
58
|
+
sage: _int_or_half_int(2.1)
|
|
59
|
+
Traceback (most recent call last):
|
|
60
|
+
...
|
|
61
|
+
ValueError: k must be an integer or an integer + 1/2
|
|
62
|
+
"""
|
|
63
|
+
if k in ZZ:
|
|
64
|
+
return True, ZZ(k)
|
|
65
|
+
# Try to see if it is a half integer
|
|
66
|
+
try:
|
|
67
|
+
k = QQ(k)
|
|
68
|
+
if k.denominator() == 2:
|
|
69
|
+
return False, k.floor()
|
|
70
|
+
except (ValueError, TypeError):
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
raise ValueError("k must be an integer or an integer + 1/2")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class SetPartitionsXkElement(SetPartition):
|
|
77
|
+
"""
|
|
78
|
+
An element for the classes of ``SetPartitionXk`` where ``X`` is some
|
|
79
|
+
letter.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
def check(self):
|
|
83
|
+
"""
|
|
84
|
+
Check to make sure this is a set partition.
|
|
85
|
+
|
|
86
|
+
EXAMPLES::
|
|
87
|
+
|
|
88
|
+
sage: A2p5 = SetPartitionsAk(2.5)
|
|
89
|
+
sage: x = A2p5.first(); x
|
|
90
|
+
{{-3, -2, -1, 1, 2, 3}}
|
|
91
|
+
sage: x.check()
|
|
92
|
+
sage: y = A2p5.next(x); y
|
|
93
|
+
{{-3, 3}, {-2, -1, 1, 2}}
|
|
94
|
+
sage: y.check()
|
|
95
|
+
"""
|
|
96
|
+
# Check to make sure each element of x is a set
|
|
97
|
+
for s in self:
|
|
98
|
+
assert isinstance(s, (set, frozenset, Set_generic))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
#######
|
|
102
|
+
# A_k #
|
|
103
|
+
#######
|
|
104
|
+
|
|
105
|
+
def SetPartitionsAk(k):
|
|
106
|
+
r"""
|
|
107
|
+
Return the combinatorial class of set partitions of type `A_k`.
|
|
108
|
+
|
|
109
|
+
EXAMPLES::
|
|
110
|
+
|
|
111
|
+
sage: A3 = SetPartitionsAk(3); A3
|
|
112
|
+
Set partitions of {1, ..., 3, -1, ..., -3}
|
|
113
|
+
|
|
114
|
+
sage: A3.first() #random
|
|
115
|
+
{{1, 2, 3, -1, -3, -2}}
|
|
116
|
+
sage: A3.last() #random
|
|
117
|
+
{{-1}, {-2}, {3}, {1}, {-3}, {2}}
|
|
118
|
+
sage: A3.random_element() #random # needs sage.symbolic
|
|
119
|
+
{{1, 3, -3, -1}, {2, -2}}
|
|
120
|
+
|
|
121
|
+
sage: A3.cardinality() # needs sage.libs.flint
|
|
122
|
+
203
|
|
123
|
+
|
|
124
|
+
sage: A2p5 = SetPartitionsAk(2.5); A2p5
|
|
125
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block
|
|
126
|
+
sage: A2p5.cardinality()
|
|
127
|
+
52
|
|
128
|
+
|
|
129
|
+
sage: A2p5.first() #random
|
|
130
|
+
{{1, 2, 3, -1, -3, -2}}
|
|
131
|
+
sage: A2p5.last() #random
|
|
132
|
+
{{-1}, {-2}, {2}, {3, -3}, {1}}
|
|
133
|
+
sage: A2p5.random_element() #random # needs sage.symbolic
|
|
134
|
+
{{-1}, {-2}, {3, -3}, {1, 2}}
|
|
135
|
+
"""
|
|
136
|
+
is_int, k = _int_or_half_int(k)
|
|
137
|
+
if not is_int:
|
|
138
|
+
return SetPartitionsAkhalf_k(k)
|
|
139
|
+
return SetPartitionsAk_k(k)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class SetPartitionsAk_k(SetPartitions_set):
|
|
143
|
+
def __init__(self, k):
|
|
144
|
+
"""
|
|
145
|
+
TESTS::
|
|
146
|
+
|
|
147
|
+
sage: A3 = SetPartitionsAk(3); A3
|
|
148
|
+
Set partitions of {1, ..., 3, -1, ..., -3}
|
|
149
|
+
sage: A3 == loads(dumps(A3))
|
|
150
|
+
True
|
|
151
|
+
"""
|
|
152
|
+
self.k = k
|
|
153
|
+
set_k = frozenset(list(range(1, k + 1)) +
|
|
154
|
+
[-x for x in range(1, k + 1)])
|
|
155
|
+
SetPartitions_set.__init__(self, set_k)
|
|
156
|
+
|
|
157
|
+
Element = SetPartitionsXkElement
|
|
158
|
+
|
|
159
|
+
def _repr_(self):
|
|
160
|
+
"""
|
|
161
|
+
TESTS::
|
|
162
|
+
|
|
163
|
+
sage: SetPartitionsAk(3)
|
|
164
|
+
Set partitions of {1, ..., 3, -1, ..., -3}
|
|
165
|
+
"""
|
|
166
|
+
return "Set partitions of {1, ..., %s, -1, ..., -%s}" % (self.k, self.k)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class SetPartitionsAkhalf_k(SetPartitions_set):
|
|
170
|
+
def __init__(self, k):
|
|
171
|
+
"""
|
|
172
|
+
TESTS::
|
|
173
|
+
|
|
174
|
+
sage: A2p5 = SetPartitionsAk(2.5); A2p5
|
|
175
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block
|
|
176
|
+
sage: A2p5 == loads(dumps(A2p5))
|
|
177
|
+
True
|
|
178
|
+
"""
|
|
179
|
+
self.k = k
|
|
180
|
+
set_k = frozenset(list(range(1, k + 2)) + [-x for x in range(1, k + 1)])
|
|
181
|
+
SetPartitions_set.__init__(self, set_k)
|
|
182
|
+
|
|
183
|
+
Element = SetPartitionsXkElement
|
|
184
|
+
|
|
185
|
+
def _repr_(self):
|
|
186
|
+
"""
|
|
187
|
+
TESTS::
|
|
188
|
+
|
|
189
|
+
sage: SetPartitionsAk(2.5)
|
|
190
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block
|
|
191
|
+
"""
|
|
192
|
+
s = self.k + 1
|
|
193
|
+
return "Set partitions of {1, ..., %s, -1, ..., -%s} with %s and -%s in the same block" % (s, s, s, s)
|
|
194
|
+
|
|
195
|
+
def __contains__(self, x):
|
|
196
|
+
"""
|
|
197
|
+
TESTS::
|
|
198
|
+
|
|
199
|
+
sage: A2p5 = SetPartitionsAk(2.5)
|
|
200
|
+
sage: all(sp in A2p5 for sp in A2p5)
|
|
201
|
+
True
|
|
202
|
+
sage: A3 = SetPartitionsAk(3)
|
|
203
|
+
sage: len([x for x in A3 if x in A2p5])
|
|
204
|
+
52
|
|
205
|
+
sage: A2p5.cardinality()
|
|
206
|
+
52
|
|
207
|
+
"""
|
|
208
|
+
if x not in SetPartitionsAk_k(self.k + 1):
|
|
209
|
+
return False
|
|
210
|
+
|
|
211
|
+
for part in x:
|
|
212
|
+
if self.k + 1 in part and -self.k - 1 not in part:
|
|
213
|
+
return False
|
|
214
|
+
|
|
215
|
+
return True
|
|
216
|
+
|
|
217
|
+
def __iter__(self):
|
|
218
|
+
"""
|
|
219
|
+
TESTS::
|
|
220
|
+
|
|
221
|
+
sage: SetPartitionsAk(1.5).list() #random
|
|
222
|
+
[{{1, 2, -2, -1}},
|
|
223
|
+
{{2, -2, -1}, {1}},
|
|
224
|
+
{{2, -2}, {1, -1}},
|
|
225
|
+
{{-1}, {1, 2, -2}},
|
|
226
|
+
{{-1}, {2, -2}, {1}}]
|
|
227
|
+
|
|
228
|
+
::
|
|
229
|
+
|
|
230
|
+
sage: ks = [ 1.5, 2.5, 3.5 ]
|
|
231
|
+
sage: aks = map(SetPartitionsAk, ks)
|
|
232
|
+
sage: all(ak.cardinality() == len(ak.list()) for ak in aks)
|
|
233
|
+
True
|
|
234
|
+
"""
|
|
235
|
+
kp = frozenset([-self.k - 1])
|
|
236
|
+
for sp in SetPartitions_set.__iter__(self):
|
|
237
|
+
res = []
|
|
238
|
+
for part in sp:
|
|
239
|
+
if self.k + 1 in part:
|
|
240
|
+
res.append(part.union(kp))
|
|
241
|
+
else:
|
|
242
|
+
res.append(part)
|
|
243
|
+
yield self.element_class(self, res)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
#######
|
|
247
|
+
# S_k #
|
|
248
|
+
#######
|
|
249
|
+
|
|
250
|
+
def SetPartitionsSk(k):
|
|
251
|
+
r"""
|
|
252
|
+
Return the combinatorial class of set partitions of type `S_k`.
|
|
253
|
+
|
|
254
|
+
There is a bijection between these set partitions and the
|
|
255
|
+
permutations of `1, \ldots, k`.
|
|
256
|
+
|
|
257
|
+
EXAMPLES::
|
|
258
|
+
|
|
259
|
+
sage: S3 = SetPartitionsSk(3); S3
|
|
260
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with propagating number 3
|
|
261
|
+
sage: S3.cardinality()
|
|
262
|
+
6
|
|
263
|
+
|
|
264
|
+
sage: S3.list() #random
|
|
265
|
+
[{{2, -2}, {3, -3}, {1, -1}},
|
|
266
|
+
{{1, -1}, {2, -3}, {3, -2}},
|
|
267
|
+
{{2, -1}, {3, -3}, {1, -2}},
|
|
268
|
+
{{1, -2}, {2, -3}, {3, -1}},
|
|
269
|
+
{{1, -3}, {2, -1}, {3, -2}},
|
|
270
|
+
{{1, -3}, {2, -2}, {3, -1}}]
|
|
271
|
+
sage: S3.first() #random
|
|
272
|
+
{{2, -2}, {3, -3}, {1, -1}}
|
|
273
|
+
sage: S3.last() #random
|
|
274
|
+
{{1, -3}, {2, -2}, {3, -1}}
|
|
275
|
+
sage: S3.random_element() #random # needs sage.symbolic
|
|
276
|
+
{{1, -3}, {2, -1}, {3, -2}}
|
|
277
|
+
|
|
278
|
+
sage: S3p5 = SetPartitionsSk(3.5); S3p5
|
|
279
|
+
Set partitions of {1, ..., 4, -1, ..., -4} with 4 and -4 in the same block and propagating number 4
|
|
280
|
+
sage: S3p5.cardinality()
|
|
281
|
+
6
|
|
282
|
+
|
|
283
|
+
sage: S3p5.list() #random
|
|
284
|
+
[{{2, -2}, {3, -3}, {1, -1}, {4, -4}},
|
|
285
|
+
{{2, -3}, {1, -1}, {4, -4}, {3, -2}},
|
|
286
|
+
{{2, -1}, {3, -3}, {1, -2}, {4, -4}},
|
|
287
|
+
{{2, -3}, {1, -2}, {4, -4}, {3, -1}},
|
|
288
|
+
{{1, -3}, {2, -1}, {4, -4}, {3, -2}},
|
|
289
|
+
{{1, -3}, {2, -2}, {4, -4}, {3, -1}}]
|
|
290
|
+
sage: S3p5.first() #random
|
|
291
|
+
{{2, -2}, {3, -3}, {1, -1}, {4, -4}}
|
|
292
|
+
sage: S3p5.last() #random
|
|
293
|
+
{{1, -3}, {2, -2}, {4, -4}, {3, -1}}
|
|
294
|
+
sage: S3p5.random_element() #random # needs sage.symbolic
|
|
295
|
+
{{1, -3}, {2, -2}, {4, -4}, {3, -1}}
|
|
296
|
+
"""
|
|
297
|
+
is_int, k = _int_or_half_int(k)
|
|
298
|
+
if not is_int:
|
|
299
|
+
return SetPartitionsSkhalf_k(k)
|
|
300
|
+
return SetPartitionsSk_k(k)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
class SetPartitionsSk_k(SetPartitionsAk_k):
|
|
304
|
+
def _repr_(self):
|
|
305
|
+
"""
|
|
306
|
+
TESTS::
|
|
307
|
+
|
|
308
|
+
sage: SetPartitionsSk(3)
|
|
309
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with propagating number 3
|
|
310
|
+
"""
|
|
311
|
+
return SetPartitionsAk_k._repr_(self) + " with propagating number %s" % self.k
|
|
312
|
+
|
|
313
|
+
def __contains__(self, x):
|
|
314
|
+
"""
|
|
315
|
+
TESTS::
|
|
316
|
+
|
|
317
|
+
sage: A3 = SetPartitionsAk(3)
|
|
318
|
+
sage: S3 = SetPartitionsSk(3)
|
|
319
|
+
sage: all(sp in S3 for sp in S3)
|
|
320
|
+
True
|
|
321
|
+
sage: S3.cardinality()
|
|
322
|
+
6
|
|
323
|
+
sage: len([x for x in A3 if x in S3])
|
|
324
|
+
6
|
|
325
|
+
"""
|
|
326
|
+
if not SetPartitionsAk_k.__contains__(self, x):
|
|
327
|
+
return False
|
|
328
|
+
|
|
329
|
+
if propagating_number(x) != self.k:
|
|
330
|
+
return False
|
|
331
|
+
|
|
332
|
+
return True
|
|
333
|
+
|
|
334
|
+
def cardinality(self):
|
|
335
|
+
"""
|
|
336
|
+
Return k!.
|
|
337
|
+
|
|
338
|
+
TESTS::
|
|
339
|
+
|
|
340
|
+
sage: SetPartitionsSk(2).cardinality()
|
|
341
|
+
2
|
|
342
|
+
sage: SetPartitionsSk(3).cardinality()
|
|
343
|
+
6
|
|
344
|
+
sage: SetPartitionsSk(4).cardinality()
|
|
345
|
+
24
|
|
346
|
+
sage: SetPartitionsSk(5).cardinality()
|
|
347
|
+
120
|
|
348
|
+
"""
|
|
349
|
+
return factorial(self.k)
|
|
350
|
+
|
|
351
|
+
def __iter__(self):
|
|
352
|
+
"""
|
|
353
|
+
TESTS::
|
|
354
|
+
|
|
355
|
+
sage: SetPartitionsSk(3).list() #random
|
|
356
|
+
[{{2, -2}, {3, -3}, {1, -1}},
|
|
357
|
+
{{1, -1}, {2, -3}, {3, -2}},
|
|
358
|
+
{{2, -1}, {3, -3}, {1, -2}},
|
|
359
|
+
{{1, -2}, {2, -3}, {3, -1}},
|
|
360
|
+
{{1, -3}, {2, -1}, {3, -2}},
|
|
361
|
+
{{1, -3}, {2, -2}, {3, -1}}]
|
|
362
|
+
sage: ks = list(range(1, 6))
|
|
363
|
+
sage: sks = map(SetPartitionsSk, ks)
|
|
364
|
+
sage: all(sk.cardinality() == len(sk.list()) for sk in sks)
|
|
365
|
+
True
|
|
366
|
+
"""
|
|
367
|
+
for p in Permutations(self.k):
|
|
368
|
+
res = [Set([i, -pi]) for i, pi in enumerate(p, start=1)]
|
|
369
|
+
yield self.element_class(self, res)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
class SetPartitionsSkhalf_k(SetPartitionsAkhalf_k):
|
|
373
|
+
def __contains__(self, x):
|
|
374
|
+
"""
|
|
375
|
+
TESTS::
|
|
376
|
+
|
|
377
|
+
sage: S2p5 = SetPartitionsSk(2.5)
|
|
378
|
+
sage: A3 = SetPartitionsAk(3)
|
|
379
|
+
sage: all(sp in S2p5 for sp in S2p5)
|
|
380
|
+
True
|
|
381
|
+
sage: len([x for x in A3 if x in S2p5])
|
|
382
|
+
2
|
|
383
|
+
sage: S2p5.cardinality()
|
|
384
|
+
2
|
|
385
|
+
"""
|
|
386
|
+
if not SetPartitionsAkhalf_k.__contains__(self, x):
|
|
387
|
+
return False
|
|
388
|
+
if propagating_number(x) != self.k + 1:
|
|
389
|
+
return False
|
|
390
|
+
return True
|
|
391
|
+
|
|
392
|
+
def _repr_(self):
|
|
393
|
+
"""
|
|
394
|
+
TESTS::
|
|
395
|
+
|
|
396
|
+
sage: SetPartitionsSk(2.5)
|
|
397
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and propagating number 3
|
|
398
|
+
"""
|
|
399
|
+
s = self.k + 1
|
|
400
|
+
return SetPartitionsAkhalf_k._repr_(self) + " and propagating number %s" % s
|
|
401
|
+
|
|
402
|
+
def cardinality(self):
|
|
403
|
+
"""
|
|
404
|
+
TESTS::
|
|
405
|
+
|
|
406
|
+
sage: SetPartitionsSk(2.5).cardinality()
|
|
407
|
+
2
|
|
408
|
+
sage: SetPartitionsSk(3.5).cardinality()
|
|
409
|
+
6
|
|
410
|
+
sage: SetPartitionsSk(4.5).cardinality()
|
|
411
|
+
24
|
|
412
|
+
|
|
413
|
+
::
|
|
414
|
+
|
|
415
|
+
sage: ks = [2.5, 3.5, 4.5, 5.5]
|
|
416
|
+
sage: sks = [SetPartitionsSk(k) for k in ks]
|
|
417
|
+
sage: all(sk.cardinality() == len(sk.list()) for sk in sks)
|
|
418
|
+
True
|
|
419
|
+
"""
|
|
420
|
+
return factorial(self.k)
|
|
421
|
+
|
|
422
|
+
def __iter__(self):
|
|
423
|
+
"""
|
|
424
|
+
TESTS::
|
|
425
|
+
|
|
426
|
+
sage: SetPartitionsSk(3.5).list() #random indirect test
|
|
427
|
+
[{{2, -2}, {3, -3}, {1, -1}, {4, -4}},
|
|
428
|
+
{{2, -3}, {1, -1}, {4, -4}, {3, -2}},
|
|
429
|
+
{{2, -1}, {3, -3}, {1, -2}, {4, -4}},
|
|
430
|
+
{{2, -3}, {1, -2}, {4, -4}, {3, -1}},
|
|
431
|
+
{{1, -3}, {2, -1}, {4, -4}, {3, -2}},
|
|
432
|
+
{{1, -3}, {2, -2}, {4, -4}, {3, -1}}]
|
|
433
|
+
"""
|
|
434
|
+
for p in Permutations(self.k):
|
|
435
|
+
res = [Set([i, -pi]) for i, pi in enumerate(p, start=1)]
|
|
436
|
+
res.append(Set([self.k + 1, -self.k - 1]))
|
|
437
|
+
yield self.element_class(self, res)
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
#######
|
|
441
|
+
# I_k #
|
|
442
|
+
#######
|
|
443
|
+
|
|
444
|
+
def SetPartitionsIk(k):
|
|
445
|
+
r"""
|
|
446
|
+
Return the combinatorial class of set partitions of type `I_k`.
|
|
447
|
+
|
|
448
|
+
These are set partitions with a propagating number of less than `k`.
|
|
449
|
+
Note that the identity set partition `\{\{1, -1\}, \ldots, \{k, -k\}\}`
|
|
450
|
+
is not in `I_k`.
|
|
451
|
+
|
|
452
|
+
EXAMPLES::
|
|
453
|
+
|
|
454
|
+
sage: I3 = SetPartitionsIk(3); I3
|
|
455
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with propagating number < 3
|
|
456
|
+
sage: I3.cardinality()
|
|
457
|
+
197
|
|
458
|
+
|
|
459
|
+
sage: I3.first() #random
|
|
460
|
+
{{1, 2, 3, -1, -3, -2}}
|
|
461
|
+
sage: I3.last() #random
|
|
462
|
+
{{-1}, {-2}, {3}, {1}, {-3}, {2}}
|
|
463
|
+
sage: I3.random_element() #random # needs sage.symbolic
|
|
464
|
+
{{-1}, {-3, -2}, {2, 3}, {1}}
|
|
465
|
+
|
|
466
|
+
sage: I2p5 = SetPartitionsIk(2.5); I2p5
|
|
467
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and propagating number < 3
|
|
468
|
+
sage: I2p5.cardinality()
|
|
469
|
+
50
|
|
470
|
+
|
|
471
|
+
sage: I2p5.first() #random
|
|
472
|
+
{{1, 2, 3, -1, -3, -2}}
|
|
473
|
+
sage: I2p5.last() #random
|
|
474
|
+
{{-1}, {-2}, {2}, {3, -3}, {1}}
|
|
475
|
+
sage: I2p5.random_element() #random # needs sage.symbolic
|
|
476
|
+
{{-1}, {-2}, {1, 3, -3}, {2}}
|
|
477
|
+
"""
|
|
478
|
+
is_int, k = _int_or_half_int(k)
|
|
479
|
+
if not is_int:
|
|
480
|
+
return SetPartitionsIkhalf_k(k)
|
|
481
|
+
return SetPartitionsIk_k(k)
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
class SetPartitionsIk_k(SetPartitionsAk_k):
|
|
485
|
+
def _repr_(self):
|
|
486
|
+
"""
|
|
487
|
+
TESTS::
|
|
488
|
+
|
|
489
|
+
sage: SetPartitionsIk(3)
|
|
490
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with propagating number < 3
|
|
491
|
+
"""
|
|
492
|
+
return SetPartitionsAk_k._repr_(self) + " with propagating number < %s" % self.k
|
|
493
|
+
|
|
494
|
+
def __contains__(self, x):
|
|
495
|
+
"""
|
|
496
|
+
TESTS::
|
|
497
|
+
|
|
498
|
+
sage: I3 = SetPartitionsIk(3)
|
|
499
|
+
sage: A3 = SetPartitionsAk(3)
|
|
500
|
+
sage: all(sp in I3 for sp in I3)
|
|
501
|
+
True
|
|
502
|
+
sage: len([x for x in A3 if x in I3])
|
|
503
|
+
197
|
|
504
|
+
sage: I3.cardinality()
|
|
505
|
+
197
|
|
506
|
+
"""
|
|
507
|
+
if not SetPartitionsAk_k.__contains__(self, x):
|
|
508
|
+
return False
|
|
509
|
+
if propagating_number(x) >= self.k:
|
|
510
|
+
return False
|
|
511
|
+
return True
|
|
512
|
+
|
|
513
|
+
def cardinality(self):
|
|
514
|
+
"""
|
|
515
|
+
TESTS::
|
|
516
|
+
|
|
517
|
+
sage: SetPartitionsIk(2).cardinality()
|
|
518
|
+
13
|
|
519
|
+
"""
|
|
520
|
+
return len(self.list())
|
|
521
|
+
|
|
522
|
+
def __iter__(self):
|
|
523
|
+
"""
|
|
524
|
+
TESTS::
|
|
525
|
+
|
|
526
|
+
sage: SetPartitionsIk(2).list() #random indirect test
|
|
527
|
+
[{{1, 2, -1, -2}},
|
|
528
|
+
{{2, -1, -2}, {1}},
|
|
529
|
+
{{2}, {1, -1, -2}},
|
|
530
|
+
{{-1}, {1, 2, -2}},
|
|
531
|
+
{{-2}, {1, 2, -1}},
|
|
532
|
+
{{1, 2}, {-1, -2}},
|
|
533
|
+
{{2}, {-1, -2}, {1}},
|
|
534
|
+
{{-1}, {2, -2}, {1}},
|
|
535
|
+
{{-2}, {2, -1}, {1}},
|
|
536
|
+
{{-1}, {2}, {1, -2}},
|
|
537
|
+
{{-2}, {2}, {1, -1}},
|
|
538
|
+
{{-1}, {-2}, {1, 2}},
|
|
539
|
+
{{-1}, {-2}, {2}, {1}}]
|
|
540
|
+
"""
|
|
541
|
+
for sp in SetPartitionsAk_k.__iter__(self):
|
|
542
|
+
if propagating_number(sp) < self.k:
|
|
543
|
+
yield sp
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
class SetPartitionsIkhalf_k(SetPartitionsAkhalf_k):
|
|
547
|
+
def __contains__(self, x):
|
|
548
|
+
"""
|
|
549
|
+
TESTS::
|
|
550
|
+
|
|
551
|
+
sage: I2p5 = SetPartitionsIk(2.5)
|
|
552
|
+
sage: A3 = SetPartitionsAk(3)
|
|
553
|
+
sage: all(sp in I2p5 for sp in I2p5)
|
|
554
|
+
True
|
|
555
|
+
sage: len([x for x in A3 if x in I2p5])
|
|
556
|
+
50
|
|
557
|
+
sage: I2p5.cardinality()
|
|
558
|
+
50
|
|
559
|
+
"""
|
|
560
|
+
if not SetPartitionsAkhalf_k.__contains__(self, x):
|
|
561
|
+
return False
|
|
562
|
+
if propagating_number(x) >= self.k + 1:
|
|
563
|
+
return False
|
|
564
|
+
return True
|
|
565
|
+
|
|
566
|
+
def _repr_(self):
|
|
567
|
+
"""
|
|
568
|
+
TESTS::
|
|
569
|
+
|
|
570
|
+
sage: SetPartitionsIk(2.5)
|
|
571
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and propagating number < 3
|
|
572
|
+
"""
|
|
573
|
+
return SetPartitionsAkhalf_k._repr_(self) + " and propagating number < %s" % (self.k + 1)
|
|
574
|
+
|
|
575
|
+
def cardinality(self):
|
|
576
|
+
"""
|
|
577
|
+
TESTS::
|
|
578
|
+
|
|
579
|
+
sage: SetPartitionsIk(1.5).cardinality()
|
|
580
|
+
4
|
|
581
|
+
sage: SetPartitionsIk(2.5).cardinality()
|
|
582
|
+
50
|
|
583
|
+
sage: SetPartitionsIk(3.5).cardinality()
|
|
584
|
+
871
|
|
585
|
+
"""
|
|
586
|
+
return len(self.list())
|
|
587
|
+
|
|
588
|
+
def __iter__(self):
|
|
589
|
+
"""
|
|
590
|
+
TESTS::
|
|
591
|
+
|
|
592
|
+
sage: SetPartitionsIk(1.5).list() #random
|
|
593
|
+
[{{1, 2, -2, -1}},
|
|
594
|
+
{{2, -2, -1}, {1}},
|
|
595
|
+
{{-1}, {1, 2, -2}},
|
|
596
|
+
{{-1}, {2, -2}, {1}}]
|
|
597
|
+
"""
|
|
598
|
+
|
|
599
|
+
for sp in SetPartitionsAkhalf_k.__iter__(self):
|
|
600
|
+
if propagating_number(sp) < self.k + 1:
|
|
601
|
+
yield sp
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
#######
|
|
605
|
+
# B_k #
|
|
606
|
+
#######
|
|
607
|
+
|
|
608
|
+
def SetPartitionsBk(k):
|
|
609
|
+
r"""
|
|
610
|
+
Return the combinatorial class of set partitions of type `B_k`.
|
|
611
|
+
|
|
612
|
+
These are the set partitions where every block has size 2.
|
|
613
|
+
|
|
614
|
+
EXAMPLES::
|
|
615
|
+
|
|
616
|
+
sage: B3 = SetPartitionsBk(3); B3
|
|
617
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with block size 2
|
|
618
|
+
|
|
619
|
+
sage: # needs sage.graphs
|
|
620
|
+
sage: B3.first() #random
|
|
621
|
+
{{2, -2}, {1, -3}, {3, -1}}
|
|
622
|
+
sage: B3.last() #random
|
|
623
|
+
{{1, 2}, {3, -2}, {-3, -1}}
|
|
624
|
+
sage: B3.random_element() #random # needs sage.symbolic
|
|
625
|
+
{{2, -1}, {1, -3}, {3, -2}}
|
|
626
|
+
|
|
627
|
+
sage: B3.cardinality()
|
|
628
|
+
15
|
|
629
|
+
|
|
630
|
+
sage: B2p5 = SetPartitionsBk(2.5); B2p5
|
|
631
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with block size 2
|
|
632
|
+
|
|
633
|
+
sage: # needs sage.graphs
|
|
634
|
+
sage: B2p5.first() #random
|
|
635
|
+
{{2, -1}, {3, -3}, {1, -2}}
|
|
636
|
+
sage: B2p5.last() #random
|
|
637
|
+
{{1, 2}, {3, -3}, {-1, -2}}
|
|
638
|
+
sage: B2p5.random_element() #random # needs sage.symbolic
|
|
639
|
+
{{2, -2}, {3, -3}, {1, -1}}
|
|
640
|
+
|
|
641
|
+
sage: B2p5.cardinality()
|
|
642
|
+
3
|
|
643
|
+
"""
|
|
644
|
+
is_int, k = _int_or_half_int(k)
|
|
645
|
+
if not is_int:
|
|
646
|
+
return SetPartitionsBkhalf_k(k)
|
|
647
|
+
return SetPartitionsBk_k(k)
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
class SetPartitionsBk_k(SetPartitionsAk_k):
|
|
651
|
+
def _repr_(self):
|
|
652
|
+
"""
|
|
653
|
+
TESTS::
|
|
654
|
+
|
|
655
|
+
sage: SetPartitionsBk(2.5)
|
|
656
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with block size 2
|
|
657
|
+
"""
|
|
658
|
+
return SetPartitionsAk_k._repr_(self) + " with block size 2"
|
|
659
|
+
|
|
660
|
+
def __contains__(self, x):
|
|
661
|
+
"""
|
|
662
|
+
TESTS::
|
|
663
|
+
|
|
664
|
+
sage: B3 = SetPartitionsBk(3)
|
|
665
|
+
sage: A3 = SetPartitionsAk(3)
|
|
666
|
+
sage: len([x for x in A3 if x in B3])
|
|
667
|
+
15
|
|
668
|
+
sage: B3.cardinality()
|
|
669
|
+
15
|
|
670
|
+
"""
|
|
671
|
+
if not SetPartitionsAk_k.__contains__(self, x):
|
|
672
|
+
return False
|
|
673
|
+
|
|
674
|
+
for part in x:
|
|
675
|
+
if len(part) != 2:
|
|
676
|
+
return False
|
|
677
|
+
|
|
678
|
+
return True
|
|
679
|
+
|
|
680
|
+
def cardinality(self):
|
|
681
|
+
r"""
|
|
682
|
+
Return the number of set partitions in `B_k` where `k` is an integer.
|
|
683
|
+
|
|
684
|
+
This is given by (2k)!! = (2k-1)\*(2k-3)\*...\*5\*3\*1.
|
|
685
|
+
|
|
686
|
+
EXAMPLES::
|
|
687
|
+
|
|
688
|
+
sage: SetPartitionsBk(3).cardinality()
|
|
689
|
+
15
|
|
690
|
+
sage: SetPartitionsBk(2).cardinality()
|
|
691
|
+
3
|
|
692
|
+
sage: SetPartitionsBk(1).cardinality()
|
|
693
|
+
1
|
|
694
|
+
sage: SetPartitionsBk(4).cardinality()
|
|
695
|
+
105
|
|
696
|
+
sage: SetPartitionsBk(5).cardinality()
|
|
697
|
+
945
|
|
698
|
+
"""
|
|
699
|
+
c = 1
|
|
700
|
+
for i in range(1, 2 * self.k, 2):
|
|
701
|
+
c *= i
|
|
702
|
+
return c
|
|
703
|
+
|
|
704
|
+
def __iter__(self):
|
|
705
|
+
"""
|
|
706
|
+
TESTS::
|
|
707
|
+
|
|
708
|
+
sage: SetPartitionsBk(1).list() # needs sage.graphs
|
|
709
|
+
[{{-1, 1}}]
|
|
710
|
+
|
|
711
|
+
::
|
|
712
|
+
|
|
713
|
+
sage: SetPartitionsBk(2).list() #random # needs sage.graphs
|
|
714
|
+
[{{2, -1}, {1, -2}}, {{2, -2}, {1, -1}}, {{1, 2}, {-1, -2}}]
|
|
715
|
+
sage: SetPartitionsBk(3).list() #random # needs sage.graphs
|
|
716
|
+
[{{2, -2}, {1, -3}, {3, -1}},
|
|
717
|
+
{{2, -1}, {1, -3}, {3, -2}},
|
|
718
|
+
{{1, -3}, {2, 3}, {-1, -2}},
|
|
719
|
+
{{3, -1}, {1, -2}, {2, -3}},
|
|
720
|
+
{{3, -2}, {1, -1}, {2, -3}},
|
|
721
|
+
{{1, 3}, {2, -3}, {-1, -2}},
|
|
722
|
+
{{2, -1}, {3, -3}, {1, -2}},
|
|
723
|
+
{{2, -2}, {3, -3}, {1, -1}},
|
|
724
|
+
{{1, 2}, {3, -3}, {-1, -2}},
|
|
725
|
+
{{-3, -2}, {2, 3}, {1, -1}},
|
|
726
|
+
{{1, 3}, {-3, -2}, {2, -1}},
|
|
727
|
+
{{1, 2}, {3, -1}, {-3, -2}},
|
|
728
|
+
{{-3, -1}, {2, 3}, {1, -2}},
|
|
729
|
+
{{1, 3}, {-3, -1}, {2, -2}},
|
|
730
|
+
{{1, 2}, {3, -2}, {-3, -1}}]
|
|
731
|
+
|
|
732
|
+
Check to make sure that the number of elements generated is the
|
|
733
|
+
same as what is given by cardinality()
|
|
734
|
+
|
|
735
|
+
::
|
|
736
|
+
|
|
737
|
+
sage: bks = [SetPartitionsBk(i) for i in range(1, 6)]
|
|
738
|
+
sage: all(bk.cardinality() == len(bk.list()) for bk in bks) # needs sage.graphs
|
|
739
|
+
True
|
|
740
|
+
"""
|
|
741
|
+
for sp in SetPartitions(self._set, [2] * (len(self._set) // 2)):
|
|
742
|
+
yield self.element_class(self, sp)
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
class SetPartitionsBkhalf_k(SetPartitionsAkhalf_k):
|
|
746
|
+
def _repr_(self):
|
|
747
|
+
"""
|
|
748
|
+
TESTS::
|
|
749
|
+
|
|
750
|
+
sage: SetPartitionsBk(2.5)
|
|
751
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with block size 2
|
|
752
|
+
"""
|
|
753
|
+
return SetPartitionsAkhalf_k._repr_(self) + " and with block size 2"
|
|
754
|
+
|
|
755
|
+
def __contains__(self, x):
|
|
756
|
+
"""
|
|
757
|
+
TESTS::
|
|
758
|
+
|
|
759
|
+
sage: A3 = SetPartitionsAk(3)
|
|
760
|
+
sage: B2p5 = SetPartitionsBk(2.5)
|
|
761
|
+
sage: all(sp in B2p5 for sp in B2p5)
|
|
762
|
+
True
|
|
763
|
+
sage: len([x for x in A3 if x in B2p5])
|
|
764
|
+
3
|
|
765
|
+
sage: B2p5.cardinality()
|
|
766
|
+
3
|
|
767
|
+
"""
|
|
768
|
+
if not SetPartitionsAkhalf_k.__contains__(self, x):
|
|
769
|
+
return False
|
|
770
|
+
for part in x:
|
|
771
|
+
if len(part) != 2:
|
|
772
|
+
return False
|
|
773
|
+
return True
|
|
774
|
+
|
|
775
|
+
def cardinality(self):
|
|
776
|
+
"""
|
|
777
|
+
TESTS::
|
|
778
|
+
|
|
779
|
+
sage: B3p5 = SetPartitionsBk(3.5)
|
|
780
|
+
sage: B3p5.cardinality()
|
|
781
|
+
15
|
|
782
|
+
"""
|
|
783
|
+
return len(self.list())
|
|
784
|
+
|
|
785
|
+
def __iter__(self):
|
|
786
|
+
"""
|
|
787
|
+
TESTS::
|
|
788
|
+
|
|
789
|
+
sage: B3p5 = SetPartitionsBk(3.5)
|
|
790
|
+
sage: B3p5.cardinality()
|
|
791
|
+
15
|
|
792
|
+
|
|
793
|
+
::
|
|
794
|
+
|
|
795
|
+
sage: B3p5.list() #random
|
|
796
|
+
[{{2, -2}, {1, -3}, {4, -4}, {3, -1}},
|
|
797
|
+
{{2, -1}, {1, -3}, {4, -4}, {3, -2}},
|
|
798
|
+
{{1, -3}, {2, 3}, {4, -4}, {-1, -2}},
|
|
799
|
+
{{2, -3}, {1, -2}, {4, -4}, {3, -1}},
|
|
800
|
+
{{2, -3}, {1, -1}, {4, -4}, {3, -2}},
|
|
801
|
+
{{1, 3}, {4, -4}, {2, -3}, {-1, -2}},
|
|
802
|
+
{{2, -1}, {3, -3}, {1, -2}, {4, -4}},
|
|
803
|
+
{{2, -2}, {3, -3}, {1, -1}, {4, -4}},
|
|
804
|
+
{{1, 2}, {3, -3}, {4, -4}, {-1, -2}},
|
|
805
|
+
{{-3, -2}, {2, 3}, {1, -1}, {4, -4}},
|
|
806
|
+
{{1, 3}, {-3, -2}, {2, -1}, {4, -4}},
|
|
807
|
+
{{1, 2}, {-3, -2}, {4, -4}, {3, -1}},
|
|
808
|
+
{{-3, -1}, {2, 3}, {1, -2}, {4, -4}},
|
|
809
|
+
{{1, 3}, {-3, -1}, {2, -2}, {4, -4}},
|
|
810
|
+
{{1, 2}, {-3, -1}, {4, -4}, {3, -2}}]
|
|
811
|
+
"""
|
|
812
|
+
set = list(range(1, self.k + 1)) + [-x for x in range(1, self.k + 1)]
|
|
813
|
+
for sp in SetPartitions(set, [2] * (len(set) // 2)):
|
|
814
|
+
yield self.element_class(self, Set(list(sp)) + Set([Set([self.k + 1, -self.k - 1])]))
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
#######
|
|
818
|
+
# P_k #
|
|
819
|
+
#######
|
|
820
|
+
|
|
821
|
+
def SetPartitionsPk(k):
|
|
822
|
+
r"""
|
|
823
|
+
Return the combinatorial class of set partitions of type `P_k`.
|
|
824
|
+
|
|
825
|
+
These are the planar set partitions.
|
|
826
|
+
|
|
827
|
+
EXAMPLES::
|
|
828
|
+
|
|
829
|
+
sage: P3 = SetPartitionsPk(3); P3
|
|
830
|
+
Set partitions of {1, ..., 3, -1, ..., -3} that are planar
|
|
831
|
+
sage: P3.cardinality()
|
|
832
|
+
132
|
|
833
|
+
|
|
834
|
+
sage: P3.first() #random
|
|
835
|
+
{{1, 2, 3, -1, -3, -2}}
|
|
836
|
+
sage: P3.last() #random
|
|
837
|
+
{{-1}, {-2}, {3}, {1}, {-3}, {2}}
|
|
838
|
+
sage: P3.random_element() #random # needs sage.symbolic
|
|
839
|
+
{{1, 2, -1}, {-3}, {3, -2}}
|
|
840
|
+
|
|
841
|
+
sage: P2p5 = SetPartitionsPk(2.5); P2p5
|
|
842
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and that are planar
|
|
843
|
+
sage: P2p5.cardinality()
|
|
844
|
+
42
|
|
845
|
+
|
|
846
|
+
sage: P2p5.first() #random
|
|
847
|
+
{{1, 2, 3, -1, -3, -2}}
|
|
848
|
+
sage: P2p5.last() #random
|
|
849
|
+
{{-1}, {-2}, {2}, {3, -3}, {1}}
|
|
850
|
+
sage: P2p5.random_element() #random # needs sage.symbolic
|
|
851
|
+
{{1, 2, 3, -3}, {-1, -2}}
|
|
852
|
+
"""
|
|
853
|
+
is_int, k = _int_or_half_int(k)
|
|
854
|
+
if not is_int:
|
|
855
|
+
return SetPartitionsPkhalf_k(k)
|
|
856
|
+
return SetPartitionsPk_k(k)
|
|
857
|
+
|
|
858
|
+
|
|
859
|
+
class SetPartitionsPk_k(SetPartitionsAk_k):
|
|
860
|
+
def _repr_(self):
|
|
861
|
+
"""
|
|
862
|
+
TESTS::
|
|
863
|
+
|
|
864
|
+
sage: SetPartitionsPk(3)
|
|
865
|
+
Set partitions of {1, ..., 3, -1, ..., -3} that are planar
|
|
866
|
+
"""
|
|
867
|
+
return SetPartitionsAk_k._repr_(self) + " that are planar"
|
|
868
|
+
|
|
869
|
+
def __contains__(self, x):
|
|
870
|
+
"""
|
|
871
|
+
TESTS::
|
|
872
|
+
|
|
873
|
+
sage: P3 = SetPartitionsPk(3)
|
|
874
|
+
sage: A3 = SetPartitionsAk(3)
|
|
875
|
+
sage: len([x for x in A3 if x in P3])
|
|
876
|
+
132
|
|
877
|
+
sage: P3.cardinality()
|
|
878
|
+
132
|
|
879
|
+
sage: all(sp in P3 for sp in P3)
|
|
880
|
+
True
|
|
881
|
+
"""
|
|
882
|
+
if not SetPartitionsAk_k.__contains__(self, x):
|
|
883
|
+
return False
|
|
884
|
+
|
|
885
|
+
if not is_planar(x):
|
|
886
|
+
return False
|
|
887
|
+
|
|
888
|
+
return True
|
|
889
|
+
|
|
890
|
+
def cardinality(self):
|
|
891
|
+
"""
|
|
892
|
+
TESTS::
|
|
893
|
+
|
|
894
|
+
sage: SetPartitionsPk(2).cardinality()
|
|
895
|
+
14
|
|
896
|
+
sage: SetPartitionsPk(3).cardinality()
|
|
897
|
+
132
|
|
898
|
+
sage: SetPartitionsPk(4).cardinality()
|
|
899
|
+
1430
|
|
900
|
+
"""
|
|
901
|
+
return catalan_number(2 * self.k)
|
|
902
|
+
|
|
903
|
+
def __iter__(self):
|
|
904
|
+
"""
|
|
905
|
+
TESTS::
|
|
906
|
+
|
|
907
|
+
sage: SetPartitionsPk(2).list() #random indirect test
|
|
908
|
+
[{{1, 2, -1, -2}},
|
|
909
|
+
{{2, -1, -2}, {1}},
|
|
910
|
+
{{2}, {1, -1, -2}},
|
|
911
|
+
{{-1}, {1, 2, -2}},
|
|
912
|
+
{{-2}, {1, 2, -1}},
|
|
913
|
+
{{2, -2}, {1, -1}},
|
|
914
|
+
{{1, 2}, {-1, -2}},
|
|
915
|
+
{{2}, {-1, -2}, {1}},
|
|
916
|
+
{{-1}, {2, -2}, {1}},
|
|
917
|
+
{{-2}, {2, -1}, {1}},
|
|
918
|
+
{{-1}, {2}, {1, -2}},
|
|
919
|
+
{{-2}, {2}, {1, -1}},
|
|
920
|
+
{{-1}, {-2}, {1, 2}},
|
|
921
|
+
{{-1}, {-2}, {2}, {1}}]
|
|
922
|
+
"""
|
|
923
|
+
for sp in SetPartitionsAk_k.__iter__(self):
|
|
924
|
+
if is_planar(sp):
|
|
925
|
+
yield self.element_class(self, sp)
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
class SetPartitionsPkhalf_k(SetPartitionsAkhalf_k):
|
|
929
|
+
def __contains__(self, x):
|
|
930
|
+
"""
|
|
931
|
+
TESTS::
|
|
932
|
+
|
|
933
|
+
sage: A3 = SetPartitionsAk(3)
|
|
934
|
+
sage: P2p5 = SetPartitionsPk(2.5)
|
|
935
|
+
sage: all(sp in P2p5 for sp in P2p5)
|
|
936
|
+
True
|
|
937
|
+
sage: len([x for x in A3 if x in P2p5])
|
|
938
|
+
42
|
|
939
|
+
sage: P2p5.cardinality()
|
|
940
|
+
42
|
|
941
|
+
"""
|
|
942
|
+
if not SetPartitionsAkhalf_k.__contains__(self, x):
|
|
943
|
+
return False
|
|
944
|
+
if not is_planar(x):
|
|
945
|
+
return False
|
|
946
|
+
|
|
947
|
+
return True
|
|
948
|
+
|
|
949
|
+
def _repr_(self):
|
|
950
|
+
"""
|
|
951
|
+
TESTS::
|
|
952
|
+
|
|
953
|
+
sage: repr( SetPartitionsPk(2.5) )
|
|
954
|
+
'Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and that are planar'
|
|
955
|
+
"""
|
|
956
|
+
return SetPartitionsAkhalf_k._repr_(self) + " and that are planar"
|
|
957
|
+
|
|
958
|
+
def cardinality(self):
|
|
959
|
+
"""
|
|
960
|
+
TESTS::
|
|
961
|
+
|
|
962
|
+
sage: SetPartitionsPk(2.5).cardinality()
|
|
963
|
+
42
|
|
964
|
+
sage: SetPartitionsPk(1.5).cardinality()
|
|
965
|
+
5
|
|
966
|
+
"""
|
|
967
|
+
return len(self.list())
|
|
968
|
+
|
|
969
|
+
def __iter__(self):
|
|
970
|
+
"""
|
|
971
|
+
TESTS::
|
|
972
|
+
|
|
973
|
+
sage: SetPartitionsPk(1.5).list() #random
|
|
974
|
+
[{{1, 2, -2, -1}},
|
|
975
|
+
{{2, -2, -1}, {1}},
|
|
976
|
+
{{2, -2}, {1, -1}},
|
|
977
|
+
{{-1}, {1, 2, -2}},
|
|
978
|
+
{{-1}, {2, -2}, {1}}]
|
|
979
|
+
"""
|
|
980
|
+
for sp in SetPartitionsAkhalf_k.__iter__(self):
|
|
981
|
+
if is_planar(sp):
|
|
982
|
+
yield self.element_class(self, sp)
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
#######
|
|
986
|
+
# T_k #
|
|
987
|
+
#######
|
|
988
|
+
|
|
989
|
+
def SetPartitionsTk(k):
|
|
990
|
+
r"""
|
|
991
|
+
Return the combinatorial class of set partitions of type `T_k`.
|
|
992
|
+
|
|
993
|
+
These are planar set partitions where every block is of size 2.
|
|
994
|
+
|
|
995
|
+
EXAMPLES::
|
|
996
|
+
|
|
997
|
+
sage: T3 = SetPartitionsTk(3); T3
|
|
998
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with block size 2 and that are planar
|
|
999
|
+
sage: T3.cardinality()
|
|
1000
|
+
5
|
|
1001
|
+
|
|
1002
|
+
sage: # needs sage.graphs
|
|
1003
|
+
sage: T3.first() # random
|
|
1004
|
+
{{1, -3}, {2, 3}, {-1, -2}}
|
|
1005
|
+
sage: T3.last() # random
|
|
1006
|
+
{{1, 2}, {3, -1}, {-3, -2}}
|
|
1007
|
+
sage: T3.random_element() # random # needs sage.symbolic
|
|
1008
|
+
{{1, -3}, {2, 3}, {-1, -2}}
|
|
1009
|
+
|
|
1010
|
+
sage: T2p5 = SetPartitionsTk(2.5); T2p5
|
|
1011
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with block size 2 and that are planar
|
|
1012
|
+
sage: T2p5.cardinality()
|
|
1013
|
+
2
|
|
1014
|
+
|
|
1015
|
+
sage: # needs sage.graphs
|
|
1016
|
+
sage: T2p5.first() # random
|
|
1017
|
+
{{2, -2}, {3, -3}, {1, -1}}
|
|
1018
|
+
sage: T2p5.last() # random
|
|
1019
|
+
{{1, 2}, {3, -3}, {-1, -2}}
|
|
1020
|
+
"""
|
|
1021
|
+
is_int, k = _int_or_half_int(k)
|
|
1022
|
+
if not is_int:
|
|
1023
|
+
return SetPartitionsTkhalf_k(k)
|
|
1024
|
+
return SetPartitionsTk_k(k)
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
class SetPartitionsTk_k(SetPartitionsBk_k):
|
|
1028
|
+
def _repr_(self):
|
|
1029
|
+
"""
|
|
1030
|
+
TESTS::
|
|
1031
|
+
|
|
1032
|
+
sage: SetPartitionsTk(3)
|
|
1033
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with block size 2 and that are planar
|
|
1034
|
+
"""
|
|
1035
|
+
return SetPartitionsBk_k._repr_(self) + " and that are planar"
|
|
1036
|
+
|
|
1037
|
+
def __contains__(self, x):
|
|
1038
|
+
"""
|
|
1039
|
+
TESTS::
|
|
1040
|
+
|
|
1041
|
+
sage: # needs sage.graphs
|
|
1042
|
+
sage: T3 = SetPartitionsTk(3)
|
|
1043
|
+
sage: A3 = SetPartitionsAk(3)
|
|
1044
|
+
sage: all(sp in T3 for sp in T3)
|
|
1045
|
+
True
|
|
1046
|
+
sage: len([x for x in A3 if x in T3])
|
|
1047
|
+
5
|
|
1048
|
+
sage: T3.cardinality()
|
|
1049
|
+
5
|
|
1050
|
+
"""
|
|
1051
|
+
if not SetPartitionsBk_k.__contains__(self, x):
|
|
1052
|
+
return False
|
|
1053
|
+
|
|
1054
|
+
if not is_planar(x):
|
|
1055
|
+
return False
|
|
1056
|
+
|
|
1057
|
+
return True
|
|
1058
|
+
|
|
1059
|
+
def cardinality(self):
|
|
1060
|
+
"""
|
|
1061
|
+
TESTS::
|
|
1062
|
+
|
|
1063
|
+
sage: SetPartitionsTk(2).cardinality()
|
|
1064
|
+
2
|
|
1065
|
+
sage: SetPartitionsTk(3).cardinality()
|
|
1066
|
+
5
|
|
1067
|
+
sage: SetPartitionsTk(4).cardinality()
|
|
1068
|
+
14
|
|
1069
|
+
sage: SetPartitionsTk(5).cardinality()
|
|
1070
|
+
42
|
|
1071
|
+
"""
|
|
1072
|
+
return catalan_number(self.k)
|
|
1073
|
+
|
|
1074
|
+
def __iter__(self):
|
|
1075
|
+
"""
|
|
1076
|
+
TESTS::
|
|
1077
|
+
|
|
1078
|
+
sage: # needs sage.graphs
|
|
1079
|
+
sage: SetPartitionsTk(3).list() # random
|
|
1080
|
+
[{{1, -3}, {2, 3}, {-1, -2}},
|
|
1081
|
+
{{2, -2}, {3, -3}, {1, -1}},
|
|
1082
|
+
{{1, 2}, {3, -3}, {-1, -2}},
|
|
1083
|
+
{{-3, -2}, {2, 3}, {1, -1}},
|
|
1084
|
+
{{1, 2}, {3, -1}, {-3, -2}}]
|
|
1085
|
+
"""
|
|
1086
|
+
for sp in SetPartitionsBk_k.__iter__(self):
|
|
1087
|
+
if is_planar(sp):
|
|
1088
|
+
yield self.element_class(self, sp)
|
|
1089
|
+
|
|
1090
|
+
|
|
1091
|
+
class SetPartitionsTkhalf_k(SetPartitionsBkhalf_k):
|
|
1092
|
+
def __contains__(self, x):
|
|
1093
|
+
"""
|
|
1094
|
+
TESTS::
|
|
1095
|
+
|
|
1096
|
+
sage: A3 = SetPartitionsAk(3)
|
|
1097
|
+
sage: T2p5 = SetPartitionsTk(2.5)
|
|
1098
|
+
sage: all(sp in T2p5 for sp in T2p5)
|
|
1099
|
+
True
|
|
1100
|
+
sage: len([x for x in A3 if x in T2p5])
|
|
1101
|
+
2
|
|
1102
|
+
sage: T2p5.cardinality()
|
|
1103
|
+
2
|
|
1104
|
+
"""
|
|
1105
|
+
if not SetPartitionsBkhalf_k.__contains__(self, x):
|
|
1106
|
+
return False
|
|
1107
|
+
if not is_planar(x):
|
|
1108
|
+
return False
|
|
1109
|
+
|
|
1110
|
+
return True
|
|
1111
|
+
|
|
1112
|
+
def _repr_(self):
|
|
1113
|
+
"""
|
|
1114
|
+
TESTS::
|
|
1115
|
+
|
|
1116
|
+
sage: SetPartitionsTk(2.5)
|
|
1117
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with block size 2 and that are planar
|
|
1118
|
+
"""
|
|
1119
|
+
return SetPartitionsBkhalf_k._repr_(self) + " and that are planar"
|
|
1120
|
+
|
|
1121
|
+
def cardinality(self):
|
|
1122
|
+
"""
|
|
1123
|
+
TESTS::
|
|
1124
|
+
|
|
1125
|
+
sage: SetPartitionsTk(2.5).cardinality()
|
|
1126
|
+
2
|
|
1127
|
+
sage: SetPartitionsTk(3.5).cardinality()
|
|
1128
|
+
5
|
|
1129
|
+
sage: SetPartitionsTk(4.5).cardinality()
|
|
1130
|
+
14
|
|
1131
|
+
"""
|
|
1132
|
+
return catalan_number(self.k)
|
|
1133
|
+
|
|
1134
|
+
def __iter__(self):
|
|
1135
|
+
"""
|
|
1136
|
+
TESTS::
|
|
1137
|
+
|
|
1138
|
+
sage: SetPartitionsTk(3.5).list() #random
|
|
1139
|
+
[{{1, -3}, {2, 3}, {4, -4}, {-1, -2}},
|
|
1140
|
+
{{2, -2}, {3, -3}, {1, -1}, {4, -4}},
|
|
1141
|
+
{{1, 2}, {3, -3}, {4, -4}, {-1, -2}},
|
|
1142
|
+
{{-3, -2}, {2, 3}, {1, -1}, {4, -4}},
|
|
1143
|
+
{{1, 2}, {-3, -2}, {4, -4}, {3, -1}}]
|
|
1144
|
+
"""
|
|
1145
|
+
for sp in SetPartitionsBkhalf_k.__iter__(self):
|
|
1146
|
+
if is_planar(sp):
|
|
1147
|
+
yield self.element_class(self, sp)
|
|
1148
|
+
|
|
1149
|
+
|
|
1150
|
+
def SetPartitionsRk(k):
|
|
1151
|
+
r"""
|
|
1152
|
+
Return the combinatorial class of set partitions of type `R_k`.
|
|
1153
|
+
|
|
1154
|
+
EXAMPLES::
|
|
1155
|
+
|
|
1156
|
+
sage: SetPartitionsRk(3)
|
|
1157
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with at most 1 positive
|
|
1158
|
+
and negative entry in each block
|
|
1159
|
+
"""
|
|
1160
|
+
is_int, k = _int_or_half_int(k)
|
|
1161
|
+
if not is_int:
|
|
1162
|
+
return SetPartitionsRkhalf_k(k)
|
|
1163
|
+
return SetPartitionsRk_k(k)
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
class SetPartitionsRk_k(SetPartitionsAk_k):
|
|
1167
|
+
def __init__(self, k):
|
|
1168
|
+
"""
|
|
1169
|
+
TESTS::
|
|
1170
|
+
|
|
1171
|
+
sage: R3 = SetPartitionsRk(3); R3
|
|
1172
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with at most 1 positive and negative entry in each block
|
|
1173
|
+
sage: R3 == loads(dumps(R3))
|
|
1174
|
+
True
|
|
1175
|
+
"""
|
|
1176
|
+
self.k = k
|
|
1177
|
+
SetPartitionsAk_k.__init__(self, k)
|
|
1178
|
+
|
|
1179
|
+
def _repr_(self):
|
|
1180
|
+
"""
|
|
1181
|
+
TESTS::
|
|
1182
|
+
|
|
1183
|
+
sage: SetPartitionsRk(3)
|
|
1184
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with at most 1 positive and negative entry in each block
|
|
1185
|
+
"""
|
|
1186
|
+
return SetPartitionsAk_k._repr_(self) + " with at most 1 positive and negative entry in each block"
|
|
1187
|
+
|
|
1188
|
+
def __contains__(self, x):
|
|
1189
|
+
"""
|
|
1190
|
+
TESTS::
|
|
1191
|
+
|
|
1192
|
+
sage: R3 = SetPartitionsRk(3)
|
|
1193
|
+
sage: A3 = SetPartitionsAk(3)
|
|
1194
|
+
sage: all(sp in R3 for sp in R3)
|
|
1195
|
+
True
|
|
1196
|
+
sage: len([x for x in A3 if x in R3])
|
|
1197
|
+
34
|
|
1198
|
+
sage: R3.cardinality()
|
|
1199
|
+
34
|
|
1200
|
+
"""
|
|
1201
|
+
if not SetPartitionsAk_k.__contains__(self, x):
|
|
1202
|
+
return False
|
|
1203
|
+
|
|
1204
|
+
for block in x:
|
|
1205
|
+
if len(block) > 2:
|
|
1206
|
+
return False
|
|
1207
|
+
|
|
1208
|
+
negatives = 0
|
|
1209
|
+
positives = 0
|
|
1210
|
+
for i in block:
|
|
1211
|
+
if i < 0:
|
|
1212
|
+
negatives += 1
|
|
1213
|
+
else:
|
|
1214
|
+
positives += 1
|
|
1215
|
+
|
|
1216
|
+
if negatives > 1 or positives > 1:
|
|
1217
|
+
return False
|
|
1218
|
+
|
|
1219
|
+
return True
|
|
1220
|
+
|
|
1221
|
+
def cardinality(self):
|
|
1222
|
+
"""
|
|
1223
|
+
TESTS::
|
|
1224
|
+
|
|
1225
|
+
sage: SetPartitionsRk(2).cardinality()
|
|
1226
|
+
7
|
|
1227
|
+
sage: SetPartitionsRk(3).cardinality()
|
|
1228
|
+
34
|
|
1229
|
+
sage: SetPartitionsRk(4).cardinality()
|
|
1230
|
+
209
|
|
1231
|
+
sage: SetPartitionsRk(5).cardinality()
|
|
1232
|
+
1546
|
|
1233
|
+
"""
|
|
1234
|
+
return sum(binomial(self.k, l)**2 * factorial(l)
|
|
1235
|
+
for l in range(self.k + 1))
|
|
1236
|
+
|
|
1237
|
+
def __iter__(self):
|
|
1238
|
+
"""
|
|
1239
|
+
TESTS::
|
|
1240
|
+
|
|
1241
|
+
sage: len(SetPartitionsRk(3).list() ) == SetPartitionsRk(3).cardinality()
|
|
1242
|
+
True
|
|
1243
|
+
"""
|
|
1244
|
+
# The number of blocks with at most two things
|
|
1245
|
+
positives = Set(range(1, self.k + 1))
|
|
1246
|
+
negatives = Set(-i for i in positives)
|
|
1247
|
+
|
|
1248
|
+
yield self.element_class(self, to_set_partition([], self.k))
|
|
1249
|
+
for n in range(1, self.k + 1):
|
|
1250
|
+
for top in Subsets(positives, n):
|
|
1251
|
+
t = list(top)
|
|
1252
|
+
for bottom in Subsets(negatives, n):
|
|
1253
|
+
b = list(bottom)
|
|
1254
|
+
for permutation in Permutations(n):
|
|
1255
|
+
l = [[t[i], b[permutation[i] - 1]] for i in range(n)]
|
|
1256
|
+
yield self.element_class(self, to_set_partition(l, k=self.k))
|
|
1257
|
+
|
|
1258
|
+
|
|
1259
|
+
class SetPartitionsRkhalf_k(SetPartitionsAkhalf_k):
|
|
1260
|
+
def __contains__(self, x):
|
|
1261
|
+
"""
|
|
1262
|
+
TESTS::
|
|
1263
|
+
|
|
1264
|
+
sage: A3 = SetPartitionsAk(3)
|
|
1265
|
+
sage: R2p5 = SetPartitionsRk(2.5)
|
|
1266
|
+
sage: all(sp in R2p5 for sp in R2p5)
|
|
1267
|
+
True
|
|
1268
|
+
sage: len([x for x in A3 if x in R2p5])
|
|
1269
|
+
7
|
|
1270
|
+
sage: R2p5.cardinality()
|
|
1271
|
+
7
|
|
1272
|
+
"""
|
|
1273
|
+
if not SetPartitionsAkhalf_k.__contains__(self, x):
|
|
1274
|
+
return False
|
|
1275
|
+
|
|
1276
|
+
for block in x:
|
|
1277
|
+
if len(block) > 2:
|
|
1278
|
+
return False
|
|
1279
|
+
|
|
1280
|
+
negatives = 0
|
|
1281
|
+
positives = 0
|
|
1282
|
+
for i in block:
|
|
1283
|
+
if i < 0:
|
|
1284
|
+
negatives += 1
|
|
1285
|
+
else:
|
|
1286
|
+
positives += 1
|
|
1287
|
+
|
|
1288
|
+
if negatives > 1 or positives > 1:
|
|
1289
|
+
return False
|
|
1290
|
+
|
|
1291
|
+
return True
|
|
1292
|
+
|
|
1293
|
+
def _repr_(self):
|
|
1294
|
+
"""
|
|
1295
|
+
TESTS::
|
|
1296
|
+
|
|
1297
|
+
sage: SetPartitionsRk(2.5)
|
|
1298
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with at most 1 positive and negative entry in each block
|
|
1299
|
+
"""
|
|
1300
|
+
return SetPartitionsAkhalf_k._repr_(self) + " and with at most 1 positive and negative entry in each block"
|
|
1301
|
+
|
|
1302
|
+
def cardinality(self):
|
|
1303
|
+
"""
|
|
1304
|
+
TESTS::
|
|
1305
|
+
|
|
1306
|
+
sage: SetPartitionsRk(2.5).cardinality()
|
|
1307
|
+
7
|
|
1308
|
+
sage: SetPartitionsRk(3.5).cardinality()
|
|
1309
|
+
34
|
|
1310
|
+
sage: SetPartitionsRk(4.5).cardinality()
|
|
1311
|
+
209
|
|
1312
|
+
"""
|
|
1313
|
+
return sum(binomial(self.k, l)**2 * factorial(l)
|
|
1314
|
+
for l in range(self.k + 1))
|
|
1315
|
+
|
|
1316
|
+
def __iter__(self):
|
|
1317
|
+
"""
|
|
1318
|
+
TESTS::
|
|
1319
|
+
|
|
1320
|
+
sage: R2p5 = SetPartitionsRk(2.5)
|
|
1321
|
+
sage: L = list(R2p5); L #random due to sets
|
|
1322
|
+
[{{-2}, {-1}, {3, -3}, {2}, {1}},
|
|
1323
|
+
{{-2}, {3, -3}, {2}, {1, -1}},
|
|
1324
|
+
{{-1}, {3, -3}, {2}, {1, -2}},
|
|
1325
|
+
{{-2}, {2, -1}, {3, -3}, {1}},
|
|
1326
|
+
{{-1}, {2, -2}, {3, -3}, {1}},
|
|
1327
|
+
{{2, -2}, {3, -3}, {1, -1}},
|
|
1328
|
+
{{2, -1}, {3, -3}, {1, -2}}]
|
|
1329
|
+
sage: len(L)
|
|
1330
|
+
7
|
|
1331
|
+
"""
|
|
1332
|
+
positives = Set(range(1, self.k + 1))
|
|
1333
|
+
negatives = Set(-i for i in positives)
|
|
1334
|
+
|
|
1335
|
+
yield self.element_class(self, to_set_partition([[self.k + 1, -self.k - 1]], self.k + 1))
|
|
1336
|
+
for n in range(1, self.k + 1):
|
|
1337
|
+
for top in Subsets(positives, n):
|
|
1338
|
+
t = list(top)
|
|
1339
|
+
for bottom in Subsets(negatives, n):
|
|
1340
|
+
b = list(bottom)
|
|
1341
|
+
for permutation in Permutations(n):
|
|
1342
|
+
l = [[t[i], b[permutation[i] - 1]] for i in range(n)] + [[self.k + 1, -self.k - 1]]
|
|
1343
|
+
yield self.element_class(self, to_set_partition(l, k=self.k + 1))
|
|
1344
|
+
|
|
1345
|
+
|
|
1346
|
+
def SetPartitionsPRk(k):
|
|
1347
|
+
r"""
|
|
1348
|
+
Return the combinatorial class of set partitions of type `PR_k`.
|
|
1349
|
+
|
|
1350
|
+
EXAMPLES::
|
|
1351
|
+
|
|
1352
|
+
sage: SetPartitionsPRk(3)
|
|
1353
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with at most 1 positive
|
|
1354
|
+
and negative entry in each block and that are planar
|
|
1355
|
+
"""
|
|
1356
|
+
is_int, k = _int_or_half_int(k)
|
|
1357
|
+
if not is_int:
|
|
1358
|
+
return SetPartitionsPRkhalf_k(k)
|
|
1359
|
+
return SetPartitionsPRk_k(k)
|
|
1360
|
+
|
|
1361
|
+
|
|
1362
|
+
class SetPartitionsPRk_k(SetPartitionsRk_k):
|
|
1363
|
+
def __init__(self, k):
|
|
1364
|
+
"""
|
|
1365
|
+
TESTS::
|
|
1366
|
+
|
|
1367
|
+
sage: PR3 = SetPartitionsPRk(3); PR3
|
|
1368
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with at most 1 positive and negative entry in each block and that are planar
|
|
1369
|
+
sage: PR3 == loads(dumps(PR3))
|
|
1370
|
+
True
|
|
1371
|
+
"""
|
|
1372
|
+
self.k = k
|
|
1373
|
+
SetPartitionsRk_k.__init__(self, k)
|
|
1374
|
+
|
|
1375
|
+
def _repr_(self):
|
|
1376
|
+
"""
|
|
1377
|
+
TESTS::
|
|
1378
|
+
|
|
1379
|
+
sage: SetPartitionsPRk(3)
|
|
1380
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with at most 1 positive and negative entry in each block and that are planar
|
|
1381
|
+
"""
|
|
1382
|
+
return SetPartitionsRk_k._repr_(self) + " and that are planar"
|
|
1383
|
+
|
|
1384
|
+
def __contains__(self, x):
|
|
1385
|
+
"""
|
|
1386
|
+
TESTS::
|
|
1387
|
+
|
|
1388
|
+
sage: PR3 = SetPartitionsPRk(3)
|
|
1389
|
+
sage: A3 = SetPartitionsAk(3)
|
|
1390
|
+
sage: all(sp in PR3 for sp in PR3)
|
|
1391
|
+
True
|
|
1392
|
+
sage: len([x for x in A3 if x in PR3])
|
|
1393
|
+
20
|
|
1394
|
+
sage: PR3.cardinality()
|
|
1395
|
+
20
|
|
1396
|
+
"""
|
|
1397
|
+
if not SetPartitionsRk_k.__contains__(self, x):
|
|
1398
|
+
return False
|
|
1399
|
+
|
|
1400
|
+
if not is_planar(x):
|
|
1401
|
+
return False
|
|
1402
|
+
|
|
1403
|
+
return True
|
|
1404
|
+
|
|
1405
|
+
def cardinality(self):
|
|
1406
|
+
"""
|
|
1407
|
+
TESTS::
|
|
1408
|
+
|
|
1409
|
+
sage: SetPartitionsPRk(2).cardinality()
|
|
1410
|
+
6
|
|
1411
|
+
sage: SetPartitionsPRk(3).cardinality()
|
|
1412
|
+
20
|
|
1413
|
+
sage: SetPartitionsPRk(4).cardinality()
|
|
1414
|
+
70
|
|
1415
|
+
sage: SetPartitionsPRk(5).cardinality()
|
|
1416
|
+
252
|
|
1417
|
+
"""
|
|
1418
|
+
return binomial(2 * self.k, self.k)
|
|
1419
|
+
|
|
1420
|
+
def __iter__(self):
|
|
1421
|
+
"""
|
|
1422
|
+
TESTS::
|
|
1423
|
+
|
|
1424
|
+
sage: len(SetPartitionsPRk(3).list() ) == SetPartitionsPRk(3).cardinality()
|
|
1425
|
+
True
|
|
1426
|
+
"""
|
|
1427
|
+
# The number of blocks with at most two things
|
|
1428
|
+
positives = Set(range(1, self.k + 1))
|
|
1429
|
+
negatives = Set(-i for i in positives)
|
|
1430
|
+
|
|
1431
|
+
yield self.element_class(self, to_set_partition([], self.k))
|
|
1432
|
+
for n in range(1, self.k + 1):
|
|
1433
|
+
for top in Subsets(positives, n):
|
|
1434
|
+
t = sorted(top)
|
|
1435
|
+
for bottom in Subsets(negatives, n):
|
|
1436
|
+
b = list(bottom)
|
|
1437
|
+
b.sort(reverse=True)
|
|
1438
|
+
l = [[t[i], b[i]] for i in range(n)]
|
|
1439
|
+
yield self.element_class(self, to_set_partition(l, k=self.k))
|
|
1440
|
+
|
|
1441
|
+
|
|
1442
|
+
class SetPartitionsPRkhalf_k(SetPartitionsRkhalf_k):
|
|
1443
|
+
def __contains__(self, x):
|
|
1444
|
+
"""
|
|
1445
|
+
TESTS::
|
|
1446
|
+
|
|
1447
|
+
sage: A3 = SetPartitionsAk(3)
|
|
1448
|
+
sage: PR2p5 = SetPartitionsPRk(2.5)
|
|
1449
|
+
sage: all(sp in PR2p5 for sp in PR2p5)
|
|
1450
|
+
True
|
|
1451
|
+
sage: len([x for x in A3 if x in PR2p5])
|
|
1452
|
+
6
|
|
1453
|
+
sage: PR2p5.cardinality()
|
|
1454
|
+
6
|
|
1455
|
+
"""
|
|
1456
|
+
if not SetPartitionsRkhalf_k.__contains__(self, x):
|
|
1457
|
+
return False
|
|
1458
|
+
|
|
1459
|
+
if not is_planar(x):
|
|
1460
|
+
return False
|
|
1461
|
+
|
|
1462
|
+
return True
|
|
1463
|
+
|
|
1464
|
+
def _repr_(self):
|
|
1465
|
+
"""
|
|
1466
|
+
TESTS::
|
|
1467
|
+
|
|
1468
|
+
sage: SetPartitionsPRk(2.5)
|
|
1469
|
+
Set partitions of {1, ..., 3, -1, ..., -3} with 3 and -3 in the same block and with at most 1 positive and negative entry in each block and that are planar
|
|
1470
|
+
"""
|
|
1471
|
+
return SetPartitionsRkhalf_k._repr_(self) + " and that are planar"
|
|
1472
|
+
|
|
1473
|
+
def cardinality(self):
|
|
1474
|
+
"""
|
|
1475
|
+
TESTS::
|
|
1476
|
+
|
|
1477
|
+
sage: SetPartitionsPRk(2.5).cardinality()
|
|
1478
|
+
6
|
|
1479
|
+
sage: SetPartitionsPRk(3.5).cardinality()
|
|
1480
|
+
20
|
|
1481
|
+
sage: SetPartitionsPRk(4.5).cardinality()
|
|
1482
|
+
70
|
|
1483
|
+
"""
|
|
1484
|
+
return binomial(2 * self.k, self.k)
|
|
1485
|
+
|
|
1486
|
+
def __iter__(self):
|
|
1487
|
+
"""
|
|
1488
|
+
TESTS::
|
|
1489
|
+
|
|
1490
|
+
sage: next(iter(SetPartitionsPRk(2.5)))
|
|
1491
|
+
{{-3, 3}, {-2}, {-1}, {1}, {2}}
|
|
1492
|
+
sage: len(list(SetPartitionsPRk(2.5)))
|
|
1493
|
+
6
|
|
1494
|
+
"""
|
|
1495
|
+
positives = Set(range(1, self.k + 1))
|
|
1496
|
+
negatives = Set(-i for i in positives)
|
|
1497
|
+
|
|
1498
|
+
yield self.element_class(self,
|
|
1499
|
+
to_set_partition([[self.k + 1, -self.k - 1]],
|
|
1500
|
+
k=self.k + 1))
|
|
1501
|
+
for n in range(1, self.k + 1):
|
|
1502
|
+
for top in Subsets(positives, n):
|
|
1503
|
+
t = sorted(top)
|
|
1504
|
+
for bottom in Subsets(negatives, n):
|
|
1505
|
+
b = list(bottom)
|
|
1506
|
+
b.sort(reverse=True)
|
|
1507
|
+
l = [[t[i], b[i]] for i in range(n)] + [[self.k + 1, -self.k - 1]]
|
|
1508
|
+
yield self.element_class(self,
|
|
1509
|
+
to_set_partition(l, k=self.k + 1))
|
|
1510
|
+
|
|
1511
|
+
|
|
1512
|
+
#########################################################
|
|
1513
|
+
# Algebras
|
|
1514
|
+
|
|
1515
|
+
class PartitionAlgebra_generic(CombinatorialFreeModule):
|
|
1516
|
+
def __init__(self, R, cclass, n, k, name=None, prefix=None):
|
|
1517
|
+
"""
|
|
1518
|
+
EXAMPLES::
|
|
1519
|
+
|
|
1520
|
+
sage: from sage.combinat.partition_algebra import *
|
|
1521
|
+
sage: s = PartitionAlgebra_sk(QQ, 3, 1)
|
|
1522
|
+
sage: TestSuite(s).run() # needs sage.graphs
|
|
1523
|
+
sage: s == loads(dumps(s))
|
|
1524
|
+
True
|
|
1525
|
+
"""
|
|
1526
|
+
self.k = k
|
|
1527
|
+
self.n = n
|
|
1528
|
+
self._indices = cclass
|
|
1529
|
+
self._name = "Generic partition algebra with k = %s and n = %s and basis %s" % (self.k, self.n, cclass) if name is None else name
|
|
1530
|
+
self._prefix = "" if prefix is None else prefix
|
|
1531
|
+
CombinatorialFreeModule.__init__(self, R, cclass, category=AlgebrasWithBasis(R))
|
|
1532
|
+
|
|
1533
|
+
def one_basis(self):
|
|
1534
|
+
"""
|
|
1535
|
+
Return the basis index for the unit of the algebra.
|
|
1536
|
+
|
|
1537
|
+
EXAMPLES::
|
|
1538
|
+
|
|
1539
|
+
sage: from sage.combinat.partition_algebra import *
|
|
1540
|
+
sage: s = PartitionAlgebra_sk(ZZ, 3, 1)
|
|
1541
|
+
sage: len(s.one().support()) # indirect doctest
|
|
1542
|
+
1
|
|
1543
|
+
"""
|
|
1544
|
+
return self.basis().keys()(identity(ceil(self.k)))
|
|
1545
|
+
|
|
1546
|
+
def product_on_basis(self, left, right):
|
|
1547
|
+
"""
|
|
1548
|
+
EXAMPLES::
|
|
1549
|
+
|
|
1550
|
+
sage: from sage.combinat.partition_algebra import *
|
|
1551
|
+
sage: s = PartitionAlgebra_sk(QQ, 3, 1)
|
|
1552
|
+
sage: t12 = s(Set([Set([1,-2]),Set([2,-1]),Set([3,-3])]))
|
|
1553
|
+
sage: t12^2 == s(1) # indirect doctest # needs sage.graphs
|
|
1554
|
+
True
|
|
1555
|
+
"""
|
|
1556
|
+
sp, l = set_partition_composition(left, right)
|
|
1557
|
+
sp = self.basis().keys()(sp)
|
|
1558
|
+
return self.term(sp, self.n**l)
|
|
1559
|
+
|
|
1560
|
+
|
|
1561
|
+
class PartitionAlgebraElement_generic(CombinatorialFreeModule.Element):
|
|
1562
|
+
pass
|
|
1563
|
+
|
|
1564
|
+
|
|
1565
|
+
class PartitionAlgebraElement_ak(PartitionAlgebraElement_generic):
|
|
1566
|
+
pass
|
|
1567
|
+
|
|
1568
|
+
|
|
1569
|
+
class PartitionAlgebra_ak(PartitionAlgebra_generic):
|
|
1570
|
+
def __init__(self, R, k, n, name=None):
|
|
1571
|
+
"""
|
|
1572
|
+
EXAMPLES::
|
|
1573
|
+
|
|
1574
|
+
sage: from sage.combinat.partition_algebra import *
|
|
1575
|
+
sage: p = PartitionAlgebra_ak(QQ, 3, 1)
|
|
1576
|
+
sage: p == loads(dumps(p))
|
|
1577
|
+
True
|
|
1578
|
+
"""
|
|
1579
|
+
if name is None:
|
|
1580
|
+
name = "Partition algebra A_%s(%s)" % (k, n)
|
|
1581
|
+
cclass = SetPartitionsAk(k)
|
|
1582
|
+
self._element_class = PartitionAlgebraElement_ak
|
|
1583
|
+
PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='A')
|
|
1584
|
+
|
|
1585
|
+
|
|
1586
|
+
class PartitionAlgebraElement_bk(PartitionAlgebraElement_generic):
|
|
1587
|
+
pass
|
|
1588
|
+
|
|
1589
|
+
|
|
1590
|
+
class PartitionAlgebra_bk(PartitionAlgebra_generic):
|
|
1591
|
+
def __init__(self, R, k, n, name=None):
|
|
1592
|
+
"""
|
|
1593
|
+
EXAMPLES::
|
|
1594
|
+
|
|
1595
|
+
sage: from sage.combinat.partition_algebra import *
|
|
1596
|
+
sage: p = PartitionAlgebra_bk(QQ, 3, 1)
|
|
1597
|
+
sage: p == loads(dumps(p))
|
|
1598
|
+
True
|
|
1599
|
+
"""
|
|
1600
|
+
if name is None:
|
|
1601
|
+
name = "Partition algebra B_%s(%s)" % (k, n)
|
|
1602
|
+
cclass = SetPartitionsBk(k)
|
|
1603
|
+
self._element_class = PartitionAlgebraElement_bk
|
|
1604
|
+
PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='B')
|
|
1605
|
+
|
|
1606
|
+
|
|
1607
|
+
class PartitionAlgebraElement_sk(PartitionAlgebraElement_generic):
|
|
1608
|
+
pass
|
|
1609
|
+
|
|
1610
|
+
|
|
1611
|
+
class PartitionAlgebra_sk(PartitionAlgebra_generic):
|
|
1612
|
+
def __init__(self, R, k, n, name=None):
|
|
1613
|
+
"""
|
|
1614
|
+
EXAMPLES::
|
|
1615
|
+
|
|
1616
|
+
sage: from sage.combinat.partition_algebra import *
|
|
1617
|
+
sage: p = PartitionAlgebra_sk(QQ, 3, 1)
|
|
1618
|
+
sage: p == loads(dumps(p))
|
|
1619
|
+
True
|
|
1620
|
+
"""
|
|
1621
|
+
if name is None:
|
|
1622
|
+
name = "Partition algebra S_%s(%s)" % (k, n)
|
|
1623
|
+
cclass = SetPartitionsSk(k)
|
|
1624
|
+
self._element_class = PartitionAlgebraElement_sk
|
|
1625
|
+
PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='S')
|
|
1626
|
+
|
|
1627
|
+
|
|
1628
|
+
class PartitionAlgebraElement_pk(PartitionAlgebraElement_generic):
|
|
1629
|
+
pass
|
|
1630
|
+
|
|
1631
|
+
|
|
1632
|
+
class PartitionAlgebra_pk(PartitionAlgebra_generic):
|
|
1633
|
+
def __init__(self, R, k, n, name=None):
|
|
1634
|
+
"""
|
|
1635
|
+
EXAMPLES::
|
|
1636
|
+
|
|
1637
|
+
sage: from sage.combinat.partition_algebra import *
|
|
1638
|
+
sage: p = PartitionAlgebra_pk(QQ, 3, 1)
|
|
1639
|
+
sage: p == loads(dumps(p))
|
|
1640
|
+
True
|
|
1641
|
+
"""
|
|
1642
|
+
if name is None:
|
|
1643
|
+
name = "Partition algebra P_%s(%s)" % (k, n)
|
|
1644
|
+
cclass = SetPartitionsPk(k)
|
|
1645
|
+
self._element_class = PartitionAlgebraElement_pk
|
|
1646
|
+
PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='P')
|
|
1647
|
+
|
|
1648
|
+
|
|
1649
|
+
class PartitionAlgebraElement_tk(PartitionAlgebraElement_generic):
|
|
1650
|
+
pass
|
|
1651
|
+
|
|
1652
|
+
|
|
1653
|
+
class PartitionAlgebra_tk(PartitionAlgebra_generic):
|
|
1654
|
+
def __init__(self, R, k, n, name=None):
|
|
1655
|
+
"""
|
|
1656
|
+
EXAMPLES::
|
|
1657
|
+
|
|
1658
|
+
sage: from sage.combinat.partition_algebra import *
|
|
1659
|
+
sage: p = PartitionAlgebra_tk(QQ, 3, 1)
|
|
1660
|
+
sage: p == loads(dumps(p))
|
|
1661
|
+
True
|
|
1662
|
+
"""
|
|
1663
|
+
if name is None:
|
|
1664
|
+
name = "Partition algebra T_%s(%s)" % (k, n)
|
|
1665
|
+
cclass = SetPartitionsTk(k)
|
|
1666
|
+
self._element_class = PartitionAlgebraElement_tk
|
|
1667
|
+
PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='T')
|
|
1668
|
+
|
|
1669
|
+
|
|
1670
|
+
class PartitionAlgebraElement_rk(PartitionAlgebraElement_generic):
|
|
1671
|
+
pass
|
|
1672
|
+
|
|
1673
|
+
|
|
1674
|
+
class PartitionAlgebra_rk(PartitionAlgebra_generic):
|
|
1675
|
+
def __init__(self, R, k, n, name=None):
|
|
1676
|
+
"""
|
|
1677
|
+
EXAMPLES::
|
|
1678
|
+
|
|
1679
|
+
sage: from sage.combinat.partition_algebra import *
|
|
1680
|
+
sage: p = PartitionAlgebra_rk(QQ, 3, 1)
|
|
1681
|
+
sage: p == loads(dumps(p))
|
|
1682
|
+
True
|
|
1683
|
+
"""
|
|
1684
|
+
if name is None:
|
|
1685
|
+
name = "Partition algebra R_%s(%s)" % (k, n)
|
|
1686
|
+
cclass = SetPartitionsRk(k)
|
|
1687
|
+
self._element_class = PartitionAlgebraElement_rk
|
|
1688
|
+
PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='R')
|
|
1689
|
+
|
|
1690
|
+
|
|
1691
|
+
class PartitionAlgebraElement_prk(PartitionAlgebraElement_generic):
|
|
1692
|
+
pass
|
|
1693
|
+
|
|
1694
|
+
|
|
1695
|
+
class PartitionAlgebra_prk(PartitionAlgebra_generic):
|
|
1696
|
+
def __init__(self, R, k, n, name=None):
|
|
1697
|
+
"""
|
|
1698
|
+
EXAMPLES::
|
|
1699
|
+
|
|
1700
|
+
sage: from sage.combinat.partition_algebra import *
|
|
1701
|
+
sage: p = PartitionAlgebra_prk(QQ, 3, 1)
|
|
1702
|
+
sage: p == loads(dumps(p))
|
|
1703
|
+
True
|
|
1704
|
+
"""
|
|
1705
|
+
if name is None:
|
|
1706
|
+
name = "Partition algebra PR_%s(%s)" % (k, n)
|
|
1707
|
+
cclass = SetPartitionsPRk(k)
|
|
1708
|
+
self._element_class = PartitionAlgebraElement_prk
|
|
1709
|
+
PartitionAlgebra_generic.__init__(self, R, cclass, n, k, name=name, prefix='PR')
|
|
1710
|
+
|
|
1711
|
+
|
|
1712
|
+
##########################################################
|
|
1713
|
+
|
|
1714
|
+
def is_planar(sp):
|
|
1715
|
+
"""
|
|
1716
|
+
Return ``True`` if the diagram corresponding to the set partition is
|
|
1717
|
+
planar; otherwise, it returns ``False``.
|
|
1718
|
+
|
|
1719
|
+
EXAMPLES::
|
|
1720
|
+
|
|
1721
|
+
sage: import sage.combinat.partition_algebra as pa
|
|
1722
|
+
sage: pa.is_planar( pa.to_set_partition([[1,-2],[2,-1]]))
|
|
1723
|
+
False
|
|
1724
|
+
sage: pa.is_planar( pa.to_set_partition([[1,-1],[2,-2]]))
|
|
1725
|
+
True
|
|
1726
|
+
"""
|
|
1727
|
+
# Singletons don't affect planarity
|
|
1728
|
+
to_consider = [x for x in map(list, sp) if len(x) > 1]
|
|
1729
|
+
n = len(to_consider)
|
|
1730
|
+
|
|
1731
|
+
for i in range(n):
|
|
1732
|
+
# Get the positive and negative entries of this
|
|
1733
|
+
# part
|
|
1734
|
+
ap = [x for x in to_consider[i] if x > 0]
|
|
1735
|
+
an = [-x for x in to_consider[i] if x < 0]
|
|
1736
|
+
|
|
1737
|
+
# Check if a includes numbers in both the top and bottom rows
|
|
1738
|
+
if ap and an:
|
|
1739
|
+
for j in range(n):
|
|
1740
|
+
if i == j:
|
|
1741
|
+
continue
|
|
1742
|
+
# Get the positive and negative entries of this part
|
|
1743
|
+
bp = [x for x in to_consider[j] if x > 0]
|
|
1744
|
+
bn = [-x for x in to_consider[j] if x < 0]
|
|
1745
|
+
|
|
1746
|
+
# Skip the ones that don't involve numbers in both
|
|
1747
|
+
# the bottom and top rows
|
|
1748
|
+
if not bn or not bp:
|
|
1749
|
+
continue
|
|
1750
|
+
|
|
1751
|
+
# Make sure that if min(bp) > max(ap)
|
|
1752
|
+
# then min(bn) > max(an)
|
|
1753
|
+
if max(bp) > max(ap):
|
|
1754
|
+
if min(bn) < min(an):
|
|
1755
|
+
return False
|
|
1756
|
+
|
|
1757
|
+
# Go through the bottom and top rows
|
|
1758
|
+
for row in [ap, an]:
|
|
1759
|
+
if len(row) > 1:
|
|
1760
|
+
row.sort()
|
|
1761
|
+
for s in range(len(row) - 1):
|
|
1762
|
+
if row[s] + 1 == row[s + 1]:
|
|
1763
|
+
# No gap, continue on
|
|
1764
|
+
continue
|
|
1765
|
+
else:
|
|
1766
|
+
rng = list(range(row[s] + 1, row[s + 1]))
|
|
1767
|
+
|
|
1768
|
+
# Go through and make sure any parts that
|
|
1769
|
+
# contain numbers in this range are completely
|
|
1770
|
+
# contained in this range
|
|
1771
|
+
for j in range(n):
|
|
1772
|
+
if i == j:
|
|
1773
|
+
continue
|
|
1774
|
+
|
|
1775
|
+
# Make sure we make the numbers negative again
|
|
1776
|
+
# if we are in the bottom row
|
|
1777
|
+
if row is ap:
|
|
1778
|
+
sr = Set(rng)
|
|
1779
|
+
else:
|
|
1780
|
+
sr = Set(-x for x in rng)
|
|
1781
|
+
|
|
1782
|
+
sj = Set(to_consider[j])
|
|
1783
|
+
intersection = sr.intersection(sj)
|
|
1784
|
+
if intersection:
|
|
1785
|
+
if sj != intersection:
|
|
1786
|
+
return False
|
|
1787
|
+
|
|
1788
|
+
return True
|
|
1789
|
+
|
|
1790
|
+
|
|
1791
|
+
def to_graph(sp):
|
|
1792
|
+
"""
|
|
1793
|
+
Return a graph representing the set partition ``sp``.
|
|
1794
|
+
|
|
1795
|
+
EXAMPLES::
|
|
1796
|
+
|
|
1797
|
+
sage: # needs sage.graphs
|
|
1798
|
+
sage: import sage.combinat.partition_algebra as pa
|
|
1799
|
+
sage: g = pa.to_graph(pa.to_set_partition([[1,-2], [2,-1]])); g
|
|
1800
|
+
Graph on 4 vertices
|
|
1801
|
+
sage: g.vertices(sort=False) # random
|
|
1802
|
+
[1, 2, -2, -1]
|
|
1803
|
+
sage: g.edges(sort=False) # random
|
|
1804
|
+
[(1, -2, None), (2, -1, None)]
|
|
1805
|
+
"""
|
|
1806
|
+
g = Graph()
|
|
1807
|
+
for part in sp:
|
|
1808
|
+
part_list = list(part)
|
|
1809
|
+
if part_list:
|
|
1810
|
+
g.add_vertex(part_list[0])
|
|
1811
|
+
for i in range(1, len(part_list)):
|
|
1812
|
+
g.add_vertex(part_list[i])
|
|
1813
|
+
g.add_edge(part_list[i - 1], part_list[i])
|
|
1814
|
+
return g
|
|
1815
|
+
|
|
1816
|
+
|
|
1817
|
+
def pair_to_graph(sp1, sp2):
|
|
1818
|
+
"""
|
|
1819
|
+
Return a graph consisting of the disjoint union of the graphs of set
|
|
1820
|
+
partitions ``sp1`` and ``sp2`` along with edges joining the bottom
|
|
1821
|
+
row (negative numbers) of ``sp1`` to the top row (positive numbers)
|
|
1822
|
+
of ``sp2``.
|
|
1823
|
+
|
|
1824
|
+
The vertices of the graph ``sp1`` appear in the result as pairs
|
|
1825
|
+
``(k, 1)``, whereas the vertices of the graph ``sp2`` appear as
|
|
1826
|
+
pairs ``(k, 2)``.
|
|
1827
|
+
|
|
1828
|
+
EXAMPLES::
|
|
1829
|
+
|
|
1830
|
+
sage: # needs sage.graphs
|
|
1831
|
+
sage: import sage.combinat.partition_algebra as pa
|
|
1832
|
+
sage: sp1 = pa.to_set_partition([[1,-2],[2,-1]])
|
|
1833
|
+
sage: sp2 = pa.to_set_partition([[1,-2],[2,-1]])
|
|
1834
|
+
sage: g = pa.pair_to_graph( sp1, sp2 ); g
|
|
1835
|
+
Graph on 8 vertices
|
|
1836
|
+
|
|
1837
|
+
::
|
|
1838
|
+
|
|
1839
|
+
sage: # needs sage.graphs
|
|
1840
|
+
sage: g.vertices(sort=False) #random
|
|
1841
|
+
[(1, 2), (-1, 1), (-2, 2), (-1, 2), (-2, 1), (2, 1), (2, 2), (1, 1)]
|
|
1842
|
+
sage: g.edges(sort=False) #random
|
|
1843
|
+
[((1, 2), (-1, 1), None),
|
|
1844
|
+
((1, 2), (-2, 2), None),
|
|
1845
|
+
((-1, 1), (2, 1), None),
|
|
1846
|
+
((-1, 2), (2, 2), None),
|
|
1847
|
+
((-2, 1), (1, 1), None),
|
|
1848
|
+
((-2, 1), (2, 2), None)]
|
|
1849
|
+
|
|
1850
|
+
Another example which used to be wrong until :issue:`15958`::
|
|
1851
|
+
|
|
1852
|
+
sage: # needs sage.graphs
|
|
1853
|
+
sage: sp3 = pa.to_set_partition([[1, -1], [2], [-2]])
|
|
1854
|
+
sage: sp4 = pa.to_set_partition([[1], [-1], [2], [-2]])
|
|
1855
|
+
sage: g = pa.pair_to_graph( sp3, sp4 ); g
|
|
1856
|
+
Graph on 8 vertices
|
|
1857
|
+
sage: g.vertices(sort=True)
|
|
1858
|
+
[(-2, 1), (-2, 2), (-1, 1), (-1, 2), (1, 1), (1, 2), (2, 1), (2, 2)]
|
|
1859
|
+
sage: g.edges(sort=True)
|
|
1860
|
+
[((-2, 1), (2, 2), None), ((-1, 1), (1, 1), None),
|
|
1861
|
+
((-1, 1), (1, 2), None)]
|
|
1862
|
+
"""
|
|
1863
|
+
g = Graph()
|
|
1864
|
+
|
|
1865
|
+
# Add the first set partition to the graph
|
|
1866
|
+
for part in sp1:
|
|
1867
|
+
part_list = list(part)
|
|
1868
|
+
if part_list:
|
|
1869
|
+
g.add_vertex((part_list[0], 1))
|
|
1870
|
+
|
|
1871
|
+
# Add the edge to the second part of the graph
|
|
1872
|
+
if part_list[0] < 0:
|
|
1873
|
+
g.add_edge((part_list[0], 1), (-part_list[0], 2))
|
|
1874
|
+
|
|
1875
|
+
for i in range(1, len(part_list)):
|
|
1876
|
+
g.add_vertex((part_list[i], 1))
|
|
1877
|
+
|
|
1878
|
+
# Add the edge to the second part of the graph
|
|
1879
|
+
if part_list[i] < 0:
|
|
1880
|
+
g.add_edge((part_list[i], 1), (-part_list[i], 2))
|
|
1881
|
+
|
|
1882
|
+
# Add the edge between adjacent elements of a part
|
|
1883
|
+
g.add_edge((part_list[i - 1], 1), (part_list[i], 1))
|
|
1884
|
+
|
|
1885
|
+
# Add the second set partition to the graph
|
|
1886
|
+
for part in sp2:
|
|
1887
|
+
part_list = list(part)
|
|
1888
|
+
if part_list:
|
|
1889
|
+
g.add_vertex((part_list[0], 2))
|
|
1890
|
+
for i in range(1, len(part_list)):
|
|
1891
|
+
g.add_vertex((part_list[i], 2))
|
|
1892
|
+
g.add_edge((part_list[i - 1], 2), (part_list[i], 2))
|
|
1893
|
+
|
|
1894
|
+
return g
|
|
1895
|
+
|
|
1896
|
+
|
|
1897
|
+
def propagating_number(sp):
|
|
1898
|
+
"""
|
|
1899
|
+
Return the propagating number of the set partition ``sp``.
|
|
1900
|
+
|
|
1901
|
+
The propagating number is the number of blocks with both a
|
|
1902
|
+
positive and negative number.
|
|
1903
|
+
|
|
1904
|
+
EXAMPLES::
|
|
1905
|
+
|
|
1906
|
+
sage: import sage.combinat.partition_algebra as pa
|
|
1907
|
+
sage: sp1 = pa.to_set_partition([[1,-2],[2,-1]])
|
|
1908
|
+
sage: sp2 = pa.to_set_partition([[1,2],[-2,-1]])
|
|
1909
|
+
sage: pa.propagating_number(sp1)
|
|
1910
|
+
2
|
|
1911
|
+
sage: pa.propagating_number(sp2)
|
|
1912
|
+
0
|
|
1913
|
+
"""
|
|
1914
|
+
return sum(1 for part in sp if min(part) < 0 < max(part))
|
|
1915
|
+
|
|
1916
|
+
|
|
1917
|
+
def to_set_partition(l, k=None):
|
|
1918
|
+
"""
|
|
1919
|
+
Convert a list of a list of numbers to a set partitions.
|
|
1920
|
+
|
|
1921
|
+
Each list of numbers in the outer list specifies the numbers
|
|
1922
|
+
contained in one of the blocks in the set partition.
|
|
1923
|
+
|
|
1924
|
+
If k is specified, then the set partition will be a set partition
|
|
1925
|
+
of 1, ..., k, -1, ..., -k. Otherwise, k will default to the minimum
|
|
1926
|
+
number needed to contain all of the specified numbers.
|
|
1927
|
+
|
|
1928
|
+
EXAMPLES::
|
|
1929
|
+
|
|
1930
|
+
sage: import sage.combinat.partition_algebra as pa
|
|
1931
|
+
sage: pa.to_set_partition([[1,-1],[2,-2]]) == pa.identity(2)
|
|
1932
|
+
True
|
|
1933
|
+
"""
|
|
1934
|
+
if k is None:
|
|
1935
|
+
if not l:
|
|
1936
|
+
return Set([])
|
|
1937
|
+
else:
|
|
1938
|
+
k = max(max(map(abs, x)) for x in l)
|
|
1939
|
+
|
|
1940
|
+
to_be_added = Set(list(range(1, k + 1)) + [-x for x in range(1, k + 1)])
|
|
1941
|
+
|
|
1942
|
+
sp = []
|
|
1943
|
+
for part in l:
|
|
1944
|
+
spart = Set(part)
|
|
1945
|
+
to_be_added -= spart
|
|
1946
|
+
sp.append(spart)
|
|
1947
|
+
|
|
1948
|
+
sp.extend(Set([singleton])
|
|
1949
|
+
for singleton in to_be_added)
|
|
1950
|
+
|
|
1951
|
+
return Set(sp)
|
|
1952
|
+
|
|
1953
|
+
|
|
1954
|
+
def identity(k):
|
|
1955
|
+
r"""
|
|
1956
|
+
Return the identity set partition `1, -1, \ldots, k, -k`.
|
|
1957
|
+
|
|
1958
|
+
EXAMPLES::
|
|
1959
|
+
|
|
1960
|
+
sage: import sage.combinat.partition_algebra as pa
|
|
1961
|
+
sage: pa.identity(2)
|
|
1962
|
+
{{2, -2}, {1, -1}}
|
|
1963
|
+
"""
|
|
1964
|
+
return Set(Set([i, -i]) for i in range(1, k + 1))
|
|
1965
|
+
|
|
1966
|
+
|
|
1967
|
+
def set_partition_composition(sp1, sp2):
|
|
1968
|
+
"""
|
|
1969
|
+
Return a tuple consisting of the composition of the set partitions
|
|
1970
|
+
sp1 and sp2 and the number of components removed from the middle
|
|
1971
|
+
rows of the graph.
|
|
1972
|
+
|
|
1973
|
+
EXAMPLES::
|
|
1974
|
+
|
|
1975
|
+
sage: # needs sage.graphs
|
|
1976
|
+
sage: import sage.combinat.partition_algebra as pa
|
|
1977
|
+
sage: sp1 = pa.to_set_partition([[1,-2],[2,-1]])
|
|
1978
|
+
sage: sp2 = pa.to_set_partition([[1,-2],[2,-1]])
|
|
1979
|
+
sage: pa.set_partition_composition(sp1, sp2) == (pa.identity(2), 0)
|
|
1980
|
+
True
|
|
1981
|
+
"""
|
|
1982
|
+
g = pair_to_graph(sp1, sp2)
|
|
1983
|
+
connected_components = g.connected_components(sort=False)
|
|
1984
|
+
|
|
1985
|
+
res = []
|
|
1986
|
+
total_removed = 0
|
|
1987
|
+
for cc in connected_components:
|
|
1988
|
+
# Remove the vertices that live in the middle two rows
|
|
1989
|
+
new_cc = [x for x in cc if not ((x[0] < 0 and x[1] == 1) or
|
|
1990
|
+
(x[0] > 0 and x[1] == 2))]
|
|
1991
|
+
|
|
1992
|
+
if not new_cc:
|
|
1993
|
+
if len(cc) > 1:
|
|
1994
|
+
total_removed += 1
|
|
1995
|
+
else:
|
|
1996
|
+
res.append(Set(x[0] for x in new_cc))
|
|
1997
|
+
|
|
1998
|
+
return (Set(res), total_removed)
|