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,972 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
r"""
|
|
3
|
+
Module of trace monoids (free partially commutative monoids).
|
|
4
|
+
|
|
5
|
+
EXAMPLES:
|
|
6
|
+
|
|
7
|
+
We first create a trace monoid::
|
|
8
|
+
|
|
9
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
10
|
+
sage: M.<a,b,c> = TraceMonoid(I=(('a','c'), ('c','a'))); M
|
|
11
|
+
Trace monoid on 3 generators ([a], [b], [c]) with independence relation {{a, c}}
|
|
12
|
+
|
|
13
|
+
Different elements can be equal because of the partially
|
|
14
|
+
commutative multiplication::
|
|
15
|
+
|
|
16
|
+
sage: c * a * b == a * c * b
|
|
17
|
+
True
|
|
18
|
+
|
|
19
|
+
We check that it is a monoid::
|
|
20
|
+
|
|
21
|
+
sage: M in Monoids()
|
|
22
|
+
True
|
|
23
|
+
|
|
24
|
+
REFERENCES:
|
|
25
|
+
|
|
26
|
+
- :wikipedia:`Trace_monoid`
|
|
27
|
+
|
|
28
|
+
- https://ncatlab.org/nlab/show/trace+monoid
|
|
29
|
+
|
|
30
|
+
AUTHORS:
|
|
31
|
+
|
|
32
|
+
- Pavlo Tokariev (2019-05-31): initial version
|
|
33
|
+
"""
|
|
34
|
+
# ****************************************************************************
|
|
35
|
+
# Copyright (C) 2019 Pavlo Tokariev <pavlo.tokariev@gmail.com>
|
|
36
|
+
#
|
|
37
|
+
# This program is free software: you can redistribute it and/or modify
|
|
38
|
+
# it under the terms of the GNU General Public License as published by
|
|
39
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
40
|
+
# (at your option) any later version.
|
|
41
|
+
# https://www.gnu.org/licenses/
|
|
42
|
+
# ****************************************************************************
|
|
43
|
+
|
|
44
|
+
from itertools import repeat, chain, product
|
|
45
|
+
|
|
46
|
+
from sage.combinat.words.alphabet import Alphabet
|
|
47
|
+
from sage.misc.cachefunc import cached_method
|
|
48
|
+
from sage.misc.lazy_import import lazy_import
|
|
49
|
+
from sage.misc.misc_c import prod
|
|
50
|
+
from sage.monoids.free_monoid import FreeMonoid
|
|
51
|
+
from sage.monoids.monoid import Monoid_class
|
|
52
|
+
from sage.rings.integer_ring import ZZ
|
|
53
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
54
|
+
from sage.rings.power_series_ring import PowerSeriesRing
|
|
55
|
+
from sage.rings.infinity import infinity
|
|
56
|
+
from sage.structure.element import MonoidElement
|
|
57
|
+
from sage.structure.element_wrapper import ElementWrapper
|
|
58
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
59
|
+
|
|
60
|
+
lazy_import('sage.graphs.digraph', 'DiGraph')
|
|
61
|
+
lazy_import('sage.graphs.graph', 'Graph')
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class TraceMonoidElement(ElementWrapper, MonoidElement):
|
|
65
|
+
r"""
|
|
66
|
+
Element of a trace monoid, also known as a trace.
|
|
67
|
+
|
|
68
|
+
Elements of trace monoid is actually a equivalence classes
|
|
69
|
+
of related free monoid over some equivalence relation
|
|
70
|
+
that in the case is presented as independence relation.
|
|
71
|
+
|
|
72
|
+
.. RUBRIC:: Representative
|
|
73
|
+
|
|
74
|
+
We transform each trace to its lexicographic form for the
|
|
75
|
+
representative in the ambient free monoid. This is also used
|
|
76
|
+
for comparisons.
|
|
77
|
+
|
|
78
|
+
EXAMPLES::
|
|
79
|
+
|
|
80
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
81
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
82
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
83
|
+
sage: x = b * a * d * a * c * b
|
|
84
|
+
sage: x^3
|
|
85
|
+
[b*a^2*d*b^2*c*a^2*d*b^2*c*a^2*d*b*c]
|
|
86
|
+
sage: x^0
|
|
87
|
+
1
|
|
88
|
+
sage: x.lex_normal_form()
|
|
89
|
+
b*a^2*d*b*c
|
|
90
|
+
sage: x.foata_normal_form()
|
|
91
|
+
(b, a*d, a, b*c)
|
|
92
|
+
"""
|
|
93
|
+
def _repr_(self) -> str:
|
|
94
|
+
"""
|
|
95
|
+
Textual representation of ``self``.
|
|
96
|
+
|
|
97
|
+
TESTS::
|
|
98
|
+
|
|
99
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
100
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
101
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
102
|
+
sage: a * b
|
|
103
|
+
[a*b]
|
|
104
|
+
sage: b * a
|
|
105
|
+
[b*a]
|
|
106
|
+
sage: d * a
|
|
107
|
+
[a*d]
|
|
108
|
+
"""
|
|
109
|
+
if self == self.parent().one():
|
|
110
|
+
return "1"
|
|
111
|
+
return f"[{self.value}]"
|
|
112
|
+
|
|
113
|
+
def _richcmp_(self, other, op) -> bool:
|
|
114
|
+
r"""
|
|
115
|
+
Compare two traces by their lexicographic normal forms.
|
|
116
|
+
|
|
117
|
+
EXAMPLES::
|
|
118
|
+
|
|
119
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
120
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
121
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
122
|
+
sage: a^2 > a
|
|
123
|
+
True
|
|
124
|
+
sage: a*b < b*a
|
|
125
|
+
True
|
|
126
|
+
sage: a * c * b == a * b * c
|
|
127
|
+
True
|
|
128
|
+
"""
|
|
129
|
+
return self.value._richcmp_(other.value, op)
|
|
130
|
+
|
|
131
|
+
def lex_normal_form(self):
|
|
132
|
+
r"""
|
|
133
|
+
Return the lexicographic normal form of ``self``.
|
|
134
|
+
|
|
135
|
+
OUTPUT: a free monoid element
|
|
136
|
+
|
|
137
|
+
EXAMPLES::
|
|
138
|
+
|
|
139
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
140
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
141
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
142
|
+
sage: (a*b).lex_normal_form()
|
|
143
|
+
a*b
|
|
144
|
+
sage: (b*a).lex_normal_form()
|
|
145
|
+
b*a
|
|
146
|
+
sage: (d*a).lex_normal_form()
|
|
147
|
+
a*d
|
|
148
|
+
"""
|
|
149
|
+
return self.value
|
|
150
|
+
|
|
151
|
+
def foata_normal_form(self) -> tuple:
|
|
152
|
+
r"""
|
|
153
|
+
Return the Foata normal form of ``self``.
|
|
154
|
+
|
|
155
|
+
OUTPUT: tuple of free monoid elements
|
|
156
|
+
|
|
157
|
+
EXAMPLES::
|
|
158
|
+
|
|
159
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
160
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
161
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
162
|
+
sage: x = b * a * d * a * c * b
|
|
163
|
+
sage: x.foata_normal_form()
|
|
164
|
+
(b, a*d, a, b*c)
|
|
165
|
+
"""
|
|
166
|
+
return self.parent()._compute_foata_normal_form(self.value)
|
|
167
|
+
|
|
168
|
+
def _mul_(self, other):
|
|
169
|
+
r"""
|
|
170
|
+
Concatenate one equivalence class with another.
|
|
171
|
+
|
|
172
|
+
EXAMPLES::
|
|
173
|
+
|
|
174
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
175
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
176
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
177
|
+
sage: a * b * c == a * c * b
|
|
178
|
+
True
|
|
179
|
+
"""
|
|
180
|
+
return self.parent(self.value * other.value)
|
|
181
|
+
|
|
182
|
+
def _flat_elements(self):
|
|
183
|
+
r"""
|
|
184
|
+
Return flatten list of generator numbers representing the trace.
|
|
185
|
+
|
|
186
|
+
OUTPUT: list of generator indexes
|
|
187
|
+
|
|
188
|
+
TESTS::
|
|
189
|
+
|
|
190
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
191
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
192
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
193
|
+
sage: x = b * a^3 * d * a * c * b^2
|
|
194
|
+
sage: x._flat_elements()
|
|
195
|
+
[b, a, a, a, a, d, b, b, c]
|
|
196
|
+
"""
|
|
197
|
+
return [g for g, times in self.value for _ in range(times)]
|
|
198
|
+
|
|
199
|
+
@cached_method
|
|
200
|
+
def dependence_graph(self):
|
|
201
|
+
r"""
|
|
202
|
+
Return dependence graph of the trace.
|
|
203
|
+
|
|
204
|
+
It is a directed graph where all dependent (non-commutative)
|
|
205
|
+
generators are connected by edges which
|
|
206
|
+
direction depend on the generator position in the trace.
|
|
207
|
+
|
|
208
|
+
OUTPUT: directed graph of generator indexes
|
|
209
|
+
|
|
210
|
+
EXAMPLES::
|
|
211
|
+
|
|
212
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
213
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
214
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
215
|
+
sage: x = b * a * d * a * c * b
|
|
216
|
+
sage: x.dependence_graph() # needs sage.graphs
|
|
217
|
+
Digraph on 6 vertices
|
|
218
|
+
"""
|
|
219
|
+
elements = self._flat_elements()
|
|
220
|
+
independence = self.parent()._independence
|
|
221
|
+
graph = {}
|
|
222
|
+
|
|
223
|
+
for i, e in enumerate(elements):
|
|
224
|
+
edges = [(v, i) for v in graph
|
|
225
|
+
if (e, elements[v]) not in independence]
|
|
226
|
+
graph[i] = []
|
|
227
|
+
for v1, v2 in edges:
|
|
228
|
+
graph[v1].append(v2)
|
|
229
|
+
|
|
230
|
+
return DiGraph(graph)
|
|
231
|
+
|
|
232
|
+
@cached_method
|
|
233
|
+
def hasse_diagram(self, algorithm='naive'):
|
|
234
|
+
r"""
|
|
235
|
+
Return Hasse diagram of the trace.
|
|
236
|
+
|
|
237
|
+
Hasse diagram is a dependence graph without transitive edges.
|
|
238
|
+
|
|
239
|
+
INPUT:
|
|
240
|
+
|
|
241
|
+
- ``algorithm`` -- string (default: ``'naive'``); defines algorithm
|
|
242
|
+
that will be used to compute Hasse diagram; there are two
|
|
243
|
+
variants: ``'naive'`` and ``'min'``.
|
|
244
|
+
|
|
245
|
+
OUTPUT: directed graph of generator indexes
|
|
246
|
+
|
|
247
|
+
.. SEEALSO::
|
|
248
|
+
|
|
249
|
+
:meth:`~sage.monoids.trace_monoid.TraceMonoidElement.naive_hasse_digram`,
|
|
250
|
+
:meth:`~sage.monoids.trace_monoid.TraceMonoidElement.min_hasse_diagram`.
|
|
251
|
+
|
|
252
|
+
EXAMPLES::
|
|
253
|
+
|
|
254
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
255
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
256
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
257
|
+
sage: x = b * a * d * a * c * b
|
|
258
|
+
sage: x.hasse_diagram() # needs sage.graphs
|
|
259
|
+
Digraph on 6 vertices
|
|
260
|
+
|
|
261
|
+
TESTS::
|
|
262
|
+
|
|
263
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
264
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
265
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
266
|
+
sage: x = b * a * d * a * c * b
|
|
267
|
+
sage: x.hasse_diagram(algorithm='naive') == x.hasse_diagram(algorithm='min') # needs sage.graphs
|
|
268
|
+
True
|
|
269
|
+
sage: y = b * a^3 * d * a * c * b^2
|
|
270
|
+
sage: y.hasse_diagram(algorithm='naive') == y.hasse_diagram(algorithm='min') # needs sage.graphs
|
|
271
|
+
True
|
|
272
|
+
"""
|
|
273
|
+
if algorithm == "naive":
|
|
274
|
+
return self.naive_hasse_diagram()
|
|
275
|
+
elif algorithm == "min":
|
|
276
|
+
return self.min_hasse_diagram()
|
|
277
|
+
raise ValueError("`alg` option must be `naive` "
|
|
278
|
+
f"or `min`, got `{algorithm}`.")
|
|
279
|
+
|
|
280
|
+
def min_hasse_diagram(self):
|
|
281
|
+
r"""
|
|
282
|
+
Return Hasse diagram of the trace.
|
|
283
|
+
|
|
284
|
+
OUTPUT: directed graph of generator indexes
|
|
285
|
+
|
|
286
|
+
.. SEEALSO::
|
|
287
|
+
|
|
288
|
+
:meth:`~sage.monoids.trace_monoid.TraceMonoidElement.hasse_digram`,
|
|
289
|
+
:meth:`~sage.monoids.trace_monoid.TraceMonoidElement.naive_hasse_diagram`.
|
|
290
|
+
|
|
291
|
+
EXAMPLES::
|
|
292
|
+
|
|
293
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
294
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
295
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
296
|
+
sage: x = b * a * d * a * c * b
|
|
297
|
+
sage: x.min_hasse_diagram() # needs sage.graphs
|
|
298
|
+
Digraph on 6 vertices
|
|
299
|
+
"""
|
|
300
|
+
elements = self._flat_elements()
|
|
301
|
+
elements.reverse()
|
|
302
|
+
independence = self.parent()._independence
|
|
303
|
+
reachable = {}
|
|
304
|
+
mini = set()
|
|
305
|
+
graph = DiGraph({})
|
|
306
|
+
|
|
307
|
+
for i, x in enumerate(elements):
|
|
308
|
+
reachable[i] = set()
|
|
309
|
+
front = mini.copy()
|
|
310
|
+
while front:
|
|
311
|
+
used = set()
|
|
312
|
+
for j in list(front):
|
|
313
|
+
y = elements[j]
|
|
314
|
+
if (x, y) not in independence:
|
|
315
|
+
graph.add_edge(i, j)
|
|
316
|
+
reachable[i].add(j)
|
|
317
|
+
reachable[i].update(reachable[j])
|
|
318
|
+
if j in mini:
|
|
319
|
+
mini.remove(j)
|
|
320
|
+
used.add(j)
|
|
321
|
+
forbidden = set(chain.from_iterable(reachable[v] for v in used))
|
|
322
|
+
front = {dest for _, dest in graph.outgoing_edges(front, labels=False)}
|
|
323
|
+
front = front - forbidden
|
|
324
|
+
|
|
325
|
+
mini.add(i)
|
|
326
|
+
|
|
327
|
+
length = len(elements)
|
|
328
|
+
graph.relabel(length - 1 - i for i in range(length))
|
|
329
|
+
return graph
|
|
330
|
+
|
|
331
|
+
def naive_hasse_diagram(self):
|
|
332
|
+
r"""
|
|
333
|
+
Return Hasse diagram of ``self``.
|
|
334
|
+
|
|
335
|
+
ALGORITHM:
|
|
336
|
+
|
|
337
|
+
In loop check for every two pair of edges if they
|
|
338
|
+
have common vertex, remove their transitive edge.
|
|
339
|
+
|
|
340
|
+
OUTPUT: directed graph of generator indexes
|
|
341
|
+
|
|
342
|
+
.. SEEALSO::
|
|
343
|
+
|
|
344
|
+
:meth:`~sage.monoids.trace_monoid.TraceMonoidElement.hasse_digram`,
|
|
345
|
+
:meth:`~sage.monoids.trace_monoid.TraceMonoidElement.min_hasse_diagram`.
|
|
346
|
+
|
|
347
|
+
EXAMPLES::
|
|
348
|
+
|
|
349
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
350
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
351
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
352
|
+
sage: x = b * a * d * a * c * b
|
|
353
|
+
sage: x.naive_hasse_diagram() # needs sage.graphs
|
|
354
|
+
Digraph on 6 vertices
|
|
355
|
+
"""
|
|
356
|
+
d = self.dependence_graph()
|
|
357
|
+
h = d.copy()
|
|
358
|
+
|
|
359
|
+
d_edges = d.edges(sort=False)
|
|
360
|
+
for e1 in d_edges:
|
|
361
|
+
for e2 in d_edges:
|
|
362
|
+
if e1[1] == e2[0]:
|
|
363
|
+
h.delete_edge((e1[0], e2[1]))
|
|
364
|
+
|
|
365
|
+
return h
|
|
366
|
+
|
|
367
|
+
def alphabet(self):
|
|
368
|
+
r"""
|
|
369
|
+
Return alphabet of ``self``.
|
|
370
|
+
|
|
371
|
+
OUTPUT: a set of free monoid generators
|
|
372
|
+
|
|
373
|
+
EXAMPLES::
|
|
374
|
+
|
|
375
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
376
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
377
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
378
|
+
sage: x = b*a*d*a*c*b
|
|
379
|
+
sage: x.alphabet()
|
|
380
|
+
{b, a, d, c}
|
|
381
|
+
"""
|
|
382
|
+
return Alphabet([g for g, _ in self.value])
|
|
383
|
+
|
|
384
|
+
def projection(self, letters):
|
|
385
|
+
r"""
|
|
386
|
+
Return a trace that formed from ``self`` by erasing ``letters``.
|
|
387
|
+
|
|
388
|
+
INPUT:
|
|
389
|
+
|
|
390
|
+
- ``letters`` -- set of generators; defines set of letters that will be
|
|
391
|
+
used to filter the trace
|
|
392
|
+
|
|
393
|
+
OUTPUT: a trace
|
|
394
|
+
|
|
395
|
+
EXAMPLES::
|
|
396
|
+
|
|
397
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
398
|
+
sage: F.<a,b,c,d> = FreeMonoid()
|
|
399
|
+
sage: I = ((a,d), (d,a), (b,c), (c,b))
|
|
400
|
+
sage: M.<ac,bc,cc,dc> = TraceMonoid(F, I=I)
|
|
401
|
+
sage: x = M(b*a*d*a*c*b)
|
|
402
|
+
sage: x.projection({a,b})
|
|
403
|
+
[b*a^2*b]
|
|
404
|
+
sage: x.projection({b,d,c})
|
|
405
|
+
[b*d*b*c]
|
|
406
|
+
"""
|
|
407
|
+
P = self.parent()
|
|
408
|
+
base = P._free_monoid
|
|
409
|
+
return P(base.prod(x for x in self._flat_elements() if x in letters))
|
|
410
|
+
|
|
411
|
+
def multiplicative_order(self):
|
|
412
|
+
r"""
|
|
413
|
+
Return the multiplicative order of ``self``, which is `\infty`
|
|
414
|
+
for any element not the identity.
|
|
415
|
+
|
|
416
|
+
EXAMPLES::
|
|
417
|
+
|
|
418
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
419
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
420
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
421
|
+
sage: a.multiplicative_order()
|
|
422
|
+
+Infinity
|
|
423
|
+
sage: M.one().multiplicative_order()
|
|
424
|
+
1
|
|
425
|
+
"""
|
|
426
|
+
if self.value.is_one():
|
|
427
|
+
return ZZ.one()
|
|
428
|
+
return infinity
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
class TraceMonoid(UniqueRepresentation, Monoid_class):
|
|
432
|
+
r"""
|
|
433
|
+
Return a free partially commuting monoid (trace monoid) on `n` generators
|
|
434
|
+
over independence relation `I`.
|
|
435
|
+
|
|
436
|
+
We construct a trace monoid by specifying:
|
|
437
|
+
|
|
438
|
+
- a free monoid and independence relation
|
|
439
|
+
- or generator names and independence relation,
|
|
440
|
+
FreeMonoid is constructed automatically then.
|
|
441
|
+
|
|
442
|
+
INPUT:
|
|
443
|
+
|
|
444
|
+
- ``M`` -- a free monoid
|
|
445
|
+
|
|
446
|
+
- ``I`` -- commutation relation between generators
|
|
447
|
+
(or their names if the ``names`` are given)
|
|
448
|
+
|
|
449
|
+
- ``names`` -- names of generators
|
|
450
|
+
|
|
451
|
+
EXAMPLES::
|
|
452
|
+
|
|
453
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
454
|
+
sage: F = TraceMonoid(names=('a', 'b', 'c'), I={('a','c'), ('c','a')}); F
|
|
455
|
+
Trace monoid on 3 generators ([a], [b], [c]) with independence relation {{a, c}}
|
|
456
|
+
sage: x = F.gens()
|
|
457
|
+
sage: x[0]*x[1]**5 * (x[0]*x[2])
|
|
458
|
+
[a*b^5*a*c]
|
|
459
|
+
|
|
460
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
461
|
+
sage: M.<a,b,c> = TraceMonoid(I=(('a','c'), ('c','a')))
|
|
462
|
+
sage: latex(M)
|
|
463
|
+
\langle a, b, c \mid ac=ca \rangle
|
|
464
|
+
|
|
465
|
+
TESTS::
|
|
466
|
+
|
|
467
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
468
|
+
sage: M.<a,b,c> = TraceMonoid(I=(('a','c'), ('c','a')))
|
|
469
|
+
sage: M.number_of_words(3) == len(M.words(3)) # needs sage.graphs
|
|
470
|
+
True
|
|
471
|
+
"""
|
|
472
|
+
Element = TraceMonoidElement
|
|
473
|
+
|
|
474
|
+
@staticmethod
|
|
475
|
+
def __classcall_private__(cls, M=None, I=frozenset(), names=None):
|
|
476
|
+
"""
|
|
477
|
+
Normalize input to ensure a unique representation.
|
|
478
|
+
|
|
479
|
+
TESTS::
|
|
480
|
+
|
|
481
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
482
|
+
sage: M1.<a,b,c> = TraceMonoid(I=(('a','c'), ('c','a')))
|
|
483
|
+
sage: M2.<a,b,c> = TraceMonoid(I=[('a','c')])
|
|
484
|
+
sage: M3 = TraceMonoid(I=[{'a','c'}], names=('a', 'b', 'c'))
|
|
485
|
+
sage: M1 is M2 and M2 is M3
|
|
486
|
+
True
|
|
487
|
+
"""
|
|
488
|
+
if not M:
|
|
489
|
+
if names:
|
|
490
|
+
M = FreeMonoid(names=names)
|
|
491
|
+
else:
|
|
492
|
+
raise ValueError("names must be provided")
|
|
493
|
+
elif not names:
|
|
494
|
+
names = [str(g) for g in M.gens()]
|
|
495
|
+
names = tuple(names)
|
|
496
|
+
|
|
497
|
+
rels = set()
|
|
498
|
+
gen_from_str = {names[i]: gen for i, gen in enumerate(M.gens())}
|
|
499
|
+
for x, y in I:
|
|
500
|
+
try:
|
|
501
|
+
if isinstance(x, str):
|
|
502
|
+
x = gen_from_str[x]
|
|
503
|
+
x = M(x)
|
|
504
|
+
if isinstance(y, str):
|
|
505
|
+
y = gen_from_str[y]
|
|
506
|
+
y = M(y)
|
|
507
|
+
if x == y:
|
|
508
|
+
raise ValueError
|
|
509
|
+
except (TypeError, ValueError):
|
|
510
|
+
raise ValueError("invalid relation defined")
|
|
511
|
+
rels.add((x, y))
|
|
512
|
+
rels.add((y, x))
|
|
513
|
+
I = frozenset(rels)
|
|
514
|
+
|
|
515
|
+
return super().__classcall__(cls, M, I, names)
|
|
516
|
+
|
|
517
|
+
def __init__(self, M, I, names) -> None:
|
|
518
|
+
r"""
|
|
519
|
+
Initialize ``self``.
|
|
520
|
+
|
|
521
|
+
TESTS::
|
|
522
|
+
|
|
523
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
524
|
+
sage: M.<a,b,c> = TraceMonoid(I=(('a','c'), ('c','a')))
|
|
525
|
+
sage: TestSuite(M).run()
|
|
526
|
+
"""
|
|
527
|
+
self._free_monoid = M
|
|
528
|
+
self._independence = I
|
|
529
|
+
Monoid_class.__init__(self, names=names)
|
|
530
|
+
|
|
531
|
+
def ngens(self):
|
|
532
|
+
"""
|
|
533
|
+
Return the number of generators of ``self``.
|
|
534
|
+
|
|
535
|
+
EXAMPLES::
|
|
536
|
+
|
|
537
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
538
|
+
sage: M.<a,b,c> = TraceMonoid(I=(('a','c'), ('c','a')))
|
|
539
|
+
sage: M.ngens()
|
|
540
|
+
3
|
|
541
|
+
"""
|
|
542
|
+
return self._free_monoid.ngens()
|
|
543
|
+
|
|
544
|
+
def one(self):
|
|
545
|
+
"""
|
|
546
|
+
Return the neutral element of ``self``.
|
|
547
|
+
|
|
548
|
+
EXAMPLES::
|
|
549
|
+
|
|
550
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
551
|
+
sage: M.<a,b,c> = TraceMonoid(I=(('a','c'), ('c','a')))
|
|
552
|
+
sage: M.one()
|
|
553
|
+
1
|
|
554
|
+
"""
|
|
555
|
+
return self.element_class(self, self._free_monoid.one())
|
|
556
|
+
|
|
557
|
+
def gen(self, i=0):
|
|
558
|
+
"""
|
|
559
|
+
Return the `i`-th generator of the monoid.
|
|
560
|
+
|
|
561
|
+
INPUT:
|
|
562
|
+
|
|
563
|
+
- ``i`` -- integer (default: 0)
|
|
564
|
+
|
|
565
|
+
EXAMPLES::
|
|
566
|
+
|
|
567
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
568
|
+
sage: M.<a,b,c> = TraceMonoid(I=(('a','c'), ('c','a')))
|
|
569
|
+
sage: M.gen(1)
|
|
570
|
+
[b]
|
|
571
|
+
sage: M.gen(4)
|
|
572
|
+
Traceback (most recent call last):
|
|
573
|
+
...
|
|
574
|
+
IndexError: argument i (= 4) must be between 0 and 2
|
|
575
|
+
"""
|
|
576
|
+
return self.element_class(self, self._free_monoid.gen(i))
|
|
577
|
+
|
|
578
|
+
def cardinality(self):
|
|
579
|
+
"""
|
|
580
|
+
Return the cardinality of ``self``, which is infinite except for
|
|
581
|
+
the trivial monoid.
|
|
582
|
+
|
|
583
|
+
EXAMPLES::
|
|
584
|
+
|
|
585
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
586
|
+
sage: M.<a,b,c> = TraceMonoid(I=(('a','c'), ('c','a')))
|
|
587
|
+
sage: M.cardinality()
|
|
588
|
+
+Infinity
|
|
589
|
+
"""
|
|
590
|
+
return self._free_monoid.cardinality()
|
|
591
|
+
|
|
592
|
+
def _compute_dependence_stack(self, x):
|
|
593
|
+
r"""
|
|
594
|
+
Return generator stacks formed from trace
|
|
595
|
+
subelements with respect to non-commutativity.
|
|
596
|
+
|
|
597
|
+
OUTPUT: used generators and list of stacks as tuple
|
|
598
|
+
|
|
599
|
+
ALGORITHM:
|
|
600
|
+
|
|
601
|
+
Let `x` be a word of monoid; we scan `x` from right to left;
|
|
602
|
+
when processing a letter `a` it is pushed on its stack and a
|
|
603
|
+
marker is pushed on the stack of all the letters `b` ( `b \neq a` )
|
|
604
|
+
which do not commute with `a`.
|
|
605
|
+
|
|
606
|
+
TESTS::
|
|
607
|
+
|
|
608
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
609
|
+
sage: F.<a,b,c,d> = FreeMonoid()
|
|
610
|
+
sage: I = (('ac','dc'), ('dc','ac'), ('bc','cc'), ('cc','bc'))
|
|
611
|
+
sage: M.<ac,bc,cc,dc> = TraceMonoid(F, I=I)
|
|
612
|
+
sage: x = b*a*d*a*c*b
|
|
613
|
+
sage: M._compute_dependence_stack(x)
|
|
614
|
+
({a, b, c, d},
|
|
615
|
+
{a: [False, False, True, True, False],
|
|
616
|
+
b: [True, False, False, False, True],
|
|
617
|
+
c: [True, False, False, False],
|
|
618
|
+
d: [False, False, True, False]})
|
|
619
|
+
"""
|
|
620
|
+
independence = self._independence
|
|
621
|
+
generators_set = {e for e, _ in x}
|
|
622
|
+
stacks = dict(sorted((g, []) for g in generators_set))
|
|
623
|
+
for generator, times in reversed(list(x)):
|
|
624
|
+
stacks[generator].extend(repeat(True, times))
|
|
625
|
+
for other_gen in generators_set:
|
|
626
|
+
if other_gen == generator:
|
|
627
|
+
continue
|
|
628
|
+
if (generator, other_gen) not in independence:
|
|
629
|
+
stacks[other_gen].extend(repeat(False, times))
|
|
630
|
+
return generators_set, stacks
|
|
631
|
+
|
|
632
|
+
@cached_method
|
|
633
|
+
def _compute_lex_normal_form(self, x):
|
|
634
|
+
r"""
|
|
635
|
+
Return lexicographic normal form of the free monoid
|
|
636
|
+
element in free monoid terms.
|
|
637
|
+
|
|
638
|
+
OUTPUT: trace monoid element
|
|
639
|
+
|
|
640
|
+
ALGORITHM:
|
|
641
|
+
|
|
642
|
+
Take among the letters being on the top of some stack that
|
|
643
|
+
letter `a` being minimal with respect to the given lexicographic
|
|
644
|
+
ordering. We pop a marker from each stack corresponding to a
|
|
645
|
+
letter `b` ( `b \neq a` ) which does not commute with `a`. We repeat
|
|
646
|
+
this loop until all stacks are empty.
|
|
647
|
+
|
|
648
|
+
EXAMPLES::
|
|
649
|
+
|
|
650
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
651
|
+
sage: F.<a,b,c,d> = FreeMonoid()
|
|
652
|
+
sage: I = ((a,d), (d,a), (b,c), (c,b))
|
|
653
|
+
sage: M.<ac,bc,cc,dc> = TraceMonoid(F, I=I)
|
|
654
|
+
sage: M._compute_lex_normal_form(c*a*c*b*a^2)
|
|
655
|
+
c*a*b*c*a^2
|
|
656
|
+
"""
|
|
657
|
+
if not x._element_list:
|
|
658
|
+
return x
|
|
659
|
+
generators_set, stacks = self._compute_dependence_stack(x)
|
|
660
|
+
independence = self._independence
|
|
661
|
+
|
|
662
|
+
elements = []
|
|
663
|
+
while any(stacks.values()):
|
|
664
|
+
for generator, g_stack in stacks.items():
|
|
665
|
+
if g_stack and g_stack[-1]:
|
|
666
|
+
g_stack.pop()
|
|
667
|
+
elements.append(generator)
|
|
668
|
+
for other_gen in generators_set:
|
|
669
|
+
if (other_gen != generator
|
|
670
|
+
and (generator, other_gen) not in independence):
|
|
671
|
+
stacks[other_gen].pop()
|
|
672
|
+
break
|
|
673
|
+
|
|
674
|
+
return prod(elements)
|
|
675
|
+
|
|
676
|
+
@cached_method
|
|
677
|
+
def _compute_foata_normal_form(self, x) -> tuple:
|
|
678
|
+
r"""
|
|
679
|
+
Return Foata normal form of the monoid element.
|
|
680
|
+
|
|
681
|
+
OUTPUT: tuple of steps
|
|
682
|
+
|
|
683
|
+
ALGORITHM:
|
|
684
|
+
|
|
685
|
+
Within a loop we form the set using letters being
|
|
686
|
+
on the top of stacks; arranging the letters in the lexicographic
|
|
687
|
+
order yields a step of the Foata normal form;
|
|
688
|
+
This loop is repeated until all stacks are empty.
|
|
689
|
+
|
|
690
|
+
EXAMPLES::
|
|
691
|
+
|
|
692
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
693
|
+
sage: F.<a,b,c,d> = FreeMonoid()
|
|
694
|
+
sage: I = ((a,d), (d,a), (b,c), (c,b))
|
|
695
|
+
sage: M.<ac,bc,cc,dc> = TraceMonoid(F, I=I)
|
|
696
|
+
sage: x = b*a*d*a*c*b
|
|
697
|
+
sage: M._compute_foata_normal_form(x)
|
|
698
|
+
(b, a*d, a, b*c)
|
|
699
|
+
sage: y = b*a*a*d*b*a*b*c^2*a
|
|
700
|
+
sage: M._compute_foata_normal_form(y)
|
|
701
|
+
(b, a*d, a, b, a, b*c, c, a)
|
|
702
|
+
"""
|
|
703
|
+
if not x._element_list:
|
|
704
|
+
return ()
|
|
705
|
+
|
|
706
|
+
generators_set, stacks = self._compute_dependence_stack(x)
|
|
707
|
+
independence = self._independence
|
|
708
|
+
|
|
709
|
+
steps = []
|
|
710
|
+
while any(stacks.values()):
|
|
711
|
+
step = []
|
|
712
|
+
for generator, g_stack in stacks.items():
|
|
713
|
+
if g_stack and g_stack[-1]:
|
|
714
|
+
g_stack.pop()
|
|
715
|
+
step.append(generator)
|
|
716
|
+
|
|
717
|
+
for g in step:
|
|
718
|
+
for other_gen in generators_set:
|
|
719
|
+
if other_gen != g and (g, other_gen) not in independence:
|
|
720
|
+
stacks[other_gen].pop()
|
|
721
|
+
|
|
722
|
+
steps.append(step)
|
|
723
|
+
|
|
724
|
+
return tuple(prod(step) for step in steps)
|
|
725
|
+
|
|
726
|
+
def _element_constructor_(self, x):
|
|
727
|
+
"""
|
|
728
|
+
Return ``x`` coerced into this trace monoid.
|
|
729
|
+
|
|
730
|
+
One can create a free monoid element from the integer 1,
|
|
731
|
+
free monoid elements of the same generators as internal one,
|
|
732
|
+
and coerce everything that can coerce free monoid.
|
|
733
|
+
|
|
734
|
+
EXAMPLES::
|
|
735
|
+
|
|
736
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
737
|
+
sage: F.<a,b,c,d> = FreeMonoid()
|
|
738
|
+
sage: I = ((a,d), (d,a), (b,c), (c,b))
|
|
739
|
+
sage: M.<ac,bc,cc,dc> = TraceMonoid(F, I=I)
|
|
740
|
+
sage: x = b*a*d*a*c*b
|
|
741
|
+
sage: M(x)
|
|
742
|
+
[b*a^2*d*b*c]
|
|
743
|
+
"""
|
|
744
|
+
x = self._compute_lex_normal_form(self._free_monoid(x))
|
|
745
|
+
return self.element_class(self, x)
|
|
746
|
+
|
|
747
|
+
@cached_method
|
|
748
|
+
def independence(self):
|
|
749
|
+
r"""
|
|
750
|
+
Return independence relation over the monoid.
|
|
751
|
+
|
|
752
|
+
OUTPUT: set of commuting generator pairs
|
|
753
|
+
|
|
754
|
+
EXAMPLES::
|
|
755
|
+
|
|
756
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
757
|
+
sage: F.<a,b,c> = FreeMonoid()
|
|
758
|
+
sage: I = frozenset(((a,c), (c,a)))
|
|
759
|
+
sage: M.<ac,bc,cc> = TraceMonoid(F, I=I)
|
|
760
|
+
sage: M.independence() == frozenset([frozenset([a,c])])
|
|
761
|
+
True
|
|
762
|
+
"""
|
|
763
|
+
return frozenset(map(frozenset, self._independence))
|
|
764
|
+
|
|
765
|
+
@cached_method
|
|
766
|
+
def dependence(self):
|
|
767
|
+
r"""
|
|
768
|
+
Return dependence relation over the monoid.
|
|
769
|
+
|
|
770
|
+
OUTPUT: set of non-commuting generator pairs
|
|
771
|
+
|
|
772
|
+
EXAMPLES::
|
|
773
|
+
|
|
774
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
775
|
+
sage: M.<a,b,c> = TraceMonoid(I=(('a','c'), ('c','a')))
|
|
776
|
+
sage: sorted(M.dependence())
|
|
777
|
+
[(a, a), (a, b), (b, a), (b, b), (b, c), (c, b), (c, c)]
|
|
778
|
+
"""
|
|
779
|
+
return frozenset(pair for pair in product(self._free_monoid.gens(), repeat=2)
|
|
780
|
+
if pair not in self._independence)
|
|
781
|
+
|
|
782
|
+
@cached_method
|
|
783
|
+
def dependence_graph(self):
|
|
784
|
+
r"""
|
|
785
|
+
Return graph of dependence relation.
|
|
786
|
+
|
|
787
|
+
OUTPUT: dependence graph with generators as vertices
|
|
788
|
+
|
|
789
|
+
TESTS::
|
|
790
|
+
|
|
791
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
792
|
+
sage: F.<a,b,c> = FreeMonoid()
|
|
793
|
+
sage: M.<ai,bi,ci> = TraceMonoid(F, I=((a,c), (c,a)))
|
|
794
|
+
sage: M.dependence_graph() == Graph({a:[a,b], b:[b], c:[c,b]}) # needs sage.graphs
|
|
795
|
+
True
|
|
796
|
+
"""
|
|
797
|
+
return Graph({frozenset((e1, e2)) if e1 != e2 else (e1, e2)
|
|
798
|
+
for e1, e2 in self.dependence()}, loops=True,
|
|
799
|
+
format='list_of_edges',
|
|
800
|
+
immutable=True)
|
|
801
|
+
|
|
802
|
+
@cached_method
|
|
803
|
+
def independence_graph(self):
|
|
804
|
+
r"""
|
|
805
|
+
Return the digraph of independence relations.
|
|
806
|
+
|
|
807
|
+
OUTPUT: independence graph with generators as vertices
|
|
808
|
+
|
|
809
|
+
TESTS::
|
|
810
|
+
|
|
811
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
812
|
+
sage: F.<a,b,c> = FreeMonoid()
|
|
813
|
+
sage: M.<ai,bi,ci> = TraceMonoid(F, I=((a,c), (c,a)))
|
|
814
|
+
sage: M.independence_graph() == Graph({a:[c], b:[], c:[]}) # needs sage.graphs
|
|
815
|
+
True
|
|
816
|
+
"""
|
|
817
|
+
verts = list(self._free_monoid.gens())
|
|
818
|
+
edges = list(map(list, self.independence()))
|
|
819
|
+
return Graph([verts, edges], immutable=True)
|
|
820
|
+
|
|
821
|
+
@cached_method
|
|
822
|
+
def dependence_polynomial(self, t=None):
|
|
823
|
+
r"""
|
|
824
|
+
Return dependence polynomial.
|
|
825
|
+
|
|
826
|
+
The polynomial is defined as follows: `\sum{i}{(-1)^i c_i t^i}`,
|
|
827
|
+
where `c_i` equals to number of full subgraphs
|
|
828
|
+
of size `i` in the independence graph.
|
|
829
|
+
|
|
830
|
+
OUTPUT: a rational function in ``t`` with coefficients in the integer ring
|
|
831
|
+
|
|
832
|
+
EXAMPLES::
|
|
833
|
+
|
|
834
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
835
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
836
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
837
|
+
sage: M.dependence_polynomial() # needs sage.graphs
|
|
838
|
+
1/(2*t^2 - 4*t + 1)
|
|
839
|
+
"""
|
|
840
|
+
if t is None:
|
|
841
|
+
R = PolynomialRing(ZZ, 't')
|
|
842
|
+
t = R.gen()
|
|
843
|
+
clique_seq = self.independence_graph().clique_polynomial().coefficients()
|
|
844
|
+
return ~sum((-1)**i * coeff * (t**i)
|
|
845
|
+
for i, coeff in enumerate(clique_seq))
|
|
846
|
+
|
|
847
|
+
@cached_method
|
|
848
|
+
def number_of_words(self, length):
|
|
849
|
+
r"""
|
|
850
|
+
Return number of unique words of defined length.
|
|
851
|
+
|
|
852
|
+
INPUT:
|
|
853
|
+
|
|
854
|
+
- ``length`` -- integer; defines size of words what number should be computed
|
|
855
|
+
|
|
856
|
+
OUTPUT: words number as integer
|
|
857
|
+
|
|
858
|
+
EXAMPLES:
|
|
859
|
+
|
|
860
|
+
Get number of words of size 3 ::
|
|
861
|
+
|
|
862
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
863
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
864
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
865
|
+
sage: M.number_of_words(3) # needs sage.graphs
|
|
866
|
+
48
|
|
867
|
+
"""
|
|
868
|
+
psr = PowerSeriesRing(ZZ, default_prec=length + 1)
|
|
869
|
+
return psr(self.dependence_polynomial()).coefficients()[length]
|
|
870
|
+
|
|
871
|
+
@cached_method
|
|
872
|
+
def words(self, length):
|
|
873
|
+
r"""
|
|
874
|
+
Return all lexicographic forms of defined length.
|
|
875
|
+
|
|
876
|
+
INPUT:
|
|
877
|
+
|
|
878
|
+
- ``length`` -- integer; defines size of words
|
|
879
|
+
|
|
880
|
+
OUTPUT: set of traces of size ``length``
|
|
881
|
+
|
|
882
|
+
EXAMPLES:
|
|
883
|
+
|
|
884
|
+
All words of size 2::
|
|
885
|
+
|
|
886
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
887
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
888
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
889
|
+
sage: sorted(M.words(2))
|
|
890
|
+
[[a^2], [a*b], [a*c], [a*d], [b*a], [b^2], [b*c],
|
|
891
|
+
[b*d], [c*a], [c^2], [c*d], [d*b], [d*c], [d^2]]
|
|
892
|
+
|
|
893
|
+
Get number of words of size 3::
|
|
894
|
+
|
|
895
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
896
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
897
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I)
|
|
898
|
+
sage: len(M.words(3))
|
|
899
|
+
48
|
|
900
|
+
|
|
901
|
+
TESTS::
|
|
902
|
+
|
|
903
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
904
|
+
sage: M.<a,b,c> = TraceMonoid(I=(('a','b'), ('b','a'), ('b', 'c'), ('c', 'b')))
|
|
905
|
+
sage: for i in range(10): # needs sage.graphs
|
|
906
|
+
....: assert len(M.words(i)) == M.number_of_words(i)
|
|
907
|
+
"""
|
|
908
|
+
if length < 0:
|
|
909
|
+
raise ValueError("bad length of words; expected zero or positive number")
|
|
910
|
+
if length == 0:
|
|
911
|
+
return frozenset([self.one()])
|
|
912
|
+
if length == 1:
|
|
913
|
+
return frozenset(self.gens())
|
|
914
|
+
|
|
915
|
+
return frozenset([word * suffix for word in self.words(length - 1)
|
|
916
|
+
for suffix in self.gens()
|
|
917
|
+
if not ((list(word.value)[-1][0], suffix.value) in self._independence
|
|
918
|
+
and list(word.value)[-1][0] > suffix.value)])
|
|
919
|
+
|
|
920
|
+
def _sorted_independence(self) -> list:
|
|
921
|
+
r"""
|
|
922
|
+
Return independence relation over the monoid.
|
|
923
|
+
|
|
924
|
+
OUTPUT: sorted list of sorted commuting generator pairs
|
|
925
|
+
|
|
926
|
+
EXAMPLES::
|
|
927
|
+
|
|
928
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
929
|
+
sage: F.<a,b,c> = FreeMonoid()
|
|
930
|
+
sage: I = frozenset(((a,c), (c,a)))
|
|
931
|
+
sage: M.<ac,bc,cc> = TraceMonoid(F, I=I)
|
|
932
|
+
sage: M._sorted_independence()
|
|
933
|
+
[[a, c]]
|
|
934
|
+
"""
|
|
935
|
+
return sorted(sorted(x_y)
|
|
936
|
+
for x_y in self.independence())
|
|
937
|
+
|
|
938
|
+
def _repr_(self) -> str:
|
|
939
|
+
r"""
|
|
940
|
+
Textual representation of trace monoids.
|
|
941
|
+
|
|
942
|
+
TESTS::
|
|
943
|
+
|
|
944
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
945
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
946
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I); M
|
|
947
|
+
Trace monoid on 4 generators ([a], [b], [c], [d])
|
|
948
|
+
with independence relation {{a, d}, {b, c}}
|
|
949
|
+
"""
|
|
950
|
+
return ("Trace monoid on {!s} generators {!s} "
|
|
951
|
+
"with independence relation {{{}}}").format(self.ngens(), self.gens(),
|
|
952
|
+
", ".join(f"{{{x}, {y}}}"
|
|
953
|
+
for (x, y) in self._sorted_independence()))
|
|
954
|
+
|
|
955
|
+
def _latex_(self) -> str:
|
|
956
|
+
r"""
|
|
957
|
+
LaTeX representation of trace monoids.
|
|
958
|
+
|
|
959
|
+
TESTS::
|
|
960
|
+
|
|
961
|
+
sage: from sage.monoids.trace_monoid import TraceMonoid
|
|
962
|
+
sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b'))
|
|
963
|
+
sage: M.<a,b,c,d> = TraceMonoid(I=I); latex(M)
|
|
964
|
+
\langle a, b, c, d \mid ad=da,bc=cb \rangle
|
|
965
|
+
"""
|
|
966
|
+
return "\\langle {} \\mid {} \\rangle".format(
|
|
967
|
+
repr(self._free_monoid.gens())[1:-1],
|
|
968
|
+
",".join(
|
|
969
|
+
f"{v1!r}{v2!r}={v2!r}{v1!r}"
|
|
970
|
+
for v1, v2 in self._sorted_independence()
|
|
971
|
+
)
|
|
972
|
+
)
|