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,1077 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
# sage.doctest: needs sage.combinat sage.graphs sage.modules
|
|
3
|
+
r"""
|
|
4
|
+
Fully commutative elements of Coxeter groups
|
|
5
|
+
|
|
6
|
+
An element `w` in a Coxeter system (W,S) is fully commutative (FC) if
|
|
7
|
+
every two reduced words of w can be related by a sequence of only
|
|
8
|
+
commutation relations, i.e., relations of the form `st=ts` where `s,t` are
|
|
9
|
+
commuting generators in `S`. See [Ste1996]_.
|
|
10
|
+
|
|
11
|
+
Authors:
|
|
12
|
+
|
|
13
|
+
- Chase Meadors, Tianyuan Xu (2020): Initial version
|
|
14
|
+
|
|
15
|
+
Acknowledgements
|
|
16
|
+
----------------
|
|
17
|
+
|
|
18
|
+
A draft of this code was written during an REU project at University of
|
|
19
|
+
Colorado Boulder. We thank Rachel Castro, Joel Courtney, Thomas Magnuson and
|
|
20
|
+
Natalie Schoenhals for their contribution to the project and the code.
|
|
21
|
+
"""
|
|
22
|
+
# ****************************************************************************
|
|
23
|
+
# Copyright (C) 2020 Chase Meadors <Chase.Meadors at colorado.edu>,
|
|
24
|
+
# Tianyuan Xu <Tianyuan.Xu at colorado.edu>
|
|
25
|
+
#
|
|
26
|
+
# This program is free software: you can redistribute it and/or modify
|
|
27
|
+
# it under the terms of the GNU General Public License as published by
|
|
28
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
29
|
+
# (at your option) any later version.
|
|
30
|
+
# https://www.gnu.org/licenses/
|
|
31
|
+
# ****************************************************************************
|
|
32
|
+
from collections import deque
|
|
33
|
+
|
|
34
|
+
from sage.categories.coxeter_groups import CoxeterGroups
|
|
35
|
+
from sage.categories.enumerated_sets import EnumeratedSets
|
|
36
|
+
from sage.misc.lazy_import import lazy_import
|
|
37
|
+
from sage.structure.list_clone import NormalizedClonableList
|
|
38
|
+
from sage.structure.parent import Parent
|
|
39
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
40
|
+
|
|
41
|
+
lazy_import('sage.combinat.posets.posets', 'Poset')
|
|
42
|
+
lazy_import('sage.combinat.root_system.coxeter_group', 'CoxeterGroup')
|
|
43
|
+
lazy_import('sage.combinat.root_system.coxeter_matrix', 'CoxeterMatrix')
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class FullyCommutativeElement(NormalizedClonableList):
|
|
47
|
+
r"""
|
|
48
|
+
A fully commutative (FC) element in a Coxeter system.
|
|
49
|
+
|
|
50
|
+
An element `w` in a Coxeter system (W,S) is fully commutative (FC) if every
|
|
51
|
+
two reduced word of w can be related by a sequence of only commutation
|
|
52
|
+
relations, i.e., relations of the form `st=ts` where `s,t` are commuting
|
|
53
|
+
generators in `S`.
|
|
54
|
+
|
|
55
|
+
Every FC element has a canonical reduced word called its Cartier--Foata
|
|
56
|
+
form. See [Gre2006]_. We will normalize each FC element to this form.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def group_element(self):
|
|
60
|
+
r"""
|
|
61
|
+
Get the actual element of the Coxeter group associated with
|
|
62
|
+
``self.parent()`` corresponding to ``self``.
|
|
63
|
+
|
|
64
|
+
EXAMPLES::
|
|
65
|
+
|
|
66
|
+
sage: W = CoxeterGroup(['A', 3])
|
|
67
|
+
sage: FC = W.fully_commutative_elements()
|
|
68
|
+
sage: x = FC([1, 2])
|
|
69
|
+
sage: x.group_element()
|
|
70
|
+
[ 0 -1 1]
|
|
71
|
+
[ 1 -1 1]
|
|
72
|
+
[ 0 0 1]
|
|
73
|
+
sage: x.group_element() in W
|
|
74
|
+
True
|
|
75
|
+
"""
|
|
76
|
+
return self.parent().coxeter_group().from_reduced_word(self)
|
|
77
|
+
|
|
78
|
+
###########################################################################
|
|
79
|
+
# Characterization and representation of FC elements #
|
|
80
|
+
###########################################################################
|
|
81
|
+
|
|
82
|
+
# Methods required as a subclass of NormalizedClonableList:
|
|
83
|
+
def check(self):
|
|
84
|
+
r"""
|
|
85
|
+
Called automatically when an element is created.
|
|
86
|
+
|
|
87
|
+
EXAMPLES::
|
|
88
|
+
|
|
89
|
+
sage: CoxeterGroup(['A', 3]).fully_commutative_elements()([1, 2]) # indirect doctest
|
|
90
|
+
[1, 2]
|
|
91
|
+
sage: CoxeterGroup(['A', 3]).fully_commutative_elements()([1, 2, 1]) # indirect doctest
|
|
92
|
+
Traceback (most recent call last):
|
|
93
|
+
...
|
|
94
|
+
ValueError: the input is not a reduced word of a fully commutative element
|
|
95
|
+
"""
|
|
96
|
+
if not self.is_fully_commutative():
|
|
97
|
+
raise ValueError('the input is not a reduced word of a fully commutative element')
|
|
98
|
+
|
|
99
|
+
def normalize(self):
|
|
100
|
+
r"""
|
|
101
|
+
Mutate ``self`` into Cartier-Foata normal form.
|
|
102
|
+
|
|
103
|
+
EXAMPLES:
|
|
104
|
+
|
|
105
|
+
The following reduced words express the same FC elements in `B_5`::
|
|
106
|
+
|
|
107
|
+
sage: FC = CoxeterGroup(['B', 5]).fully_commutative_elements()
|
|
108
|
+
sage: FC([1, 4, 3, 5, 2, 4, 3]) # indirect doctest
|
|
109
|
+
[1, 4, 3, 5, 2, 4, 3]
|
|
110
|
+
sage: FC([4, 1, 3, 5, 2, 4, 3]) # indirect doctest
|
|
111
|
+
[1, 4, 3, 5, 2, 4, 3]
|
|
112
|
+
sage: FC([4, 3, 1, 5, 4, 2, 3]) # indirect doctest
|
|
113
|
+
[1, 4, 3, 5, 2, 4, 3]
|
|
114
|
+
|
|
115
|
+
.. NOTE::
|
|
116
|
+
|
|
117
|
+
The Cartier--Foata form of a reduced word of an FC element `w` can
|
|
118
|
+
be found recursively by repeatedly moving left descents of
|
|
119
|
+
elements to the left and ordering the left descents from small to
|
|
120
|
+
large. In the above example, the left descents of the element are
|
|
121
|
+
4 and 1, therefore the Cartier--Foata form of the element is the
|
|
122
|
+
concatenation of [1,4] with the Cartier--Foata form of the
|
|
123
|
+
remaining part of the word. See [Gre2006]_.
|
|
124
|
+
|
|
125
|
+
.. SEEALSO:: :func:`descents`
|
|
126
|
+
"""
|
|
127
|
+
self._require_mutable()
|
|
128
|
+
|
|
129
|
+
out_word = []
|
|
130
|
+
|
|
131
|
+
while self:
|
|
132
|
+
fronts = self.descents()
|
|
133
|
+
out_word.extend(sorted(fronts))
|
|
134
|
+
for s in fronts:
|
|
135
|
+
self.remove(s)
|
|
136
|
+
|
|
137
|
+
self._set_list(out_word)
|
|
138
|
+
|
|
139
|
+
# Full commutativity test
|
|
140
|
+
def is_fully_commutative(self):
|
|
141
|
+
r"""
|
|
142
|
+
Check if ``self`` is the reduced word of an FC element.
|
|
143
|
+
|
|
144
|
+
To check if ``self`` is FC, we use the well-known characterization that
|
|
145
|
+
an element `w` in a Coxeter system `(W,S)` is FC if and only if for
|
|
146
|
+
every pair of generators `s,t \in S` for which `m(s,t)>2`, no reduced
|
|
147
|
+
word of `w` contains the 'braid' word `sts...` of length `m(s,t)` as a
|
|
148
|
+
contiguous subword. See [Ste1996]_.
|
|
149
|
+
|
|
150
|
+
:func:`check` is an alias of this method, and is called automatically
|
|
151
|
+
when an element is created.
|
|
152
|
+
|
|
153
|
+
EXAMPLES::
|
|
154
|
+
|
|
155
|
+
sage: FC = CoxeterGroup(['A', 3]).fully_commutative_elements()
|
|
156
|
+
sage: x = FC([1, 2]); x.is_fully_commutative()
|
|
157
|
+
True
|
|
158
|
+
sage: x = FC.element_class(FC, [1, 2, 1], check=False); x.is_fully_commutative()
|
|
159
|
+
False
|
|
160
|
+
"""
|
|
161
|
+
word = list(self)
|
|
162
|
+
from sage.combinat.root_system.braid_orbit import is_fully_commutative as is_fully_comm
|
|
163
|
+
|
|
164
|
+
group = self.parent().coxeter_group()
|
|
165
|
+
braid_rels = group.braid_relations()
|
|
166
|
+
I = group.index_set()
|
|
167
|
+
|
|
168
|
+
from sage.rings.integer_ring import ZZ
|
|
169
|
+
be_careful = any(i not in ZZ for i in I)
|
|
170
|
+
|
|
171
|
+
if be_careful:
|
|
172
|
+
Iinv = {i: j for j, i in enumerate(I)}
|
|
173
|
+
word = [Iinv[i] for i in word]
|
|
174
|
+
braid_rels = [[[Iinv[i] for i in l],
|
|
175
|
+
[Iinv[i] for i in r]] for l, r in braid_rels]
|
|
176
|
+
|
|
177
|
+
return is_fully_comm(word, braid_rels)
|
|
178
|
+
|
|
179
|
+
# Representing FC elements: Heaps
|
|
180
|
+
def heap(self, **kargs):
|
|
181
|
+
r"""
|
|
182
|
+
Create the heap poset of ``self``.
|
|
183
|
+
|
|
184
|
+
The heap of an FC element `w` is a labeled poset that can be defined
|
|
185
|
+
from any reduced word of `w`. Different reduced words yield isomorphic
|
|
186
|
+
labeled posets, so the heap is well defined.
|
|
187
|
+
|
|
188
|
+
Heaps are very useful for visualizing and studying FC elements; see, for
|
|
189
|
+
example, [Ste1996]_ and [GX2020]_.
|
|
190
|
+
|
|
191
|
+
INPUT:
|
|
192
|
+
|
|
193
|
+
- ``self`` -- list; a reduced word `w=s_0... s_{k-1}` of an FC element
|
|
194
|
+
|
|
195
|
+
- ``one_index`` -- boolean (default: ``False``); setting the value to True
|
|
196
|
+
will change the underlying set of the poset to `\{1, 2, \dots, n\}`
|
|
197
|
+
|
|
198
|
+
- ``display_labeling`` -- boolean (default: ``False``); setting the value to
|
|
199
|
+
``True`` will display the label `s_i` for each element `i` of the poset
|
|
200
|
+
|
|
201
|
+
OUTPUT:
|
|
202
|
+
|
|
203
|
+
A labeled poset where the underlying set is `\{0,1,...,k-1\}`
|
|
204
|
+
and where each element `i` carries `s_i` as its label. The partial order
|
|
205
|
+
`\prec` on the poset is defined by declaring `i\prec j` if `i<j` and
|
|
206
|
+
`m(s_i,s_j)\neq 2`.
|
|
207
|
+
|
|
208
|
+
EXAMPLES::
|
|
209
|
+
|
|
210
|
+
sage: FC = CoxeterGroup(['A', 5]).fully_commutative_elements()
|
|
211
|
+
sage: FC([1, 4, 3, 5, 2, 4]).heap().cover_relations()
|
|
212
|
+
[[1, 2], [1, 3], [2, 5], [2, 4], [3, 5], [0, 4]]
|
|
213
|
+
sage: FC([1, 4, 3, 5, 4, 2]).heap(one_index=True).cover_relations()
|
|
214
|
+
[[2, 3], [2, 4], [3, 6], [3, 5], [4, 6], [1, 5]]
|
|
215
|
+
"""
|
|
216
|
+
m = self.parent().coxeter_group().coxeter_matrix()
|
|
217
|
+
|
|
218
|
+
one_index = kargs.get('one_index', False)
|
|
219
|
+
display_labeling = kargs.get('display_labeling', False)
|
|
220
|
+
# elements of the poset:
|
|
221
|
+
elements = list(range(1, len(self) + 1)
|
|
222
|
+
) if one_index else list(range(len(self)))
|
|
223
|
+
|
|
224
|
+
# get the label of each poset element:
|
|
225
|
+
def letter(index):
|
|
226
|
+
return self[index - 1] if one_index else self[index]
|
|
227
|
+
|
|
228
|
+
# specify the partial order:
|
|
229
|
+
relations = [(i, j) for i in elements for j in elements
|
|
230
|
+
if i < j and m[letter(i), letter(j)] != 2]
|
|
231
|
+
p = Poset((elements, relations))
|
|
232
|
+
|
|
233
|
+
if not display_labeling:
|
|
234
|
+
return p
|
|
235
|
+
else:
|
|
236
|
+
return p.relabel(lambda i: (i, letter(i)))
|
|
237
|
+
|
|
238
|
+
# Hasse diagrams of heaps help visualize FC elements:
|
|
239
|
+
def plot_heap(self):
|
|
240
|
+
r"""
|
|
241
|
+
Display the Hasse diagram of the heap of ``self``.
|
|
242
|
+
|
|
243
|
+
The Hasse diagram is rendered in the lattice `S \times \NN`, with
|
|
244
|
+
every element `i` in the poset drawn as a point labelled by its label
|
|
245
|
+
`s_i`. Every point is placed in the column for its label at a certain
|
|
246
|
+
level. The levels start at 0 and the level k of an element `i` is the
|
|
247
|
+
maximal number `k` such that the heap contains a chain `i_0\prec
|
|
248
|
+
i_1\prec ... \prec i_k` where `i_k=i`. See [Ste1996]_ and [GX2020]_.
|
|
249
|
+
|
|
250
|
+
OUTPUT: GraphicsObject
|
|
251
|
+
|
|
252
|
+
EXAMPLES::
|
|
253
|
+
|
|
254
|
+
sage: FC = CoxeterGroup(['B', 5]).fully_commutative_elements()
|
|
255
|
+
sage: FC([3,2,4,3,1]).plot_heap() # needs sage.plot
|
|
256
|
+
Graphics object consisting of 15 graphics primitives
|
|
257
|
+
|
|
258
|
+
.. PLOT::
|
|
259
|
+
:width: 400 px
|
|
260
|
+
|
|
261
|
+
FC = CoxeterGroup(['B', 5]).fully_commutative_elements()
|
|
262
|
+
g = FC([3,2,4,3,1]).plot_heap()
|
|
263
|
+
sphinx_plot(g)
|
|
264
|
+
"""
|
|
265
|
+
import sage.plot.all as plot
|
|
266
|
+
|
|
267
|
+
m = self.parent().coxeter_group().coxeter_matrix()
|
|
268
|
+
letters = self.parent().coxeter_group().index_set()
|
|
269
|
+
graphics = []
|
|
270
|
+
|
|
271
|
+
h = self.heap()
|
|
272
|
+
levels = h.level_sets()
|
|
273
|
+
letters_at_level = [set(self[i] for i in level) for level in levels]
|
|
274
|
+
|
|
275
|
+
for (level_zero_index, members) in enumerate(levels):
|
|
276
|
+
level = level_zero_index + 1
|
|
277
|
+
for i in members:
|
|
278
|
+
x = self[i]
|
|
279
|
+
|
|
280
|
+
# Draw the node
|
|
281
|
+
graphics.append(plot.circle(
|
|
282
|
+
(x, level), 0.1, fill=True, facecolor='white', edgecolor='blue', zorder=1))
|
|
283
|
+
graphics.append(
|
|
284
|
+
plot.text(str(x), (x, level), color='blue', zorder=2))
|
|
285
|
+
|
|
286
|
+
neighbors = {z for z in letters if m[x, z] >= 3}
|
|
287
|
+
for other in neighbors:
|
|
288
|
+
highest_level = max(
|
|
289
|
+
(j + 1 for j in range(level_zero_index) if other in letters_at_level[j]), default=None)
|
|
290
|
+
if highest_level:
|
|
291
|
+
graphics.append(
|
|
292
|
+
plot.line([(other, highest_level), (x, level)], color='black', zorder=0))
|
|
293
|
+
|
|
294
|
+
g = sum(graphics)
|
|
295
|
+
g.axes(False)
|
|
296
|
+
return g
|
|
297
|
+
|
|
298
|
+
# An application of heaps:
|
|
299
|
+
def n_value(self):
|
|
300
|
+
r"""
|
|
301
|
+
Calculate the n-value of ``self``.
|
|
302
|
+
|
|
303
|
+
The *n-value* of a fully commutative element is the *width* (length of
|
|
304
|
+
any longest antichain) of its heap. The n-value is important as it
|
|
305
|
+
coincides with Lusztig's a-value for FC elements in all Weyl and affine
|
|
306
|
+
Weyl groups as well as so-called star-reducible groups; see [GX2020]_.
|
|
307
|
+
|
|
308
|
+
EXAMPLES::
|
|
309
|
+
|
|
310
|
+
sage: FC = CoxeterGroup(['A', 5]).fully_commutative_elements()
|
|
311
|
+
sage: FC([1,3]).n_value()
|
|
312
|
+
2
|
|
313
|
+
sage: FC([1,2,3]).n_value()
|
|
314
|
+
1
|
|
315
|
+
sage: FC([1,3,2]).n_value()
|
|
316
|
+
2
|
|
317
|
+
sage: FC([1,3,2,5]).n_value()
|
|
318
|
+
3
|
|
319
|
+
"""
|
|
320
|
+
return self.heap().width()
|
|
321
|
+
|
|
322
|
+
###########################################################################
|
|
323
|
+
# Descents and coset decompositions of FC elements #
|
|
324
|
+
###########################################################################
|
|
325
|
+
|
|
326
|
+
# Descents
|
|
327
|
+
|
|
328
|
+
# The following three functions deal with descents of FC elements.
|
|
329
|
+
# Descents of FC elements are easier to find than those of general
|
|
330
|
+
# elements, but they are also extremely useful: repeated searching of
|
|
331
|
+
# descents is essential to finding Cartier Foata forms and coset
|
|
332
|
+
# decompositions of FC elements; see :func:`cartier_foata_form` and
|
|
333
|
+
# :func:`coset_decomposition`.
|
|
334
|
+
|
|
335
|
+
def find_descent(self, s, side='left'):
|
|
336
|
+
r"""
|
|
337
|
+
Check if ``s`` is a descent of ``self`` and find its position if so.
|
|
338
|
+
|
|
339
|
+
A generator `s` is called a left or right descent of an element `w` if
|
|
340
|
+
`l(sw)` or `l(ws)` is smaller than `l(w)`, respectively. If `w` is FC,
|
|
341
|
+
then `s` is a left descent of `w` if and only if `s` appears to in the
|
|
342
|
+
word and every generator to the left of the leftmost `s` in the word
|
|
343
|
+
commutes with `s`. A similar characterization exists for right descents
|
|
344
|
+
of FC elements.
|
|
345
|
+
|
|
346
|
+
INPUT:
|
|
347
|
+
|
|
348
|
+
- ``s`` -- integer representing a generator of the Coxeter system
|
|
349
|
+
|
|
350
|
+
- ``side`` -- string (default: ``'left'``); if the argument is set to
|
|
351
|
+
'right', the function checks if ``s`` is a right descent of ``self``
|
|
352
|
+
and finds the index of the rightmost occurrence of ``s`` if so
|
|
353
|
+
|
|
354
|
+
OUTPUT:
|
|
355
|
+
|
|
356
|
+
Determine if the generator ``s`` is a left descent of ``self``; return
|
|
357
|
+
the index of the leftmost occurrence of ``s`` in ``self`` if so and
|
|
358
|
+
return ``None`` if not.
|
|
359
|
+
|
|
360
|
+
EXAMPLES::
|
|
361
|
+
|
|
362
|
+
sage: FC = CoxeterGroup(['B', 5]).fully_commutative_elements()
|
|
363
|
+
sage: w = FC([1, 4, 3, 5, 2, 4, 3])
|
|
364
|
+
sage: w.find_descent(1)
|
|
365
|
+
0
|
|
366
|
+
sage: w.find_descent(1, side='right')
|
|
367
|
+
<BLANKLINE>
|
|
368
|
+
sage: w.find_descent(4)
|
|
369
|
+
1
|
|
370
|
+
sage: w.find_descent(4, side='right')
|
|
371
|
+
<BLANKLINE>
|
|
372
|
+
sage: w.find_descent(3)
|
|
373
|
+
<BLANKLINE>
|
|
374
|
+
"""
|
|
375
|
+
m = self.parent().coxeter_group().coxeter_matrix()
|
|
376
|
+
view = list(self) if side == 'left' else self[::-1]
|
|
377
|
+
for i, t in enumerate(view):
|
|
378
|
+
if t == s and not any(m[x, t] > 2 for x in view[:i]):
|
|
379
|
+
return i
|
|
380
|
+
return None
|
|
381
|
+
|
|
382
|
+
def has_descent(self, s, side='left') -> bool:
|
|
383
|
+
r"""
|
|
384
|
+
Determine if ``s`` is a descent on the appropriate side of ``self``.
|
|
385
|
+
|
|
386
|
+
INPUT:
|
|
387
|
+
|
|
388
|
+
- ``side`` -- string (default: ``'left'``); if set to 'right', determine
|
|
389
|
+
if ``self`` has ``s`` as a right descent
|
|
390
|
+
|
|
391
|
+
OUTPUT: boolean
|
|
392
|
+
|
|
393
|
+
EXAMPLES::
|
|
394
|
+
|
|
395
|
+
sage: FC = CoxeterGroup(['B', 5]).fully_commutative_elements()
|
|
396
|
+
sage: w = FC([1, 4, 3, 5, 2, 4, 3])
|
|
397
|
+
sage: w.has_descent(1)
|
|
398
|
+
True
|
|
399
|
+
sage: w.has_descent(1, side='right')
|
|
400
|
+
False
|
|
401
|
+
sage: w.has_descent(4)
|
|
402
|
+
True
|
|
403
|
+
sage: w.has_descent(4, side='right')
|
|
404
|
+
False
|
|
405
|
+
|
|
406
|
+
.. SEEALSO:: :func:`find_descent`
|
|
407
|
+
"""
|
|
408
|
+
return self.find_descent(s, side=side) is not None
|
|
409
|
+
|
|
410
|
+
def descents(self, side='left'):
|
|
411
|
+
r"""
|
|
412
|
+
Obtain the set of descents on the appropriate side of ``self``.
|
|
413
|
+
|
|
414
|
+
INPUT:
|
|
415
|
+
|
|
416
|
+
- ``side`` -- string (default: ``'left'``); if set to 'right', find the
|
|
417
|
+
right descents
|
|
418
|
+
|
|
419
|
+
A generator `s` is called a left or right descent of an element `w` if
|
|
420
|
+
`l(sw)` or `l(ws)` is smaller than `l(w)`, respectively. If `w` is FC,
|
|
421
|
+
then `s` is a left descent of `w` if and only if `s` appears to in the
|
|
422
|
+
word and every generator to the left of the leftmost `s` in the word
|
|
423
|
+
commutes with `s`. A similar characterization exists for right descents
|
|
424
|
+
of FC elements.
|
|
425
|
+
|
|
426
|
+
EXAMPLES::
|
|
427
|
+
|
|
428
|
+
sage: FC = CoxeterGroup(['B', 5]).fully_commutative_elements()
|
|
429
|
+
sage: w = FC([1, 4, 3, 5, 2, 4, 3])
|
|
430
|
+
sage: sorted(w.descents())
|
|
431
|
+
[1, 4]
|
|
432
|
+
sage: w.descents(side='right')
|
|
433
|
+
{3}
|
|
434
|
+
sage: FC = CoxeterGroup(['A', 5]).fully_commutative_elements()
|
|
435
|
+
sage: sorted(FC([1, 4, 3, 5, 2, 4, 3]).descents())
|
|
436
|
+
[1, 4]
|
|
437
|
+
|
|
438
|
+
.. SEEALSO:: :func:`find_descent`
|
|
439
|
+
"""
|
|
440
|
+
view = list(self) if side == 'left' else self[::-1]
|
|
441
|
+
m = self.parent().coxeter_group().coxeter_matrix()
|
|
442
|
+
out = set()
|
|
443
|
+
for (i, t) in enumerate(view):
|
|
444
|
+
if not any(m[x, t] > 2 for x in view[:i]):
|
|
445
|
+
out.add(t)
|
|
446
|
+
return out
|
|
447
|
+
|
|
448
|
+
# Coset decompositions
|
|
449
|
+
def coset_decomposition(self, J, side='left'):
|
|
450
|
+
r"""
|
|
451
|
+
Return the coset decomposition of ``self`` with respect to the parabolic
|
|
452
|
+
subgroup generated by ``J``.
|
|
453
|
+
|
|
454
|
+
INPUT:
|
|
455
|
+
|
|
456
|
+
- ``J`` -- subset of the generating set `S` of the Coxeter system
|
|
457
|
+
|
|
458
|
+
- ``side`` -- string (default: ``'left'``); if the value is set to
|
|
459
|
+
'right', then the function returns the tuple `(w'^J, w'_J)` from the
|
|
460
|
+
coset decomposition `w = w'^J \cdot w'_J` of `w` with respect to `J`
|
|
461
|
+
|
|
462
|
+
OUTPUT:
|
|
463
|
+
|
|
464
|
+
The tuple of elements `(w_J, w^J)` such that `w=w_J \cdot w^J`, `w_J` is
|
|
465
|
+
generated by the elements in `J`, and `w^J` has no left descent from
|
|
466
|
+
`J`. This tuple is unique and satisfies the equation `\ell(w) =
|
|
467
|
+
\ell(w_J) + \ell(w^J)`, where `\ell` denotes Coxeter length, by general
|
|
468
|
+
theory; see Proposition 2.4.4 of [BB2005]_.
|
|
469
|
+
|
|
470
|
+
EXAMPLES::
|
|
471
|
+
|
|
472
|
+
sage: FC = CoxeterGroup(['B', 6]).fully_commutative_elements()
|
|
473
|
+
sage: w = FC([1, 6, 2, 5, 4, 6, 5])
|
|
474
|
+
sage: w.coset_decomposition({1})
|
|
475
|
+
([1], [6, 2, 5, 4, 6, 5])
|
|
476
|
+
sage: w.coset_decomposition({1}, side = 'right')
|
|
477
|
+
([1, 6, 2, 5, 4, 6, 5], [])
|
|
478
|
+
sage: w.coset_decomposition({5, 6})
|
|
479
|
+
([6, 5, 6], [1, 2, 4, 5])
|
|
480
|
+
sage: w.coset_decomposition({5, 6}, side='right')
|
|
481
|
+
([1, 6, 2, 5, 4], [6, 5])
|
|
482
|
+
|
|
483
|
+
.. NOTE::
|
|
484
|
+
|
|
485
|
+
The factor `w_J` of the coset decomposition `w = w_J \cdot
|
|
486
|
+
w^J` can be obtained by greedily "pulling left descents of `w` that
|
|
487
|
+
are in `J` to the left"; see the proof of [BB2005]_. This greedy
|
|
488
|
+
algorithm works for all elements in Coxeter group, but it becomes
|
|
489
|
+
especially simple for FC elements because descents are easier to
|
|
490
|
+
find for FC elements.
|
|
491
|
+
"""
|
|
492
|
+
string = [] # to record w_J
|
|
493
|
+
remaining = self.clone() # to record w^J
|
|
494
|
+
|
|
495
|
+
if side == 'right':
|
|
496
|
+
remaining._set_list(remaining[::-1])
|
|
497
|
+
|
|
498
|
+
while True:
|
|
499
|
+
x = next((x for x in J if remaining.has_descent(x, side='left')), None)
|
|
500
|
+
if x is not None:
|
|
501
|
+
string.append(x)
|
|
502
|
+
remaining.remove(x)
|
|
503
|
+
else:
|
|
504
|
+
break
|
|
505
|
+
|
|
506
|
+
if side == 'right':
|
|
507
|
+
remaining._set_list(remaining[::-1])
|
|
508
|
+
string = string[::-1]
|
|
509
|
+
|
|
510
|
+
string = self.parent().element_class(self.parent(), string, check=False)
|
|
511
|
+
remaining.set_immutable()
|
|
512
|
+
|
|
513
|
+
return (string, remaining) if side == 'left' else (remaining, string)
|
|
514
|
+
|
|
515
|
+
###########################################################################
|
|
516
|
+
# Application of coset decompositions, I: New FC elements from old #
|
|
517
|
+
###########################################################################
|
|
518
|
+
|
|
519
|
+
# The following function uses coset decompositions and will help us
|
|
520
|
+
# generate all FC elements in a Coxeter group by induction on length.
|
|
521
|
+
def _still_reduced_fc_after_prepending(self, s):
|
|
522
|
+
r"""
|
|
523
|
+
Determine if ``self`` prepended with ``s`` is still a reduced word of an
|
|
524
|
+
FC element in the Coxeter system.
|
|
525
|
+
|
|
526
|
+
INPUT:
|
|
527
|
+
|
|
528
|
+
- ``s`` -- integer representing a generator of the Coxeter system
|
|
529
|
+
- ``self`` -- a reduced word of an FC element
|
|
530
|
+
|
|
531
|
+
EXAMPLES:
|
|
532
|
+
|
|
533
|
+
Consider the FC element `w = 12` in the group `B_3`::
|
|
534
|
+
|
|
535
|
+
sage: FCB3 = CoxeterGroup(['B', 3]).fully_commutative_elements()
|
|
536
|
+
sage: w = FCB3([1,2])
|
|
537
|
+
|
|
538
|
+
When `s=1`, `sw` is 112, which is not reduced::
|
|
539
|
+
|
|
540
|
+
sage: w._still_reduced_fc_after_prepending(1)
|
|
541
|
+
False
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
When `s=2`, `sw` is 212, which is reduced but not FC::
|
|
545
|
+
|
|
546
|
+
sage: w._still_reduced_fc_after_prepending(2)
|
|
547
|
+
False
|
|
548
|
+
|
|
549
|
+
When `s=31, `sw` is 312, which is reduced and FC::
|
|
550
|
+
|
|
551
|
+
sage: w._still_reduced_fc_after_prepending(3)
|
|
552
|
+
True
|
|
553
|
+
|
|
554
|
+
More examples::
|
|
555
|
+
|
|
556
|
+
sage: u = FCB3([3,1,2])
|
|
557
|
+
sage: u._still_reduced_fc_after_prepending(1)
|
|
558
|
+
False
|
|
559
|
+
sage: u._still_reduced_fc_after_prepending(2)
|
|
560
|
+
True
|
|
561
|
+
sage: u._still_reduced_fc_after_prepending(3)
|
|
562
|
+
False
|
|
563
|
+
|
|
564
|
+
sage: FCA5 = CoxeterGroup(['A', 5]).fully_commutative_elements()
|
|
565
|
+
sage: w = FCA5([2,4,1,3,2,5])
|
|
566
|
+
sage: w._still_reduced_fc_after_prepending(5)
|
|
567
|
+
False
|
|
568
|
+
|
|
569
|
+
.. NOTE::
|
|
570
|
+
|
|
571
|
+
If `w` is a reduced word of an element, then the concatenation
|
|
572
|
+
`sw` is still a reduced word if and only if `s` is not a left
|
|
573
|
+
descent of `w` by general Coxeter group theory. So now assume `w`
|
|
574
|
+
is a reduced word of an FC element and `s` is not a left descent
|
|
575
|
+
`w`. In this case, Lemma 4.1 of [Ste1996]_ implies that `sw` is
|
|
576
|
+
not a reduced word of an FC element if and only if some letter in
|
|
577
|
+
`w` does not commute with `s` and the following conditions hold
|
|
578
|
+
simultaneously for the leftmost such letter `t`:
|
|
579
|
+
|
|
580
|
+
(1) `t` is left descent of the word `u_1` obtained by removing
|
|
581
|
+
all letters to the left of the aforementioned `t` from `w`;
|
|
582
|
+
(this condition is automatically true by definition of `u_1`)
|
|
583
|
+
|
|
584
|
+
(2) `s` is left descent of the word `u_2` obtained by
|
|
585
|
+
removing the leftmost `t` from `u_1`;
|
|
586
|
+
|
|
587
|
+
(3) `t` is left descent of the word `u_3` obtained by
|
|
588
|
+
removing the leftmost `s` from `u_2`;
|
|
589
|
+
|
|
590
|
+
...
|
|
591
|
+
|
|
592
|
+
(m-1) the appropriate element in `\{s, t\}` is a left descent
|
|
593
|
+
of the word `u_{m-1}` obtained by removing the leftmost letter
|
|
594
|
+
required to be a descent in Condition (m-2) from `u_{m-2}`.
|
|
595
|
+
|
|
596
|
+
In the last example above, we have `s=5`, `t=4`, Condition (1)
|
|
597
|
+
holds, but Condition (2) fails, therefore `5w` is still a
|
|
598
|
+
reduced word of an FC element.
|
|
599
|
+
|
|
600
|
+
Note that the conditions (1)--(m-1) are equivalent to the
|
|
601
|
+
condition that the parabolic factor `u_J` from the coset
|
|
602
|
+
decomposition `u_1 = u_J \cdot u^J` of `u_1` with respect to
|
|
603
|
+
`J := \{s, t\}` is the element `tst...` of length `m(s,t)-1`.
|
|
604
|
+
|
|
605
|
+
REFERENCES:
|
|
606
|
+
|
|
607
|
+
See Lemma 4.1 of [Ste1996]_.
|
|
608
|
+
"""
|
|
609
|
+
m = self.parent().coxeter_group().coxeter_matrix()
|
|
610
|
+
if self.has_descent(s):
|
|
611
|
+
return False
|
|
612
|
+
|
|
613
|
+
# Find the first letter in that doesn't commute with s.
|
|
614
|
+
try:
|
|
615
|
+
j, t = next((i, x) for i, x in enumerate(self) if m[s, x] >= 3)
|
|
616
|
+
except StopIteration:
|
|
617
|
+
return True
|
|
618
|
+
|
|
619
|
+
u = self.clone()
|
|
620
|
+
u._set_list(self[j:])
|
|
621
|
+
x, _ = u.coset_decomposition({s, t})
|
|
622
|
+
return len(x) != m[s, t] - 1
|
|
623
|
+
|
|
624
|
+
###########################################################################
|
|
625
|
+
# Application of coset decompositions, II: Star operations #
|
|
626
|
+
###########################################################################
|
|
627
|
+
|
|
628
|
+
# Generalized star operations
|
|
629
|
+
def star_operation(self, J, direction, side='left'):
|
|
630
|
+
r"""
|
|
631
|
+
Apply a star operation on ``self`` relative to two noncommuting
|
|
632
|
+
generators.
|
|
633
|
+
|
|
634
|
+
Star operations were first defined on elements of Coxeter groups by
|
|
635
|
+
Kazhdan and Lusztig in [KL1979]_ with respect to pair of generators
|
|
636
|
+
`s,t` such that `m(s,t)=3`. Later, Lusztig generalized the definition in
|
|
637
|
+
[Lus1985]_, via coset decompositions, to allow star operations with
|
|
638
|
+
respect to any pair of generators `s,t` such that `m(s,t)\ge 3`. Given
|
|
639
|
+
such a pair, we can potentially perform four types of star operations
|
|
640
|
+
corresponding to all combinations of a 'direction' and a 'side': upper
|
|
641
|
+
left, lower left, upper right and lower right; see [Gre2006]_.
|
|
642
|
+
|
|
643
|
+
Let `w` be an element in `W` and let `J` be any pair `\{s, t\}` of
|
|
644
|
+
noncommuting generators in `S`. Consider the coset decomposition `w =
|
|
645
|
+
w_J \cdot {}^J w` of `w` relative to `J`. Then an upper left star
|
|
646
|
+
operation is defined on `w` if and only if `1 \le l(w_J) \le m(s,t)-2`;
|
|
647
|
+
when this is the case, the operation returns `x\cdot w_J\cdot w^J` where
|
|
648
|
+
`x` is the letter `J` different from the leftmost letter of `w_J`. A
|
|
649
|
+
lower left star operation is defined on `w` if and only if `2 \le l(w_J)
|
|
650
|
+
\le m(s,t)-1`; when this is the case, the operation removes the leftmost
|
|
651
|
+
letter of `w_J` from `w`. Similar facts hold for right star operations.
|
|
652
|
+
See [Gre2006]_.
|
|
653
|
+
|
|
654
|
+
The facts of the previous paragraph hold in general, even if `w` is not
|
|
655
|
+
FC. Note that if `f` is a star operation of any kind, then for every
|
|
656
|
+
element `w \in W`, the elements `w` and `f(w)` are either both FC or
|
|
657
|
+
both not FC.
|
|
658
|
+
|
|
659
|
+
INPUT:
|
|
660
|
+
|
|
661
|
+
- ``J`` -- set of two integers representing two noncommuting
|
|
662
|
+
generators of the Coxeter system
|
|
663
|
+
|
|
664
|
+
- ``direction`` -- string, ``'upper'`` or ``'lower'``; the function
|
|
665
|
+
performs an upper or lower star operation according to ``direction``
|
|
666
|
+
|
|
667
|
+
- ``side`` -- string (default: ``'left'``); if this is set to 'right',
|
|
668
|
+
the function performs a right star operation
|
|
669
|
+
|
|
670
|
+
OUTPUT:
|
|
671
|
+
|
|
672
|
+
The Cartier--Foata form of the result of the star operation if the
|
|
673
|
+
operation is defined on ``self``, ``None`` otherwise.
|
|
674
|
+
|
|
675
|
+
EXAMPLES:
|
|
676
|
+
|
|
677
|
+
We will compute all star operations on the following FC element in type
|
|
678
|
+
`B_6` relative to `J = \{5, 6\}`::
|
|
679
|
+
|
|
680
|
+
sage: FC = CoxeterGroup(['B', 6]).fully_commutative_elements()
|
|
681
|
+
sage: w = FC([1, 6, 2, 5, 4, 6, 5])
|
|
682
|
+
|
|
683
|
+
Whether and how a left star operations can be applied depend on the
|
|
684
|
+
coset decomposition `w = w_J \cdot w^J`::
|
|
685
|
+
|
|
686
|
+
sage: w.coset_decomposition({5, 6})
|
|
687
|
+
([6, 5, 6], [1, 2, 4, 5])
|
|
688
|
+
|
|
689
|
+
Only the lower star operation is defined on the left on `w`::
|
|
690
|
+
|
|
691
|
+
sage: w.star_operation({5,6}, 'upper')
|
|
692
|
+
<BLANKLINE>
|
|
693
|
+
sage: w.star_operation({5,6}, 'lower')
|
|
694
|
+
[1, 5, 2, 4, 6, 5]
|
|
695
|
+
|
|
696
|
+
Whether and how a right star operations can be applied depend on the
|
|
697
|
+
coset decomposition `w = w^J \cdot w_J`::
|
|
698
|
+
|
|
699
|
+
sage: w.coset_decomposition({5, 6}, side='right')
|
|
700
|
+
([1, 6, 2, 5, 4], [6, 5])
|
|
701
|
+
|
|
702
|
+
Both types of right star operations on defined for this example::
|
|
703
|
+
|
|
704
|
+
sage: w.star_operation({5, 6}, 'upper', side='right')
|
|
705
|
+
[1, 6, 2, 5, 4, 6, 5, 6]
|
|
706
|
+
|
|
707
|
+
sage: w.star_operation({5, 6}, 'lower', side='right')
|
|
708
|
+
[1, 6, 2, 5, 4, 6]
|
|
709
|
+
"""
|
|
710
|
+
assert len(J) == 2, 'J needs to contain a pair of generators.'
|
|
711
|
+
s, t = J
|
|
712
|
+
mst = self.parent().coxeter_group().coxeter_matrix()[s, t]
|
|
713
|
+
|
|
714
|
+
# Perform the coset decomposition on the specified side:
|
|
715
|
+
if side == 'left':
|
|
716
|
+
(string, remaining) = self.coset_decomposition(J, side=side)
|
|
717
|
+
elif side == 'right':
|
|
718
|
+
(remaining, string) = self.coset_decomposition(J, side=side)
|
|
719
|
+
|
|
720
|
+
cur_string = list(string)
|
|
721
|
+
|
|
722
|
+
# From the coset decomposition, perform the upper or lower operation:
|
|
723
|
+
if direction == 'lower' and 2 <= len(string) <= mst - 1:
|
|
724
|
+
# the lower star operation
|
|
725
|
+
new_string = cur_string[1:] if side == 'left' else cur_string[:-1]
|
|
726
|
+
elif direction == 'upper' and 1 <= len(string) <= mst - 2:
|
|
727
|
+
# the upper star operation
|
|
728
|
+
ending_letter = cur_string[0] if side == 'left' else cur_string[-1]
|
|
729
|
+
other = next(x for x in J if x != ending_letter)
|
|
730
|
+
new_string = [other] + cur_string if side == 'left' else cur_string + [other]
|
|
731
|
+
else:
|
|
732
|
+
return None
|
|
733
|
+
|
|
734
|
+
# concatenate w_J and w^J in the appropriate order
|
|
735
|
+
combined_data = new_string + list(remaining) if side == 'left' else list(remaining) + new_string
|
|
736
|
+
|
|
737
|
+
# return the result of the star operation in its canonical form
|
|
738
|
+
return self.parent().element_class(self.parent(), combined_data, check=False)
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
class FullyCommutativeElements(UniqueRepresentation, Parent):
|
|
742
|
+
r"""
|
|
743
|
+
Class for the set of fully commutative (FC) elements of a Coxeter system.
|
|
744
|
+
|
|
745
|
+
Coxeter systems with finitely many FC elements, or *FC-finite* Coxeter
|
|
746
|
+
systems, are classified by Stembridge in [Ste1996]_. They fall into seven
|
|
747
|
+
families, namely the groups of types `A_n, B_n, D_n, E_n, F_n, H_n` and
|
|
748
|
+
`I_2(m)`.
|
|
749
|
+
|
|
750
|
+
INPUT:
|
|
751
|
+
|
|
752
|
+
- ``data`` -- CoxeterMatrix, CartanType, or the usual datum that can is
|
|
753
|
+
taken in the constructors for these classes (see
|
|
754
|
+
:func:`sage.combinat.root_system.coxeter_group.CoxeterGroup`)
|
|
755
|
+
|
|
756
|
+
OUTPUT:
|
|
757
|
+
|
|
758
|
+
The class of fully commutative elements in the Coxeter group constructed
|
|
759
|
+
from ``data``. This will belong to the category of enumerated sets. If the
|
|
760
|
+
Coxeter data corresponds to a Cartan type, the category is further refined
|
|
761
|
+
to either finite enumerated sets or infinite enumerated sets depending on
|
|
762
|
+
whether the Coxeter group is FC-finite; the refinement is not carried out
|
|
763
|
+
if ``data`` is a Coxeter matrix not corresponding to a Cartan type.
|
|
764
|
+
|
|
765
|
+
.. TODO::
|
|
766
|
+
|
|
767
|
+
It would be ideal to implement the aforementioned refinement to finite
|
|
768
|
+
and infinite enumerated sets for all possible ``data``, regardless of
|
|
769
|
+
whether it corresponds to a Cartan type. Doing so requires determining
|
|
770
|
+
if an arbitrary Coxeter matrix corresponds to a Cartan type. It may be
|
|
771
|
+
best to address this issue in ``sage.combinat.root_system``. On the other
|
|
772
|
+
hand, the refinement in the general case may be unnecessary in light of
|
|
773
|
+
the fact that Stembridge's classification of FC-finite groups contains
|
|
774
|
+
a very small number of easily-recognizable families.
|
|
775
|
+
|
|
776
|
+
EXAMPLES:
|
|
777
|
+
|
|
778
|
+
Create the enumerate set of fully commutative elements in `B_3`::
|
|
779
|
+
|
|
780
|
+
sage: FC = CoxeterGroup(['B', 3]).fully_commutative_elements(); FC
|
|
781
|
+
Fully commutative elements of Finite Coxeter group over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? with Coxeter matrix:
|
|
782
|
+
[1 3 2]
|
|
783
|
+
[3 1 4]
|
|
784
|
+
[2 4 1]
|
|
785
|
+
|
|
786
|
+
Construct elements::
|
|
787
|
+
|
|
788
|
+
sage: FC([])
|
|
789
|
+
[]
|
|
790
|
+
sage: FC([1,2])
|
|
791
|
+
[1, 2]
|
|
792
|
+
sage: FC([2,3,2])
|
|
793
|
+
[2, 3, 2]
|
|
794
|
+
sage: FC([3,2,3])
|
|
795
|
+
[3, 2, 3]
|
|
796
|
+
|
|
797
|
+
Elements are normalized to Cartier--Foata normal form upon construction::
|
|
798
|
+
|
|
799
|
+
sage: FC([3,1])
|
|
800
|
+
[1, 3]
|
|
801
|
+
sage: FC([2,3,1])
|
|
802
|
+
[2, 1, 3]
|
|
803
|
+
sage: FC([1,3]) == FC([3,1])
|
|
804
|
+
True
|
|
805
|
+
|
|
806
|
+
Attempting to create an element from an input that is not the reduced word
|
|
807
|
+
of a fully commutative element throws a :exc:`ValueError`::
|
|
808
|
+
|
|
809
|
+
sage: FC([1,2,1])
|
|
810
|
+
Traceback (most recent call last):
|
|
811
|
+
...
|
|
812
|
+
ValueError: the input is not a reduced word of a fully commutative element
|
|
813
|
+
sage: FC([2,3,2,3])
|
|
814
|
+
Traceback (most recent call last):
|
|
815
|
+
...
|
|
816
|
+
ValueError: the input is not a reduced word of a fully commutative element
|
|
817
|
+
|
|
818
|
+
Enumerate the FC elements in `A_3`::
|
|
819
|
+
|
|
820
|
+
sage: FCA3 = CoxeterGroup(['A', 3]).fully_commutative_elements()
|
|
821
|
+
sage: FCA3.category()
|
|
822
|
+
Category of finite enumerated sets
|
|
823
|
+
sage: FCA3.list()
|
|
824
|
+
[[],
|
|
825
|
+
[1],
|
|
826
|
+
[2],
|
|
827
|
+
[3],
|
|
828
|
+
[2, 1],
|
|
829
|
+
[1, 3],
|
|
830
|
+
[1, 2],
|
|
831
|
+
[3, 2],
|
|
832
|
+
[2, 3],
|
|
833
|
+
[3, 2, 1],
|
|
834
|
+
[2, 1, 3],
|
|
835
|
+
[1, 3, 2],
|
|
836
|
+
[1, 2, 3],
|
|
837
|
+
[2, 1, 3, 2]]
|
|
838
|
+
|
|
839
|
+
Count the FC elements in `B_8`::
|
|
840
|
+
|
|
841
|
+
sage: FCB8 = CoxeterGroup(['B', 8]).fully_commutative_elements()
|
|
842
|
+
sage: len(FCB8) # long time (7 seconds)
|
|
843
|
+
14299
|
|
844
|
+
|
|
845
|
+
Iterate through the FC elements of length up to 2 in the non-FC-finite group
|
|
846
|
+
affine `A_2`::
|
|
847
|
+
|
|
848
|
+
sage: FCAffineA2 = CoxeterGroup(['A', 2, 1]).fully_commutative_elements()
|
|
849
|
+
sage: FCAffineA2.category()
|
|
850
|
+
Category of infinite enumerated sets
|
|
851
|
+
sage: list(FCAffineA2.iterate_to_length(2))
|
|
852
|
+
[[], [0], [1], [2], [1, 0], [2, 0], [0, 1], [2, 1], [0, 2], [1, 2]]
|
|
853
|
+
|
|
854
|
+
The cardinality of the set is determined from the classification of
|
|
855
|
+
FC-finite Coxeter groups::
|
|
856
|
+
|
|
857
|
+
sage: CoxeterGroup('A2').fully_commutative_elements().category()
|
|
858
|
+
Category of finite enumerated sets
|
|
859
|
+
sage: CoxeterGroup('B7').fully_commutative_elements().category()
|
|
860
|
+
Category of finite enumerated sets
|
|
861
|
+
sage: CoxeterGroup('A3~').fully_commutative_elements().category()
|
|
862
|
+
Category of infinite enumerated sets
|
|
863
|
+
sage: CoxeterGroup('F4~').fully_commutative_elements().category()
|
|
864
|
+
Category of finite enumerated sets
|
|
865
|
+
sage: CoxeterGroup('E8~').fully_commutative_elements().category()
|
|
866
|
+
Category of finite enumerated sets
|
|
867
|
+
sage: CoxeterGroup('F4~xE8~').fully_commutative_elements().category()
|
|
868
|
+
Category of finite enumerated sets
|
|
869
|
+
sage: CoxeterGroup('B4~xE8~').fully_commutative_elements().category()
|
|
870
|
+
Category of infinite enumerated sets
|
|
871
|
+
"""
|
|
872
|
+
@staticmethod
|
|
873
|
+
def __classcall_private__(cls, data):
|
|
874
|
+
r"""
|
|
875
|
+
EXAMPLES::
|
|
876
|
+
|
|
877
|
+
sage: from sage.combinat.fully_commutative_elements import FullyCommutativeElements
|
|
878
|
+
sage: x1 = FullyCommutativeElements(CoxeterGroup(['B', 3])); x1
|
|
879
|
+
Fully commutative elements of Finite Coxeter group over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? with Coxeter matrix:
|
|
880
|
+
[1 3 2]
|
|
881
|
+
[3 1 4]
|
|
882
|
+
[2 4 1]
|
|
883
|
+
sage: x2 = FullyCommutativeElements(['B', 3]); x2
|
|
884
|
+
Fully commutative elements of Finite Coxeter group over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? with Coxeter matrix:
|
|
885
|
+
[1 3 2]
|
|
886
|
+
[3 1 4]
|
|
887
|
+
[2 4 1]
|
|
888
|
+
sage: x3 = FullyCommutativeElements(CoxeterMatrix([[1, 3, 2], [3, 1, 4], [2, 4, 1]])); x3
|
|
889
|
+
Fully commutative elements of Finite Coxeter group over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? with Coxeter matrix:
|
|
890
|
+
[1 3 2]
|
|
891
|
+
[3 1 4]
|
|
892
|
+
[2 4 1]
|
|
893
|
+
sage: x1 is x2 is x3
|
|
894
|
+
True
|
|
895
|
+
sage: FullyCommutativeElements(CartanType(['B', 3]).relabel({1: 3, 2: 2, 3: 1}))
|
|
896
|
+
Fully commutative elements of Finite Coxeter group over Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095? with Coxeter matrix:
|
|
897
|
+
[1 4 2]
|
|
898
|
+
[4 1 3]
|
|
899
|
+
[2 3 1]
|
|
900
|
+
sage: m = CoxeterMatrix([(1, 5, 2, 2, 2), (5, 1, 3, 2, 2), (2, 3, 1, 3, 2), (2, 2, 3, 1, 3), (2, 2, 2, 3, 1)]); FullyCommutativeElements(m)
|
|
901
|
+
Fully commutative elements of Coxeter group over Universal Cyclotomic Field with Coxeter matrix:
|
|
902
|
+
[1 5 2 2 2]
|
|
903
|
+
[5 1 3 2 2]
|
|
904
|
+
[2 3 1 3 2]
|
|
905
|
+
[2 2 3 1 3]
|
|
906
|
+
[2 2 2 3 1]
|
|
907
|
+
"""
|
|
908
|
+
if data in CoxeterGroups():
|
|
909
|
+
group = data
|
|
910
|
+
else:
|
|
911
|
+
group = CoxeterGroup(data)
|
|
912
|
+
return super().__classcall__(cls, group)
|
|
913
|
+
|
|
914
|
+
def __init__(self, coxeter_group):
|
|
915
|
+
r"""
|
|
916
|
+
EXAMPLES::
|
|
917
|
+
|
|
918
|
+
sage: from sage.combinat.fully_commutative_elements import FullyCommutativeElements
|
|
919
|
+
sage: FC = FullyCommutativeElements(CoxeterGroup(['H', 4]))
|
|
920
|
+
sage: TestSuite(FC).run()
|
|
921
|
+
"""
|
|
922
|
+
self._coxeter_group = coxeter_group
|
|
923
|
+
|
|
924
|
+
# Start with the category of enumerated sets and refine it to finite or
|
|
925
|
+
# infinite enumerated sets for Coxeter groups of Cartan types.
|
|
926
|
+
category = EnumeratedSets()
|
|
927
|
+
|
|
928
|
+
coxeter_type = self._coxeter_group.coxeter_type()
|
|
929
|
+
|
|
930
|
+
if not isinstance(coxeter_type, CoxeterMatrix):
|
|
931
|
+
# This case handles all finite or affine Coxeter types (or products thereof)
|
|
932
|
+
ctypes = [coxeter_type] if coxeter_type.is_irreducible() else coxeter_type.component_types()
|
|
933
|
+
|
|
934
|
+
is_finite = True
|
|
935
|
+
# this type will be FC-finite if and only if each component type is:
|
|
936
|
+
for ctype in ctypes:
|
|
937
|
+
family, rank = ctype.type(), ctype.rank()
|
|
938
|
+
# Finite Coxeter groups are certainly FC-finite.
|
|
939
|
+
# Of the affine Coxeter groups only the groups affine `F_4` and
|
|
940
|
+
# affine `E_8` are FC-finite; they have rank 5 and rank 9 and
|
|
941
|
+
# correspond to the groups `F_5` and `E_9` in [Ste1996]_.
|
|
942
|
+
if not (ctype.is_finite() or (family == 'F' and rank == 5) or (family == 'E' and rank == 9)):
|
|
943
|
+
is_finite = False
|
|
944
|
+
break
|
|
945
|
+
|
|
946
|
+
if is_finite:
|
|
947
|
+
category = category.Finite()
|
|
948
|
+
else:
|
|
949
|
+
category = category.Infinite()
|
|
950
|
+
else:
|
|
951
|
+
# coxeter_type is a plain CoxeterMatrix, i.e. it is an indefinite
|
|
952
|
+
# type, and we do not specify any refinement. (Note that this
|
|
953
|
+
# includes groups of the form E_n (n>9), F_n (n>5) and H_n (n>4)
|
|
954
|
+
# from [Ste1996]_ which are known to be FC-finite).
|
|
955
|
+
pass
|
|
956
|
+
|
|
957
|
+
Parent.__init__(self, category=category)
|
|
958
|
+
|
|
959
|
+
def _repr_(self):
|
|
960
|
+
r"""
|
|
961
|
+
EXAMPLES::
|
|
962
|
+
|
|
963
|
+
sage: CoxeterGroup(['H', 4]).fully_commutative_elements()
|
|
964
|
+
Fully commutative elements of Finite Coxeter group over Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790? with Coxeter matrix:
|
|
965
|
+
[1 3 2 2]
|
|
966
|
+
[3 1 3 2]
|
|
967
|
+
[2 3 1 5]
|
|
968
|
+
[2 2 5 1]
|
|
969
|
+
"""
|
|
970
|
+
return 'Fully commutative elements of {}'.format(str(self.coxeter_group()))
|
|
971
|
+
|
|
972
|
+
def _element_constructor_(self, lst):
|
|
973
|
+
r"""
|
|
974
|
+
TESTS::
|
|
975
|
+
|
|
976
|
+
sage: FC = CoxeterGroup(['A', 3]).fully_commutative_elements()
|
|
977
|
+
sage: FC([1, 2]) # indirect doctest
|
|
978
|
+
[1, 2]
|
|
979
|
+
"""
|
|
980
|
+
return self.element_class(self, lst)
|
|
981
|
+
|
|
982
|
+
Element = FullyCommutativeElement
|
|
983
|
+
|
|
984
|
+
def coxeter_group(self):
|
|
985
|
+
r"""
|
|
986
|
+
Obtain the Coxeter group associated with ``self``.
|
|
987
|
+
|
|
988
|
+
EXAMPLES::
|
|
989
|
+
|
|
990
|
+
sage: FCA3 = CoxeterGroup(['A', 3]).fully_commutative_elements()
|
|
991
|
+
sage: FCA3.coxeter_group()
|
|
992
|
+
Finite Coxeter group over Integer Ring with Coxeter matrix:
|
|
993
|
+
[1 3 2]
|
|
994
|
+
[3 1 3]
|
|
995
|
+
[2 3 1]
|
|
996
|
+
"""
|
|
997
|
+
return self._coxeter_group
|
|
998
|
+
|
|
999
|
+
def __iter__(self):
|
|
1000
|
+
r"""
|
|
1001
|
+
Enumerate the elements of this set by length, starting with the empty
|
|
1002
|
+
word and, if the group is FC-finite, ending with the longest fully
|
|
1003
|
+
commutative element.
|
|
1004
|
+
|
|
1005
|
+
TESTS::
|
|
1006
|
+
|
|
1007
|
+
sage: FC = CoxeterGroup(['A', 10]).fully_commutative_elements()
|
|
1008
|
+
sage: next(iter(FC)) # indirect doctest
|
|
1009
|
+
[]
|
|
1010
|
+
"""
|
|
1011
|
+
empty_word = self.element_class(self, [], check=False)
|
|
1012
|
+
letters = self.coxeter_group().index_set()
|
|
1013
|
+
|
|
1014
|
+
# To make the iterator deterministic, use a dictionary rather than a
|
|
1015
|
+
# set, for the keys are then ordered by default by Python 3.7+:
|
|
1016
|
+
recent_words = {empty_word: True}
|
|
1017
|
+
yield empty_word
|
|
1018
|
+
while recent_words:
|
|
1019
|
+
new_words = {}
|
|
1020
|
+
for w in recent_words:
|
|
1021
|
+
for s in letters:
|
|
1022
|
+
if w._still_reduced_fc_after_prepending(s):
|
|
1023
|
+
sw = self.element_class(
|
|
1024
|
+
self, [s] + list(w), check=False)
|
|
1025
|
+
# "Add" sw to the "set"
|
|
1026
|
+
new_words[sw] = True
|
|
1027
|
+
for w in new_words:
|
|
1028
|
+
yield w
|
|
1029
|
+
recent_words = new_words
|
|
1030
|
+
|
|
1031
|
+
def iterate_to_length(self, length):
|
|
1032
|
+
r"""
|
|
1033
|
+
Iterate through the elements of this class up to a maximum length.
|
|
1034
|
+
|
|
1035
|
+
INPUT:
|
|
1036
|
+
|
|
1037
|
+
- ``length`` -- integer; maximum length of element to generate
|
|
1038
|
+
|
|
1039
|
+
OUTPUT: generator for elements of ``self`` of length up to ``length``
|
|
1040
|
+
|
|
1041
|
+
EXAMPLES:
|
|
1042
|
+
|
|
1043
|
+
The following example produces all FC elements of length up to 2 in the
|
|
1044
|
+
group `A_3`::
|
|
1045
|
+
|
|
1046
|
+
sage: FCA3 = CoxeterGroup(['A', 3]).fully_commutative_elements()
|
|
1047
|
+
sage: list(FCA3.iterate_to_length(2))
|
|
1048
|
+
[[], [1], [2], [3], [2, 1], [1, 3], [1, 2], [3, 2], [2, 3]]
|
|
1049
|
+
|
|
1050
|
+
The lists for length 4 and 5 are the same since 4 is the maximum length
|
|
1051
|
+
of an FC element in `A_3`::
|
|
1052
|
+
|
|
1053
|
+
sage: list(FCA3.iterate_to_length(4))
|
|
1054
|
+
[[], [1], [2], [3], [2, 1], [1, 3], [1, 2], [3, 2], [2, 3],
|
|
1055
|
+
[3, 2, 1], [2, 1, 3], [1, 3, 2], [1, 2, 3], [2, 1, 3, 2]]
|
|
1056
|
+
sage: list(FCA3.iterate_to_length(5))
|
|
1057
|
+
[[], [1], [2], [3], [2, 1], [1, 3], [1, 2], [3, 2], [2, 3],
|
|
1058
|
+
[3, 2, 1], [2, 1, 3], [1, 3, 2], [1, 2, 3], [2, 1, 3, 2]]
|
|
1059
|
+
sage: list(FCA3.iterate_to_length(4)) == list(FCA3)
|
|
1060
|
+
True
|
|
1061
|
+
|
|
1062
|
+
The following example produces all FC elements of length up to 4 in the
|
|
1063
|
+
affine Weyl group `\tilde A_2`::
|
|
1064
|
+
|
|
1065
|
+
sage: FCAffineA2 = CoxeterGroup(['A', 2, 1]).fully_commutative_elements()
|
|
1066
|
+
sage: FCAffineA2.category()
|
|
1067
|
+
Category of infinite enumerated sets
|
|
1068
|
+
sage: list(FCAffineA2.iterate_to_length(4))
|
|
1069
|
+
[[], [0], [1], [2], [1, 0], [2, 0], [0, 1], [2, 1], [0, 2],
|
|
1070
|
+
[1, 2], [2, 1, 0], [1, 2, 0], [2, 0, 1], [0, 2, 1], [1, 0, 2],
|
|
1071
|
+
[0, 1, 2], [0, 2, 1, 0], [0, 1, 2, 0], [1, 2, 0, 1],
|
|
1072
|
+
[1, 0, 2, 1], [2, 1, 0, 2], [2, 0, 1, 2]]
|
|
1073
|
+
"""
|
|
1074
|
+
for w in self:
|
|
1075
|
+
if len(w) > length:
|
|
1076
|
+
break
|
|
1077
|
+
yield w
|