passagemath-combinat 10.6.42__cp314-cp314t-win_amd64.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/DELVEWHEEL +2 -0
- passagemath_combinat-10.6.42.dist-info/METADATA +160 -0
- passagemath_combinat-10.6.42.dist-info/RECORD +401 -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-10-3a5f019e2510aeaad918cab2b57a689d.dll +0 -0
- passagemath_combinat.libs/libsymmetrica-3-7dcf900932804d0df5fd0919b4668720.dll +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 +44 -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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +0 -0
- sage/combinat/debruijn_sequence.pyx +355 -0
- sage/combinat/decorated_permutation.py +270 -0
- sage/combinat/degree_sequences.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +0 -0
- sage/combinat/expnums.pyx +148 -0
- sage/combinat/fast_vector_partitions.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +0 -0
- sage/combinat/words/word_char.pyx +847 -0
- sage/combinat/words/word_datatypes.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +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.cp314t-win_amd64.pyd +0 -0
- sage/sat/solvers/satsolver.pxd +3 -0
- sage/sat/solvers/satsolver.pyx +405 -0
|
@@ -0,0 +1,2396 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
r"""
|
|
3
|
+
Set of words
|
|
4
|
+
|
|
5
|
+
To define a new class of words, please refer to the documentation file:
|
|
6
|
+
sage/combinat/words/notes/word_inheritance_howto.rst
|
|
7
|
+
|
|
8
|
+
AUTHORS:
|
|
9
|
+
|
|
10
|
+
- Franco Saliola (2008-12-17): merged into sage
|
|
11
|
+
- Sebastien Labbe (2008-12-17): merged into sage
|
|
12
|
+
- Arnaud Bergeron (2008-12-17): merged into sage
|
|
13
|
+
- Sebastien Labbe (2009-07-21): Improved morphism iterator (:issue:`6571`).
|
|
14
|
+
- Vincent Delecroix (2015): classes simplifications (:issue:`19619`)
|
|
15
|
+
|
|
16
|
+
EXAMPLES::
|
|
17
|
+
|
|
18
|
+
sage: Words()
|
|
19
|
+
Finite and infinite words over Set of Python objects of class 'object'
|
|
20
|
+
sage: Words(4)
|
|
21
|
+
Finite and infinite words over {1, 2, 3, 4}
|
|
22
|
+
sage: Words(4,5)
|
|
23
|
+
Words of length 5 over {1, 2, 3, 4}
|
|
24
|
+
|
|
25
|
+
sage: FiniteWords('ab')
|
|
26
|
+
Finite words over {'a', 'b'}
|
|
27
|
+
sage: InfiniteWords('natural numbers')
|
|
28
|
+
Infinite words over Non negative integers
|
|
29
|
+
"""
|
|
30
|
+
# ****************************************************************************
|
|
31
|
+
# Copyright (C) 2008 Arnaud Bergeron <abergeron@gmail.com>,
|
|
32
|
+
# Sébastien Labbé <slabqc@gmail.com>,
|
|
33
|
+
# Franco Saliola <saliola@gmail.com>
|
|
34
|
+
# 2015 Vincent Delecroix <20100.delecroix@gmail.com>
|
|
35
|
+
#
|
|
36
|
+
# This program is free software: you can redistribute it and/or modify
|
|
37
|
+
# it under the terms of the GNU General Public License as published by
|
|
38
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
39
|
+
# (at your option) any later version.
|
|
40
|
+
# https://www.gnu.org/licenses/
|
|
41
|
+
# ****************************************************************************
|
|
42
|
+
|
|
43
|
+
import itertools
|
|
44
|
+
from collections.abc import Iterable
|
|
45
|
+
|
|
46
|
+
from sage.misc.cachefunc import cached_method
|
|
47
|
+
from sage.misc.lazy_attribute import lazy_attribute
|
|
48
|
+
from sage.misc.persist import register_unpickle_override
|
|
49
|
+
|
|
50
|
+
from sage.structure.parent import Parent
|
|
51
|
+
|
|
52
|
+
from sage.categories.sets_cat import Sets
|
|
53
|
+
|
|
54
|
+
from sage.combinat.combinat import CombinatorialObject
|
|
55
|
+
from sage.structure.list_clone import ClonableElement
|
|
56
|
+
from sage.combinat.words.alphabet import build_alphabet
|
|
57
|
+
|
|
58
|
+
from sage.rings.infinity import Infinity
|
|
59
|
+
from sage.rings.integer import Integer
|
|
60
|
+
from sage.rings.integer_ring import ZZ
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def Words(alphabet=None, length=None, finite=True, infinite=True):
|
|
64
|
+
"""
|
|
65
|
+
Return the combinatorial class of words of length k over an alphabet.
|
|
66
|
+
|
|
67
|
+
EXAMPLES::
|
|
68
|
+
|
|
69
|
+
sage: Words()
|
|
70
|
+
Finite and infinite words over Set of Python objects of class 'object'
|
|
71
|
+
sage: Words(length=7)
|
|
72
|
+
Words of length 7 over Set of Python objects of class 'object'
|
|
73
|
+
sage: Words(5)
|
|
74
|
+
Finite and infinite words over {1, 2, 3, 4, 5}
|
|
75
|
+
sage: Words(5, 3)
|
|
76
|
+
Words of length 3 over {1, 2, 3, 4, 5}
|
|
77
|
+
sage: Words(5, infinite=False)
|
|
78
|
+
Finite words over {1, 2, 3, 4, 5}
|
|
79
|
+
sage: Words(5, finite=False)
|
|
80
|
+
Infinite words over {1, 2, 3, 4, 5}
|
|
81
|
+
sage: Words('ab')
|
|
82
|
+
Finite and infinite words over {'a', 'b'}
|
|
83
|
+
sage: Words('ab', 2)
|
|
84
|
+
Words of length 2 over {'a', 'b'}
|
|
85
|
+
sage: Words('ab', infinite=False)
|
|
86
|
+
Finite words over {'a', 'b'}
|
|
87
|
+
sage: Words('ab', finite=False)
|
|
88
|
+
Infinite words over {'a', 'b'}
|
|
89
|
+
sage: Words('positive integers', finite=False)
|
|
90
|
+
Infinite words over Positive integers
|
|
91
|
+
sage: Words('natural numbers')
|
|
92
|
+
Finite and infinite words over Non negative integers
|
|
93
|
+
"""
|
|
94
|
+
if isinstance(alphabet, (FiniteWords,
|
|
95
|
+
InfiniteWords,
|
|
96
|
+
FiniteOrInfiniteWords,
|
|
97
|
+
Words_n)):
|
|
98
|
+
return alphabet
|
|
99
|
+
|
|
100
|
+
if length is None:
|
|
101
|
+
if finite and infinite:
|
|
102
|
+
return FiniteOrInfiniteWords(alphabet)
|
|
103
|
+
elif finite:
|
|
104
|
+
return FiniteWords(alphabet)
|
|
105
|
+
elif infinite:
|
|
106
|
+
return InfiniteWords(alphabet)
|
|
107
|
+
else:
|
|
108
|
+
raise ValueError("either finite or infinite must be True")
|
|
109
|
+
|
|
110
|
+
elif isinstance(length, (int, Integer)):
|
|
111
|
+
return Words_n(FiniteWords(alphabet), length)
|
|
112
|
+
|
|
113
|
+
raise ValueError("do not know how to make a combinatorial class of words from your input")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class AbstractLanguage(Parent):
|
|
117
|
+
r"""
|
|
118
|
+
Abstract base class.
|
|
119
|
+
|
|
120
|
+
This is *not* to be used by any means. This class gather previous features
|
|
121
|
+
of set of words (prior to :issue:`19619`). In the future that class might
|
|
122
|
+
simply disappear or become a common base class for all languages. In the
|
|
123
|
+
latter case, its name would possibly change to ``Language``.
|
|
124
|
+
"""
|
|
125
|
+
def __init__(self, alphabet=None, category=None):
|
|
126
|
+
r"""
|
|
127
|
+
INPUT:
|
|
128
|
+
|
|
129
|
+
- ``alphabet`` -- the underlying alphabet
|
|
130
|
+
|
|
131
|
+
TESTS::
|
|
132
|
+
|
|
133
|
+
sage: loads(dumps(FiniteWords('ab'))) == FiniteWords('ab')
|
|
134
|
+
True
|
|
135
|
+
sage: loads(dumps(InfiniteWords('ab'))) == InfiniteWords('ab')
|
|
136
|
+
True
|
|
137
|
+
|
|
138
|
+
sage: Words('abc').sortkey_letters
|
|
139
|
+
<bound method AbstractLanguage._sortkey_trivial of ...>
|
|
140
|
+
sage: Words('bac').sortkey_letters
|
|
141
|
+
<bound method AbstractLanguage._sortkey_letters of ...>
|
|
142
|
+
"""
|
|
143
|
+
if isinstance(alphabet, (int, Integer)):
|
|
144
|
+
from sage.sets.integer_range import IntegerRange
|
|
145
|
+
alphabet = IntegerRange(1, alphabet + 1)
|
|
146
|
+
elif (alphabet == "integers" or
|
|
147
|
+
alphabet == "positive integers" or
|
|
148
|
+
alphabet == "natural numbers"):
|
|
149
|
+
alphabet = build_alphabet(name=alphabet)
|
|
150
|
+
else:
|
|
151
|
+
alphabet = build_alphabet(alphabet)
|
|
152
|
+
|
|
153
|
+
self._alphabet = alphabet
|
|
154
|
+
|
|
155
|
+
# Default sorting key: use rank()
|
|
156
|
+
self.sortkey_letters = self._sortkey_letters
|
|
157
|
+
|
|
158
|
+
# Check if we should use the trivial sorting key
|
|
159
|
+
N = alphabet.cardinality()
|
|
160
|
+
if N == Infinity:
|
|
161
|
+
self.sortkey_letters = self._sortkey_trivial
|
|
162
|
+
elif N < 36:
|
|
163
|
+
try:
|
|
164
|
+
if all(alphabet.unrank(i) > alphabet.unrank(j)
|
|
165
|
+
for i in range(N) for j in range(i)):
|
|
166
|
+
self.sortkey_letters = self._sortkey_trivial
|
|
167
|
+
except TypeError:
|
|
168
|
+
pass
|
|
169
|
+
|
|
170
|
+
if category is None:
|
|
171
|
+
category = Sets()
|
|
172
|
+
|
|
173
|
+
Parent.__init__(self, category=category)
|
|
174
|
+
|
|
175
|
+
def alphabet(self):
|
|
176
|
+
r"""
|
|
177
|
+
EXAMPLES::
|
|
178
|
+
|
|
179
|
+
sage: Words(NN).alphabet()
|
|
180
|
+
Non negative integer semiring
|
|
181
|
+
|
|
182
|
+
sage: InfiniteWords([1,2,3]).alphabet()
|
|
183
|
+
{1, 2, 3}
|
|
184
|
+
sage: InfiniteWords('ab').alphabet()
|
|
185
|
+
{'a', 'b'}
|
|
186
|
+
|
|
187
|
+
sage: FiniteWords([1,2,3]).alphabet()
|
|
188
|
+
{1, 2, 3}
|
|
189
|
+
sage: FiniteWords().alphabet()
|
|
190
|
+
Set of Python objects of class 'object'
|
|
191
|
+
"""
|
|
192
|
+
return self._alphabet
|
|
193
|
+
|
|
194
|
+
def identity_morphism(self):
|
|
195
|
+
r"""
|
|
196
|
+
Return the identity morphism from ``self`` to itself.
|
|
197
|
+
|
|
198
|
+
EXAMPLES::
|
|
199
|
+
|
|
200
|
+
sage: W = Words('ab')
|
|
201
|
+
sage: W.identity_morphism()
|
|
202
|
+
WordMorphism: a->a, b->b
|
|
203
|
+
|
|
204
|
+
::
|
|
205
|
+
|
|
206
|
+
sage: W = Words(range(3))
|
|
207
|
+
sage: W.identity_morphism()
|
|
208
|
+
WordMorphism: 0->0, 1->1, 2->2
|
|
209
|
+
|
|
210
|
+
There is no support yet for infinite alphabet::
|
|
211
|
+
|
|
212
|
+
sage: W = Words(alphabet=Alphabet(name='NN'))
|
|
213
|
+
sage: W
|
|
214
|
+
Finite and infinite words over Non negative integers
|
|
215
|
+
sage: W.identity_morphism()
|
|
216
|
+
Traceback (most recent call last):
|
|
217
|
+
...
|
|
218
|
+
NotImplementedError: size of alphabet must be finite
|
|
219
|
+
"""
|
|
220
|
+
if self.alphabet().cardinality() not in ZZ:
|
|
221
|
+
raise NotImplementedError('size of alphabet must be finite')
|
|
222
|
+
from sage.combinat.words.morphism import WordMorphism
|
|
223
|
+
return WordMorphism({a: a for a in self.alphabet()})
|
|
224
|
+
|
|
225
|
+
def _check(self, w, length=40):
|
|
226
|
+
r"""
|
|
227
|
+
Check that the first length elements are actually in the alphabet.
|
|
228
|
+
|
|
229
|
+
INPUT:
|
|
230
|
+
|
|
231
|
+
- ``w`` -- word
|
|
232
|
+
|
|
233
|
+
- ``length`` -- integer (default: `40`)
|
|
234
|
+
|
|
235
|
+
EXAMPLES::
|
|
236
|
+
|
|
237
|
+
sage: W = FiniteWords(['a','b','c'])
|
|
238
|
+
sage: W._check('abcabc') is None
|
|
239
|
+
True
|
|
240
|
+
sage: W._check('abcabcd')
|
|
241
|
+
Traceback (most recent call last):
|
|
242
|
+
...
|
|
243
|
+
ValueError: d not in alphabet
|
|
244
|
+
sage: W._check('abcabc'*10+'z') is None
|
|
245
|
+
True
|
|
246
|
+
sage: W._check('abcabc'*10+'z', length=80)
|
|
247
|
+
Traceback (most recent call last):
|
|
248
|
+
...
|
|
249
|
+
ValueError: z not in alphabet
|
|
250
|
+
"""
|
|
251
|
+
stop = None if length is None else int(length)
|
|
252
|
+
for a in itertools.islice(w, stop):
|
|
253
|
+
if a not in self.alphabet():
|
|
254
|
+
raise ValueError("%s not in alphabet" % a)
|
|
255
|
+
|
|
256
|
+
def _sortkey_trivial(self, letter1):
|
|
257
|
+
"""
|
|
258
|
+
Trivial function, used to sort the letters by their names.
|
|
259
|
+
|
|
260
|
+
INPUT:
|
|
261
|
+
|
|
262
|
+
- ``letter1`` -- a letter in the alphabet
|
|
263
|
+
|
|
264
|
+
EXAMPLES::
|
|
265
|
+
|
|
266
|
+
sage: W = FiniteWords('ade')
|
|
267
|
+
sage: W.sortkey_letters('d') # indirect doctest
|
|
268
|
+
'd'
|
|
269
|
+
"""
|
|
270
|
+
return letter1
|
|
271
|
+
|
|
272
|
+
def _sortkey_letters(self, letter1):
|
|
273
|
+
r"""
|
|
274
|
+
Return the default value used to sort the letters.
|
|
275
|
+
|
|
276
|
+
INPUT:
|
|
277
|
+
|
|
278
|
+
- ``letter1`` -- a letter in the alphabet
|
|
279
|
+
|
|
280
|
+
EXAMPLES::
|
|
281
|
+
|
|
282
|
+
sage: W = FiniteWords('woa')
|
|
283
|
+
sage: W.sortkey_letters('w') # indirect doctest
|
|
284
|
+
0
|
|
285
|
+
sage: W.sortkey_letters('o') # indirect doctest
|
|
286
|
+
1
|
|
287
|
+
sage: W.sortkey_letters('a') # indirect doctest
|
|
288
|
+
2
|
|
289
|
+
|
|
290
|
+
TESTS::
|
|
291
|
+
|
|
292
|
+
sage: assert W.sortkey_letters == W._sortkey_letters
|
|
293
|
+
"""
|
|
294
|
+
rk = self.alphabet().rank
|
|
295
|
+
return rk(letter1)
|
|
296
|
+
|
|
297
|
+
def __eq__(self, other) -> bool:
|
|
298
|
+
r"""
|
|
299
|
+
TESTS::
|
|
300
|
+
|
|
301
|
+
sage: FiniteWords() == FiniteWords()
|
|
302
|
+
True
|
|
303
|
+
sage: FiniteWords() == InfiniteWords()
|
|
304
|
+
False
|
|
305
|
+
sage: InfiniteWords() == Words()
|
|
306
|
+
False
|
|
307
|
+
sage: FiniteWords([0,1]) == FiniteWords([0,1,2,3])
|
|
308
|
+
False
|
|
309
|
+
"""
|
|
310
|
+
return self is other or (type(self) is type(other) and
|
|
311
|
+
self.alphabet() == other.alphabet())
|
|
312
|
+
|
|
313
|
+
def __ne__(self, other) -> bool:
|
|
314
|
+
r"""
|
|
315
|
+
TESTS::
|
|
316
|
+
|
|
317
|
+
sage: InfiniteWords() != InfiniteWords()
|
|
318
|
+
False
|
|
319
|
+
sage: FiniteWords() != Words()
|
|
320
|
+
True
|
|
321
|
+
sage: Words('ab') != Words('ab')
|
|
322
|
+
False
|
|
323
|
+
"""
|
|
324
|
+
return not (self == other)
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
class FiniteWords(AbstractLanguage):
|
|
328
|
+
r"""
|
|
329
|
+
The set of finite words over a fixed alphabet.
|
|
330
|
+
|
|
331
|
+
EXAMPLES::
|
|
332
|
+
|
|
333
|
+
sage: W = FiniteWords('ab')
|
|
334
|
+
sage: W
|
|
335
|
+
Finite words over {'a', 'b'}
|
|
336
|
+
|
|
337
|
+
TESTS::
|
|
338
|
+
|
|
339
|
+
sage: TestSuite(FiniteWords('ab')).run()
|
|
340
|
+
sage: TestSuite(FiniteWords([])).run()
|
|
341
|
+
sage: TestSuite(FiniteWords(['a'])).run()
|
|
342
|
+
"""
|
|
343
|
+
|
|
344
|
+
def __init__(self, alphabet=None, category=None):
|
|
345
|
+
"""
|
|
346
|
+
INPUT:
|
|
347
|
+
|
|
348
|
+
- ``alphabet`` -- the underlying alphabet
|
|
349
|
+
- ``category`` -- the suggested category of the set
|
|
350
|
+
(normally should be automatically determined)
|
|
351
|
+
|
|
352
|
+
TESTS::
|
|
353
|
+
|
|
354
|
+
sage: FiniteWords('ab').is_finite()
|
|
355
|
+
False
|
|
356
|
+
sage: FiniteWords('ab').category()
|
|
357
|
+
Category of infinite sets
|
|
358
|
+
sage: FiniteWords([]).is_finite()
|
|
359
|
+
True
|
|
360
|
+
sage: FiniteWords([]).category()
|
|
361
|
+
Category of finite sets
|
|
362
|
+
sage: FiniteWords([], Sets()).category()
|
|
363
|
+
Category of finite sets
|
|
364
|
+
"""
|
|
365
|
+
if category is None:
|
|
366
|
+
category = Sets()
|
|
367
|
+
if alphabet:
|
|
368
|
+
category = category.Infinite()
|
|
369
|
+
else:
|
|
370
|
+
category = category.Finite()
|
|
371
|
+
super().__init__(alphabet, category)
|
|
372
|
+
|
|
373
|
+
def is_empty(self):
|
|
374
|
+
"""
|
|
375
|
+
Return ``False``, because the empty word is in the set.
|
|
376
|
+
|
|
377
|
+
TESTS::
|
|
378
|
+
|
|
379
|
+
sage: FiniteWords('ab').is_empty()
|
|
380
|
+
False
|
|
381
|
+
sage: FiniteWords([]).is_empty()
|
|
382
|
+
False
|
|
383
|
+
"""
|
|
384
|
+
return False
|
|
385
|
+
|
|
386
|
+
def cardinality(self):
|
|
387
|
+
r"""
|
|
388
|
+
Return the cardinality of this set.
|
|
389
|
+
|
|
390
|
+
EXAMPLES::
|
|
391
|
+
|
|
392
|
+
sage: FiniteWords('').cardinality()
|
|
393
|
+
1
|
|
394
|
+
sage: FiniteWords('a').cardinality()
|
|
395
|
+
+Infinity
|
|
396
|
+
"""
|
|
397
|
+
if not self.alphabet():
|
|
398
|
+
return ZZ.one()
|
|
399
|
+
return Infinity
|
|
400
|
+
|
|
401
|
+
def __hash__(self):
|
|
402
|
+
r"""
|
|
403
|
+
TESTS::
|
|
404
|
+
|
|
405
|
+
sage: hash(FiniteWords('ab')) # random
|
|
406
|
+
12
|
|
407
|
+
"""
|
|
408
|
+
return hash(self.alphabet()) ^ hash('finite words')
|
|
409
|
+
|
|
410
|
+
@cached_method
|
|
411
|
+
def shift(self):
|
|
412
|
+
r"""
|
|
413
|
+
Return the set of infinite words on the same alphabet.
|
|
414
|
+
|
|
415
|
+
EXAMPLES::
|
|
416
|
+
|
|
417
|
+
sage: FiniteWords('ab').shift()
|
|
418
|
+
Infinite words over {'a', 'b'}
|
|
419
|
+
"""
|
|
420
|
+
return InfiniteWords(self.alphabet())
|
|
421
|
+
|
|
422
|
+
def factors(self):
|
|
423
|
+
r"""
|
|
424
|
+
Return itself.
|
|
425
|
+
|
|
426
|
+
EXAMPLES::
|
|
427
|
+
|
|
428
|
+
sage: FiniteWords('ab').factors()
|
|
429
|
+
Finite words over {'a', 'b'}
|
|
430
|
+
"""
|
|
431
|
+
return self
|
|
432
|
+
|
|
433
|
+
@lazy_attribute
|
|
434
|
+
def _element_classes(self):
|
|
435
|
+
r"""
|
|
436
|
+
Return a dictionary that gives the class of the element of ``self``.
|
|
437
|
+
|
|
438
|
+
The word may be finite, infinite or of unknown length.
|
|
439
|
+
Its data may be string, list, tuple, a callable or an iterable.
|
|
440
|
+
For callable and iterable, the data may be cached.
|
|
441
|
+
|
|
442
|
+
EXAMPLES:
|
|
443
|
+
|
|
444
|
+
Once you get the class, it can be used to create a new word::
|
|
445
|
+
|
|
446
|
+
sage: W = FiniteWords([0,1,2])
|
|
447
|
+
sage: L = [0,1,0] * 100
|
|
448
|
+
sage: cls = W._element_classes['list']
|
|
449
|
+
sage: w = cls(W, L)
|
|
450
|
+
sage: type(w)
|
|
451
|
+
<class 'sage.combinat.words.word.FiniteWord_list'>
|
|
452
|
+
sage: w
|
|
453
|
+
word: 0100100100100100100100100100100100100100...
|
|
454
|
+
sage: w.parent()
|
|
455
|
+
Finite words over {0, 1, 2}
|
|
456
|
+
|
|
457
|
+
TESTS::
|
|
458
|
+
|
|
459
|
+
sage: d = FiniteWords()._element_classes
|
|
460
|
+
sage: type(d)
|
|
461
|
+
<class 'dict'>
|
|
462
|
+
sage: len(d)
|
|
463
|
+
7
|
|
464
|
+
sage: e = FiniteWords('abcdefg')._element_classes
|
|
465
|
+
sage: d == e
|
|
466
|
+
True
|
|
467
|
+
"""
|
|
468
|
+
import sage.combinat.words.word as word
|
|
469
|
+
classes = {
|
|
470
|
+
'list': word.FiniteWord_list,
|
|
471
|
+
'str': word.FiniteWord_str,
|
|
472
|
+
'tuple': word.FiniteWord_tuple,
|
|
473
|
+
'callable_with_caching': word.FiniteWord_callable_with_caching,
|
|
474
|
+
'callable': word.FiniteWord_callable,
|
|
475
|
+
'iter_with_caching': word.FiniteWord_iter_with_caching,
|
|
476
|
+
'iter': word.FiniteWord_iter}
|
|
477
|
+
|
|
478
|
+
# test whether or not we can use the class Finiteword_char
|
|
479
|
+
if (self.alphabet().cardinality() <= 256 and
|
|
480
|
+
all(isinstance(i, (int, Integer)) and
|
|
481
|
+
0 <= i < 256 for i in self.alphabet())):
|
|
482
|
+
L = self.alphabet().list()
|
|
483
|
+
key = self.sortkey_letters
|
|
484
|
+
if (all(L[i] < L[i + 1] for i in range(len(L) - 1)) and
|
|
485
|
+
all(key(L[i]) < key(L[i + 1]) for i in range(len(L) - 1))):
|
|
486
|
+
classes['char'] = word.FiniteWord_char
|
|
487
|
+
|
|
488
|
+
return classes
|
|
489
|
+
|
|
490
|
+
def _word_from_word(self, data):
|
|
491
|
+
r"""
|
|
492
|
+
Return a word from a word.
|
|
493
|
+
|
|
494
|
+
The data is assumed to be ok, no check is performed.
|
|
495
|
+
|
|
496
|
+
INPUT:
|
|
497
|
+
|
|
498
|
+
- ``data`` -- word
|
|
499
|
+
|
|
500
|
+
EXAMPLES::
|
|
501
|
+
|
|
502
|
+
sage: W = FiniteWords([0,1,2])
|
|
503
|
+
sage: w = W([0,1,2,0,1,2])
|
|
504
|
+
sage: z = W._word_from_word(w)
|
|
505
|
+
sage: z
|
|
506
|
+
word: 012012
|
|
507
|
+
sage: w is z
|
|
508
|
+
True
|
|
509
|
+
"""
|
|
510
|
+
####################
|
|
511
|
+
# If `data` is already a word and if its parent is self, then
|
|
512
|
+
# return `data`.
|
|
513
|
+
###########################
|
|
514
|
+
if data.parent() is self or data.parent() == self:
|
|
515
|
+
return data
|
|
516
|
+
|
|
517
|
+
###########################
|
|
518
|
+
# Otherwise, if self is not the parent of `data`, then we try to
|
|
519
|
+
# recover the data, the length and the datatype of the input `data`
|
|
520
|
+
# To minimize the impact of the import, we do it only at the time there
|
|
521
|
+
# are needed
|
|
522
|
+
###########################
|
|
523
|
+
from sage.combinat.words.word_char import WordDatatype_char
|
|
524
|
+
if isinstance(data, WordDatatype_char):
|
|
525
|
+
data = list(data)
|
|
526
|
+
if 'char' in self._element_classes:
|
|
527
|
+
return self._element_classes['char'](self, data)
|
|
528
|
+
else:
|
|
529
|
+
return self._element_classes['list'](self, data)
|
|
530
|
+
|
|
531
|
+
from sage.combinat.words.word_datatypes import (WordDatatype_str,
|
|
532
|
+
WordDatatype_list,
|
|
533
|
+
WordDatatype_tuple)
|
|
534
|
+
if isinstance(data, WordDatatype_str):
|
|
535
|
+
return self._element_classes['str'](self, data._data)
|
|
536
|
+
if isinstance(data, WordDatatype_tuple):
|
|
537
|
+
return self._element_classes['tuple'](self, data._data)
|
|
538
|
+
if isinstance(data, WordDatatype_list):
|
|
539
|
+
return self._element_classes['list'](self, data._data)
|
|
540
|
+
|
|
541
|
+
from sage.combinat.words.word_infinite_datatypes import \
|
|
542
|
+
(WordDatatype_callable, WordDatatype_iter)
|
|
543
|
+
if isinstance(data, WordDatatype_callable):
|
|
544
|
+
length = data.length()
|
|
545
|
+
data = data._func
|
|
546
|
+
return self._word_from_callable(data, length, caching=False)
|
|
547
|
+
if isinstance(data, WordDatatype_iter):
|
|
548
|
+
length = data.length()
|
|
549
|
+
data = iter(data)
|
|
550
|
+
return self._word_from_iter(data, length, caching=False)
|
|
551
|
+
|
|
552
|
+
raise TypeError("any instance of Word_class must be an instance of WordDatatype")
|
|
553
|
+
|
|
554
|
+
def _word_from_callable(self, data, length, caching=True):
|
|
555
|
+
r"""
|
|
556
|
+
Return a word represented by a callable.
|
|
557
|
+
|
|
558
|
+
The data is assumed to be ok, no check is performed.
|
|
559
|
+
|
|
560
|
+
INPUT:
|
|
561
|
+
|
|
562
|
+
- ``data`` -- callable
|
|
563
|
+
- ``length`` -- integer or ``None`` or ``'infinite'`` or ``Infinity``
|
|
564
|
+
- ``caching`` -- boolean (default: ``True``); whether to keep a cache
|
|
565
|
+
of the letters computed by the callable
|
|
566
|
+
|
|
567
|
+
EXAMPLES::
|
|
568
|
+
|
|
569
|
+
sage: W = FiniteWords([0,1,2])
|
|
570
|
+
sage: f = lambda n : n % 3
|
|
571
|
+
sage: W._word_from_callable(f, 100)
|
|
572
|
+
word: 0120120120120120120120120120120120120120...
|
|
573
|
+
"""
|
|
574
|
+
wc = '_with_caching' if caching else ""
|
|
575
|
+
if length not in ZZ or length < 0:
|
|
576
|
+
raise ValueError("not a correct value for length (%s)" % length)
|
|
577
|
+
return self._element_classes['callable' + wc](self, data, length)
|
|
578
|
+
|
|
579
|
+
def _word_from_iter(self, data, length=None, caching=True):
|
|
580
|
+
r"""
|
|
581
|
+
Return a word represented by an iterator.
|
|
582
|
+
|
|
583
|
+
The data is assumed to be ok, no check is performed.
|
|
584
|
+
|
|
585
|
+
INPUT:
|
|
586
|
+
|
|
587
|
+
- ``data`` -- iterable
|
|
588
|
+
|
|
589
|
+
- ``length`` -- (optional) integer
|
|
590
|
+
|
|
591
|
+
- ``caching`` -- boolean (default: ``True``); whether to keep a cache
|
|
592
|
+
of the letters computed by the iterator
|
|
593
|
+
|
|
594
|
+
EXAMPLES::
|
|
595
|
+
|
|
596
|
+
sage: W = FiniteWords([0,1,2])
|
|
597
|
+
sage: W._word_from_iter(iter([1]*10))
|
|
598
|
+
word: 1111111111
|
|
599
|
+
sage: W._word_from_iter(iter([1]*10), 5)
|
|
600
|
+
word: 11111
|
|
601
|
+
"""
|
|
602
|
+
wc = '_with_caching' if caching else ""
|
|
603
|
+
if length is None or length == "finite":
|
|
604
|
+
length = "finite"
|
|
605
|
+
elif length not in ZZ or length < 0:
|
|
606
|
+
raise ValueError("not a correct value for length (%s)" % length)
|
|
607
|
+
return self._element_classes['iter' + wc](self, data, length)
|
|
608
|
+
|
|
609
|
+
def __call__(self, data=None, length=None, datatype=None, caching=True, check=True):
|
|
610
|
+
r"""
|
|
611
|
+
Construct a new word object with parent ``self``.
|
|
612
|
+
|
|
613
|
+
INPUT:
|
|
614
|
+
|
|
615
|
+
- ``data`` -- (default: ``None``) list, string, tuple, iterator, ``None``
|
|
616
|
+
(shorthand for []), or a callable defined on [0,1,...,length]
|
|
617
|
+
|
|
618
|
+
- ``length`` -- integer (default: ``None``); only used if the data is
|
|
619
|
+
an iterator or a callable. It determines the length of the word
|
|
620
|
+
|
|
621
|
+
- ``datatype`` -- (default: ``None``) ``None``, "char", "list", "str",
|
|
622
|
+
"tuple", "iter", "callable" or "pickled_function"; if ``None``, then
|
|
623
|
+
the function tries to guess this from the data
|
|
624
|
+
|
|
625
|
+
- ``caching`` -- boolean (default: ``True``); whether to keep a cache
|
|
626
|
+
of the letters computed by an iterator or callable
|
|
627
|
+
|
|
628
|
+
- ``check`` -- boolean (default: ``True``); whether to check if
|
|
629
|
+
the 40 first letters are in the parent alphabet. This is a
|
|
630
|
+
check done to test for small programming errors. Since we also
|
|
631
|
+
support infinite words, we cannot really implement a more
|
|
632
|
+
accurate check.
|
|
633
|
+
|
|
634
|
+
.. NOTE::
|
|
635
|
+
|
|
636
|
+
The check makes this method about 10 times slower (20µs instead
|
|
637
|
+
of 2µs), so make sure to set it to False if you know the
|
|
638
|
+
alphabet is OK. Fast creation (about 1µs) of a word can be
|
|
639
|
+
done using the class directly (see :meth:`_element_classes`).
|
|
640
|
+
|
|
641
|
+
.. WARNING::
|
|
642
|
+
|
|
643
|
+
Be careful when defining words using callables and iterators. It
|
|
644
|
+
appears that islice does not pickle correctly causing various errors
|
|
645
|
+
when reloading. Also, most iterators do not support copying and
|
|
646
|
+
should not support pickling by extension.
|
|
647
|
+
|
|
648
|
+
EXAMPLES::
|
|
649
|
+
|
|
650
|
+
sage: W = FiniteWords()
|
|
651
|
+
|
|
652
|
+
Empty word::
|
|
653
|
+
|
|
654
|
+
sage: W()
|
|
655
|
+
word:
|
|
656
|
+
|
|
657
|
+
Word with string::
|
|
658
|
+
|
|
659
|
+
sage: W("abbabaab")
|
|
660
|
+
word: abbabaab
|
|
661
|
+
|
|
662
|
+
Word with string constructed from other types::
|
|
663
|
+
|
|
664
|
+
sage: W([0,1,1,0,1,0,0,1], datatype='str')
|
|
665
|
+
word: 01101001
|
|
666
|
+
sage: W((0,1,1,0,1,0,0,1), datatype='str')
|
|
667
|
+
word: 01101001
|
|
668
|
+
|
|
669
|
+
Word with list::
|
|
670
|
+
|
|
671
|
+
sage: W([0,1,1,0,1,0,0,1])
|
|
672
|
+
word: 01101001
|
|
673
|
+
|
|
674
|
+
Word with list constructed from other types::
|
|
675
|
+
|
|
676
|
+
sage: W("01101001", datatype='list')
|
|
677
|
+
word: 01101001
|
|
678
|
+
sage: W((0,1,1,0,1,0,0,1), datatype='list')
|
|
679
|
+
word: 01101001
|
|
680
|
+
|
|
681
|
+
Word with tuple::
|
|
682
|
+
|
|
683
|
+
sage: W((0,1,1,0,1,0,0,1))
|
|
684
|
+
word: 01101001
|
|
685
|
+
|
|
686
|
+
Word with tuple constructed from other types::
|
|
687
|
+
|
|
688
|
+
sage: W([0,1,1,0,1,0,0,1], datatype='tuple')
|
|
689
|
+
word: 01101001
|
|
690
|
+
sage: W("01101001", datatype='str')
|
|
691
|
+
word: 01101001
|
|
692
|
+
|
|
693
|
+
Word with iterator::
|
|
694
|
+
|
|
695
|
+
sage: from itertools import count
|
|
696
|
+
sage: W(count(), length=10)
|
|
697
|
+
word: 0123456789
|
|
698
|
+
sage: W(iter("abbabaab"))
|
|
699
|
+
word: abbabaab
|
|
700
|
+
|
|
701
|
+
Word with function (a 'callable')::
|
|
702
|
+
|
|
703
|
+
sage: f = lambda n : add(Integer(n).digits(2)) % 2
|
|
704
|
+
sage: W(f, length=12)
|
|
705
|
+
word: 011010011001
|
|
706
|
+
sage: FiniteWords([0,1,2])(f, length=12)
|
|
707
|
+
word: 011010011001
|
|
708
|
+
|
|
709
|
+
Word over a string with a parent::
|
|
710
|
+
|
|
711
|
+
sage: w = FiniteWords('abc')("abbabaab"); w
|
|
712
|
+
word: abbabaab
|
|
713
|
+
sage: w.parent()
|
|
714
|
+
Finite words over {'a', 'b', 'c'}
|
|
715
|
+
|
|
716
|
+
The fourty first letters of the word are checked if they are in the
|
|
717
|
+
parent alphabet::
|
|
718
|
+
|
|
719
|
+
sage: FiniteWords("ab")("abca")
|
|
720
|
+
Traceback (most recent call last):
|
|
721
|
+
...
|
|
722
|
+
ValueError: c not in alphabet
|
|
723
|
+
sage: FiniteWords("ab")("abca", check=False)
|
|
724
|
+
word: abca
|
|
725
|
+
|
|
726
|
+
The default parent is the combinatorial class of all words::
|
|
727
|
+
|
|
728
|
+
sage: w = Word("abbabaab"); w
|
|
729
|
+
word: abbabaab
|
|
730
|
+
sage: w.parent()
|
|
731
|
+
Finite words over Set of Python objects of class 'object'
|
|
732
|
+
|
|
733
|
+
Creation of a word from a word::
|
|
734
|
+
|
|
735
|
+
sage: FiniteWords([0,1,2,3])(FiniteWords([2,3])([2,2,2,3,3,2]))
|
|
736
|
+
word: 222332
|
|
737
|
+
sage: _.parent()
|
|
738
|
+
Finite words over {0, 1, 2, 3}
|
|
739
|
+
|
|
740
|
+
::
|
|
741
|
+
|
|
742
|
+
sage: FiniteWords([3,2,1])(FiniteWords([2,3])([2,2,2,3,3,2]))
|
|
743
|
+
word: 222332
|
|
744
|
+
sage: _.parent()
|
|
745
|
+
Finite words over {3, 2, 1}
|
|
746
|
+
|
|
747
|
+
Construction of a word from a word when the parents are the same::
|
|
748
|
+
|
|
749
|
+
sage: W = FiniteWords()
|
|
750
|
+
sage: w = W(range(8))
|
|
751
|
+
sage: z = W(w)
|
|
752
|
+
sage: w is z
|
|
753
|
+
True
|
|
754
|
+
|
|
755
|
+
Construction of a word path from a finite word::
|
|
756
|
+
|
|
757
|
+
sage: W = FiniteWords('abcd')
|
|
758
|
+
sage: P = WordPaths('abcd') # needs sage.modules
|
|
759
|
+
sage: w = W('aaab')
|
|
760
|
+
sage: P(w) # needs sage.modules
|
|
761
|
+
Path: aaab
|
|
762
|
+
|
|
763
|
+
Construction of a word path from a Christoffel word::
|
|
764
|
+
|
|
765
|
+
sage: w = words.ChristoffelWord(5,8)
|
|
766
|
+
sage: w
|
|
767
|
+
word: 0010010100101
|
|
768
|
+
sage: P = WordPaths([0,1,2,3]) # needs sage.modules
|
|
769
|
+
sage: P(w) # needs sage.modules
|
|
770
|
+
Path: 0010010100101
|
|
771
|
+
|
|
772
|
+
Construction of a word represented by a list from a word
|
|
773
|
+
represented by a str ::
|
|
774
|
+
|
|
775
|
+
sage: w = W('ababbbabab')
|
|
776
|
+
sage: type(w)
|
|
777
|
+
<class 'sage.combinat.words.word.FiniteWord_str'>
|
|
778
|
+
sage: z = Word(w, datatype='list')
|
|
779
|
+
sage: type(z)
|
|
780
|
+
<class 'sage.combinat.words.word.FiniteWord_list'>
|
|
781
|
+
sage: y = Word(w, alphabet='abc', datatype='list')
|
|
782
|
+
sage: type(y)
|
|
783
|
+
<class 'sage.combinat.words.word.FiniteWord_list'>
|
|
784
|
+
|
|
785
|
+
Creation of a word from a concatenation of words::
|
|
786
|
+
|
|
787
|
+
sage: W = FiniteWords()
|
|
788
|
+
sage: w = W() * W('a')
|
|
789
|
+
sage: Z = Words('ab')
|
|
790
|
+
sage: Z(w)
|
|
791
|
+
word: a
|
|
792
|
+
|
|
793
|
+
Creation of a word path from a FiniteWord_iter::
|
|
794
|
+
|
|
795
|
+
sage: w = words.FibonacciWord()
|
|
796
|
+
sage: f = w[:100]
|
|
797
|
+
sage: P = WordPaths([0,1,2,3]) # needs sage.modules
|
|
798
|
+
sage: p = P(f); p # needs sage.modules
|
|
799
|
+
Path: 0100101001001010010100100101001001010010...
|
|
800
|
+
sage: p.length() # needs sage.modules
|
|
801
|
+
100
|
|
802
|
+
|
|
803
|
+
Creation of a word path from a FiniteWord_callable::
|
|
804
|
+
|
|
805
|
+
sage: g = W(lambda n:n%2, length = 100)
|
|
806
|
+
sage: P = WordPaths([0,1,2,3]) # needs sage.modules
|
|
807
|
+
sage: p = P(g); p # needs sage.modules
|
|
808
|
+
Path: 0101010101010101010101010101010101010101...
|
|
809
|
+
sage: p.length() # needs sage.modules
|
|
810
|
+
100
|
|
811
|
+
|
|
812
|
+
Creation of a word from a pickled function::
|
|
813
|
+
|
|
814
|
+
sage: f = lambda n : n % 10
|
|
815
|
+
sage: from sage.misc.fpickle import pickle_function
|
|
816
|
+
sage: s = pickle_function(f)
|
|
817
|
+
sage: W(s, length=10, datatype='pickled_function')
|
|
818
|
+
word: 0123456789
|
|
819
|
+
|
|
820
|
+
If the alphabet is a subset of [0, 255], then it uses char as datatype::
|
|
821
|
+
|
|
822
|
+
sage: type(Word([0,1,1,2,0], alphabet=list(range(256))))
|
|
823
|
+
<class 'sage.combinat.words.word.FiniteWord_char'>
|
|
824
|
+
|
|
825
|
+
If the alphabet is a subset of [0, 255], then the letters must
|
|
826
|
+
convert to an unsigned char. Otherwise an error is raised before
|
|
827
|
+
the check is done::
|
|
828
|
+
|
|
829
|
+
sage: type(Word([0,1,1,2,0,257], alphabet=list(range(256))))
|
|
830
|
+
Traceback (most recent call last):
|
|
831
|
+
...
|
|
832
|
+
OverflowError: value too large to convert to unsigned char
|
|
833
|
+
sage: type(Word([0,1,1,2,0,258], alphabet=list(range(257))))
|
|
834
|
+
Traceback (most recent call last):
|
|
835
|
+
...
|
|
836
|
+
ValueError: 258 not in alphabet
|
|
837
|
+
sage: type(Word([0,1,1,2,0,103], alphabet=list(range(100))))
|
|
838
|
+
Traceback (most recent call last):
|
|
839
|
+
...
|
|
840
|
+
ValueError: 103 not in alphabet
|
|
841
|
+
"""
|
|
842
|
+
if datatype is not None:
|
|
843
|
+
if datatype == 'list':
|
|
844
|
+
w = self._element_classes['list'](self, data)
|
|
845
|
+
elif datatype == 'char':
|
|
846
|
+
w = self._element_classes['char'](self, data)
|
|
847
|
+
elif datatype == 'tuple':
|
|
848
|
+
w = self._element_classes['tuple'](self, data)
|
|
849
|
+
elif datatype == 'str':
|
|
850
|
+
w = self._element_classes['str'](self, data)
|
|
851
|
+
elif datatype == 'callable':
|
|
852
|
+
w = self._word_from_callable(data, length, caching)
|
|
853
|
+
elif datatype == 'iter':
|
|
854
|
+
w = self._word_from_iter(data, length, caching)
|
|
855
|
+
elif datatype == 'pickled_function':
|
|
856
|
+
from sage.misc.fpickle import unpickle_function
|
|
857
|
+
data = unpickle_function(data)
|
|
858
|
+
w = self._word_from_callable(data, length, caching)
|
|
859
|
+
else:
|
|
860
|
+
raise ValueError("unknown datatype (={})".format(datatype))
|
|
861
|
+
|
|
862
|
+
elif 'char' in self._element_classes:
|
|
863
|
+
if data is None:
|
|
864
|
+
data = []
|
|
865
|
+
elif callable(data):
|
|
866
|
+
data = [data(i) for i in range(length)]
|
|
867
|
+
elif not isinstance(data, (tuple, list)):
|
|
868
|
+
data = list(data)
|
|
869
|
+
w = self._element_classes['char'](self, data)
|
|
870
|
+
|
|
871
|
+
elif isinstance(data, list):
|
|
872
|
+
w = self._element_classes['list'](self, data)
|
|
873
|
+
|
|
874
|
+
elif data is None:
|
|
875
|
+
w = self._element_classes['list'](self, [])
|
|
876
|
+
|
|
877
|
+
elif isinstance(data, str):
|
|
878
|
+
w = self._element_classes['str'](self, data)
|
|
879
|
+
|
|
880
|
+
elif isinstance(data, tuple):
|
|
881
|
+
w = self._element_classes['tuple'](self, data)
|
|
882
|
+
|
|
883
|
+
elif isinstance(data, (CombinatorialObject, ClonableElement)):
|
|
884
|
+
w = self._element_classes['list'](self, list(data))
|
|
885
|
+
|
|
886
|
+
elif callable(data):
|
|
887
|
+
w = self._word_from_callable(data, length, caching)
|
|
888
|
+
|
|
889
|
+
elif isinstance(data, Iterable):
|
|
890
|
+
from sage.combinat.words.abstract_word import Word_class
|
|
891
|
+
if isinstance(data, Word_class):
|
|
892
|
+
w = self._word_from_word(data)
|
|
893
|
+
else:
|
|
894
|
+
w = self._word_from_iter(data, length, caching)
|
|
895
|
+
|
|
896
|
+
else:
|
|
897
|
+
raise ValueError("cannot guess a datatype from data (=%s); please specify one" % data)
|
|
898
|
+
|
|
899
|
+
if check:
|
|
900
|
+
self._check(w)
|
|
901
|
+
return w
|
|
902
|
+
|
|
903
|
+
def _repr_(self) -> str:
|
|
904
|
+
"""
|
|
905
|
+
EXAMPLES::
|
|
906
|
+
|
|
907
|
+
sage: FiniteWords() # indirect doctest
|
|
908
|
+
Finite words over Set of Python objects of class 'object'
|
|
909
|
+
"""
|
|
910
|
+
return 'Finite words over {!r}'.format(self.alphabet())
|
|
911
|
+
|
|
912
|
+
def _an_element_(self):
|
|
913
|
+
r"""
|
|
914
|
+
Return an element of ``self``.
|
|
915
|
+
|
|
916
|
+
EXAMPLES::
|
|
917
|
+
|
|
918
|
+
sage: FiniteWords(4).an_element() # indirect doctest
|
|
919
|
+
word: 212
|
|
920
|
+
sage: FiniteWords([5, 1, 9]).an_element() # indirect doctest
|
|
921
|
+
word: 151
|
|
922
|
+
sage: FiniteWords([1]).an_element() # indirect doctest
|
|
923
|
+
word: 111
|
|
924
|
+
sage: FiniteWords(NN).an_element() # indirect doctest
|
|
925
|
+
word: 101
|
|
926
|
+
"""
|
|
927
|
+
try:
|
|
928
|
+
some_letters = list(self.alphabet().some_elements())
|
|
929
|
+
except (TypeError, ValueError, AttributeError, NotImplementedError):
|
|
930
|
+
return self([])
|
|
931
|
+
|
|
932
|
+
if len(some_letters) == 0:
|
|
933
|
+
return self([])
|
|
934
|
+
if len(some_letters) == 1:
|
|
935
|
+
return self([some_letters[0]] * 3)
|
|
936
|
+
|
|
937
|
+
a, b = some_letters[:2]
|
|
938
|
+
return self([b, a, b])
|
|
939
|
+
|
|
940
|
+
def iterate_by_length(self, l=1):
|
|
941
|
+
r"""
|
|
942
|
+
Return an iterator over all the words of ``self`` of length `l`.
|
|
943
|
+
|
|
944
|
+
INPUT:
|
|
945
|
+
|
|
946
|
+
- ``l`` -- integer (default: 1); the length of the desired words
|
|
947
|
+
|
|
948
|
+
EXAMPLES::
|
|
949
|
+
|
|
950
|
+
sage: W = FiniteWords('ab')
|
|
951
|
+
sage: list(W.iterate_by_length(1))
|
|
952
|
+
[word: a, word: b]
|
|
953
|
+
sage: list(W.iterate_by_length(2))
|
|
954
|
+
[word: aa, word: ab, word: ba, word: bb]
|
|
955
|
+
sage: list(W.iterate_by_length(3))
|
|
956
|
+
[word: aaa,
|
|
957
|
+
word: aab,
|
|
958
|
+
word: aba,
|
|
959
|
+
word: abb,
|
|
960
|
+
word: baa,
|
|
961
|
+
word: bab,
|
|
962
|
+
word: bba,
|
|
963
|
+
word: bbb]
|
|
964
|
+
sage: list(W.iterate_by_length('a'))
|
|
965
|
+
Traceback (most recent call last):
|
|
966
|
+
...
|
|
967
|
+
TypeError: the parameter l (='a') must be an integer
|
|
968
|
+
|
|
969
|
+
TESTS::
|
|
970
|
+
|
|
971
|
+
sage: W = FiniteWords(NN)
|
|
972
|
+
sage: list(W.iterate_by_length(1))
|
|
973
|
+
Traceback (most recent call last):
|
|
974
|
+
...
|
|
975
|
+
NotImplementedError: cannot iterate over words for infinite alphabets
|
|
976
|
+
"""
|
|
977
|
+
if not isinstance(l, (int, Integer)):
|
|
978
|
+
raise TypeError("the parameter l (=%r) must be an integer" % l)
|
|
979
|
+
cls = self._element_classes['tuple']
|
|
980
|
+
if not self.alphabet().is_finite():
|
|
981
|
+
raise NotImplementedError("cannot iterate over words for infinite alphabets")
|
|
982
|
+
for w in itertools.product(self.alphabet(), repeat=l):
|
|
983
|
+
yield cls(self, w)
|
|
984
|
+
|
|
985
|
+
def __iter__(self):
|
|
986
|
+
r"""
|
|
987
|
+
Return an iterator over all the words of ``self``.
|
|
988
|
+
|
|
989
|
+
The iterator outputs the words in shortlex order (see
|
|
990
|
+
:wikipedia:`Shortlex_order`), i.e. first by increasing length and then
|
|
991
|
+
lexicographically.
|
|
992
|
+
|
|
993
|
+
EXAMPLES::
|
|
994
|
+
|
|
995
|
+
sage: W = Words([4,5], infinite=False)
|
|
996
|
+
sage: for w in W:
|
|
997
|
+
....: if len(w)>3:
|
|
998
|
+
....: break
|
|
999
|
+
....: else:
|
|
1000
|
+
....: w
|
|
1001
|
+
word:
|
|
1002
|
+
word: 4
|
|
1003
|
+
word: 5
|
|
1004
|
+
word: 44
|
|
1005
|
+
word: 45
|
|
1006
|
+
...
|
|
1007
|
+
word: 554
|
|
1008
|
+
word: 555
|
|
1009
|
+
sage: W = Words([5,4], infinite=False)
|
|
1010
|
+
sage: for w in W:
|
|
1011
|
+
....: if len(w)>3:
|
|
1012
|
+
....: break
|
|
1013
|
+
....: else:
|
|
1014
|
+
....: w
|
|
1015
|
+
word:
|
|
1016
|
+
word: 5
|
|
1017
|
+
word: 4
|
|
1018
|
+
word: 55
|
|
1019
|
+
word: 54
|
|
1020
|
+
...
|
|
1021
|
+
word: 445
|
|
1022
|
+
word: 444
|
|
1023
|
+
"""
|
|
1024
|
+
for l in itertools.count():
|
|
1025
|
+
yield from self.iterate_by_length(l)
|
|
1026
|
+
|
|
1027
|
+
def __contains__(self, x) -> bool:
|
|
1028
|
+
"""
|
|
1029
|
+
Test whether ``self`` contains ``x``.
|
|
1030
|
+
|
|
1031
|
+
OUTPUT:
|
|
1032
|
+
|
|
1033
|
+
This method returns ``True`` if ``x`` is a word of the appropriate
|
|
1034
|
+
length and the alphabets of the parents match. It returns ``False``
|
|
1035
|
+
otherwise.
|
|
1036
|
+
|
|
1037
|
+
EXAMPLES::
|
|
1038
|
+
|
|
1039
|
+
sage: W = FiniteWords('ab')
|
|
1040
|
+
sage: W('ab') in W
|
|
1041
|
+
True
|
|
1042
|
+
sage: W('aa') in FiniteWords('aa')
|
|
1043
|
+
False
|
|
1044
|
+
sage: FiniteWords('a')('aa') in FiniteWords('ab')
|
|
1045
|
+
False
|
|
1046
|
+
sage: 2 in FiniteWords([1,2,3])
|
|
1047
|
+
False
|
|
1048
|
+
sage: [2] in FiniteWords([1,2,3])
|
|
1049
|
+
False
|
|
1050
|
+
sage: [1, 'a'] in FiniteWords([1,2,3])
|
|
1051
|
+
False
|
|
1052
|
+
"""
|
|
1053
|
+
from sage.combinat.words.finite_word import FiniteWord_class
|
|
1054
|
+
return isinstance(x, FiniteWord_class) and x.parent().alphabet() == self.alphabet()
|
|
1055
|
+
|
|
1056
|
+
def random_element(self, length=None, *args, **kwds):
|
|
1057
|
+
r"""
|
|
1058
|
+
Return a random finite word on the given alphabet.
|
|
1059
|
+
|
|
1060
|
+
INPUT:
|
|
1061
|
+
|
|
1062
|
+
- ``length`` -- (optional) the length of the word; if not set, will use
|
|
1063
|
+
a uniformly random number between 0 and 10
|
|
1064
|
+
|
|
1065
|
+
- all other argument are transmitted to the random generator of the
|
|
1066
|
+
alphabet
|
|
1067
|
+
|
|
1068
|
+
EXAMPLES::
|
|
1069
|
+
|
|
1070
|
+
sage: W = FiniteWords(5)
|
|
1071
|
+
sage: W.random_element() # random
|
|
1072
|
+
word: 5114325445423521544531411434451152142155...
|
|
1073
|
+
|
|
1074
|
+
sage: W = FiniteWords(ZZ)
|
|
1075
|
+
sage: W.random_element() # random
|
|
1076
|
+
word: 5,-1,-1,-1,0,0,0,0,-3,-11
|
|
1077
|
+
sage: W.random_element(length=4, x=0, y=4) # random
|
|
1078
|
+
word: 1003
|
|
1079
|
+
|
|
1080
|
+
TESTS::
|
|
1081
|
+
|
|
1082
|
+
sage: _ = FiniteWords(GF(5)).random_element() # needs sage.rings.finite_rings
|
|
1083
|
+
"""
|
|
1084
|
+
if length is None:
|
|
1085
|
+
length = ZZ.random_element(0, 10)
|
|
1086
|
+
return self([self.alphabet().random_element(*args, **kwds)
|
|
1087
|
+
for x in range(length)])
|
|
1088
|
+
|
|
1089
|
+
def iter_morphisms(self, arg=None, codomain=None, min_length=1):
|
|
1090
|
+
r"""
|
|
1091
|
+
Iterate over all morphisms with domain ``self`` and the given
|
|
1092
|
+
codomain.
|
|
1093
|
+
|
|
1094
|
+
INPUT:
|
|
1095
|
+
|
|
1096
|
+
- ``arg`` -- (default: ``None``) it can be one of the following:
|
|
1097
|
+
|
|
1098
|
+
- ``None`` -- then the method iterates through all morphisms
|
|
1099
|
+
|
|
1100
|
+
- tuple `(a, b)` of two integers -- it specifies the range
|
|
1101
|
+
``range(a, b)`` of values to consider for the sum of the length
|
|
1102
|
+
of the image of each letter in the alphabet
|
|
1103
|
+
|
|
1104
|
+
- list of nonnegative integers -- the length of the list must be
|
|
1105
|
+
equal to the size of the alphabet, and the `i`-th integer of
|
|
1106
|
+
``arg`` determines the length of the word mapped to by the `i`-th
|
|
1107
|
+
letter of the (ordered) alphabet
|
|
1108
|
+
|
|
1109
|
+
- ``codomain`` -- (default: ``None``) a combinatorial class of words;
|
|
1110
|
+
by default, ``codomain`` is ``self``
|
|
1111
|
+
|
|
1112
|
+
- ``min_length`` -- nonnegative integer (default: 1); if ``arg`` is
|
|
1113
|
+
not specified, then iterate through all the morphisms where the
|
|
1114
|
+
length of the images of each letter in the alphabet is at least
|
|
1115
|
+
``min_length``. This is ignored if ``arg`` is a list.
|
|
1116
|
+
|
|
1117
|
+
OUTPUT: iterator
|
|
1118
|
+
|
|
1119
|
+
EXAMPLES:
|
|
1120
|
+
|
|
1121
|
+
Iterator over all non-erasing morphisms::
|
|
1122
|
+
|
|
1123
|
+
sage: W = FiniteWords('ab')
|
|
1124
|
+
sage: it = W.iter_morphisms()
|
|
1125
|
+
sage: for _ in range(7): next(it)
|
|
1126
|
+
WordMorphism: a->a, b->a
|
|
1127
|
+
WordMorphism: a->a, b->b
|
|
1128
|
+
WordMorphism: a->b, b->a
|
|
1129
|
+
WordMorphism: a->b, b->b
|
|
1130
|
+
WordMorphism: a->aa, b->a
|
|
1131
|
+
WordMorphism: a->aa, b->b
|
|
1132
|
+
WordMorphism: a->ab, b->a
|
|
1133
|
+
|
|
1134
|
+
Iterator over all morphisms including erasing morphisms::
|
|
1135
|
+
|
|
1136
|
+
sage: W = FiniteWords('ab')
|
|
1137
|
+
sage: it = W.iter_morphisms(min_length=0)
|
|
1138
|
+
sage: for _ in range(7): next(it)
|
|
1139
|
+
WordMorphism: a->, b->
|
|
1140
|
+
WordMorphism: a->a, b->
|
|
1141
|
+
WordMorphism: a->b, b->
|
|
1142
|
+
WordMorphism: a->, b->a
|
|
1143
|
+
WordMorphism: a->, b->b
|
|
1144
|
+
WordMorphism: a->aa, b->
|
|
1145
|
+
WordMorphism: a->ab, b->
|
|
1146
|
+
|
|
1147
|
+
Iterator over morphisms where the sum of the lengths of the images
|
|
1148
|
+
of the letters is in a specific range::
|
|
1149
|
+
|
|
1150
|
+
sage: for m in W.iter_morphisms((0, 3), min_length=0): m
|
|
1151
|
+
WordMorphism: a->aa, b->
|
|
1152
|
+
WordMorphism: a->ab, b->
|
|
1153
|
+
WordMorphism: a->ba, b->
|
|
1154
|
+
WordMorphism: a->bb, b->
|
|
1155
|
+
WordMorphism: a->a, b->a
|
|
1156
|
+
WordMorphism: a->a, b->b
|
|
1157
|
+
WordMorphism: a->b, b->a
|
|
1158
|
+
WordMorphism: a->b, b->b
|
|
1159
|
+
WordMorphism: a->a, b->
|
|
1160
|
+
WordMorphism: a->b, b->
|
|
1161
|
+
WordMorphism: a->, b->aa
|
|
1162
|
+
WordMorphism: a->, b->ab
|
|
1163
|
+
WordMorphism: a->, b->ba
|
|
1164
|
+
WordMorphism: a->, b->bb
|
|
1165
|
+
WordMorphism: a->, b->a
|
|
1166
|
+
WordMorphism: a->, b->b
|
|
1167
|
+
WordMorphism: a->, b->
|
|
1168
|
+
|
|
1169
|
+
::
|
|
1170
|
+
|
|
1171
|
+
sage: for m in W.iter_morphisms( (2, 4) ): m
|
|
1172
|
+
WordMorphism: a->aa, b->a
|
|
1173
|
+
WordMorphism: a->aa, b->b
|
|
1174
|
+
WordMorphism: a->ab, b->a
|
|
1175
|
+
WordMorphism: a->ab, b->b
|
|
1176
|
+
WordMorphism: a->ba, b->a
|
|
1177
|
+
WordMorphism: a->ba, b->b
|
|
1178
|
+
WordMorphism: a->bb, b->a
|
|
1179
|
+
WordMorphism: a->bb, b->b
|
|
1180
|
+
WordMorphism: a->a, b->aa
|
|
1181
|
+
WordMorphism: a->a, b->ab
|
|
1182
|
+
WordMorphism: a->a, b->ba
|
|
1183
|
+
WordMorphism: a->a, b->bb
|
|
1184
|
+
WordMorphism: a->b, b->aa
|
|
1185
|
+
WordMorphism: a->b, b->ab
|
|
1186
|
+
WordMorphism: a->b, b->ba
|
|
1187
|
+
WordMorphism: a->b, b->bb
|
|
1188
|
+
WordMorphism: a->a, b->a
|
|
1189
|
+
WordMorphism: a->a, b->b
|
|
1190
|
+
WordMorphism: a->b, b->a
|
|
1191
|
+
WordMorphism: a->b, b->b
|
|
1192
|
+
|
|
1193
|
+
Iterator over morphisms with specific image lengths::
|
|
1194
|
+
|
|
1195
|
+
sage: for m in W.iter_morphisms([0, 0]): m
|
|
1196
|
+
WordMorphism: a->, b->
|
|
1197
|
+
sage: for m in W.iter_morphisms([0, 1]): m
|
|
1198
|
+
WordMorphism: a->, b->a
|
|
1199
|
+
WordMorphism: a->, b->b
|
|
1200
|
+
sage: for m in W.iter_morphisms([2, 1]): m
|
|
1201
|
+
WordMorphism: a->aa, b->a
|
|
1202
|
+
WordMorphism: a->aa, b->b
|
|
1203
|
+
WordMorphism: a->ab, b->a
|
|
1204
|
+
WordMorphism: a->ab, b->b
|
|
1205
|
+
WordMorphism: a->ba, b->a
|
|
1206
|
+
WordMorphism: a->ba, b->b
|
|
1207
|
+
WordMorphism: a->bb, b->a
|
|
1208
|
+
WordMorphism: a->bb, b->b
|
|
1209
|
+
sage: for m in W.iter_morphisms([2, 2]): m
|
|
1210
|
+
WordMorphism: a->aa, b->aa
|
|
1211
|
+
WordMorphism: a->aa, b->ab
|
|
1212
|
+
WordMorphism: a->aa, b->ba
|
|
1213
|
+
WordMorphism: a->aa, b->bb
|
|
1214
|
+
WordMorphism: a->ab, b->aa
|
|
1215
|
+
WordMorphism: a->ab, b->ab
|
|
1216
|
+
WordMorphism: a->ab, b->ba
|
|
1217
|
+
WordMorphism: a->ab, b->bb
|
|
1218
|
+
WordMorphism: a->ba, b->aa
|
|
1219
|
+
WordMorphism: a->ba, b->ab
|
|
1220
|
+
WordMorphism: a->ba, b->ba
|
|
1221
|
+
WordMorphism: a->ba, b->bb
|
|
1222
|
+
WordMorphism: a->bb, b->aa
|
|
1223
|
+
WordMorphism: a->bb, b->ab
|
|
1224
|
+
WordMorphism: a->bb, b->ba
|
|
1225
|
+
WordMorphism: a->bb, b->bb
|
|
1226
|
+
|
|
1227
|
+
The codomain may be specified as well::
|
|
1228
|
+
|
|
1229
|
+
sage: Y = FiniteWords('xyz')
|
|
1230
|
+
sage: for m in W.iter_morphisms([0, 2], codomain=Y): m
|
|
1231
|
+
WordMorphism: a->, b->xx
|
|
1232
|
+
WordMorphism: a->, b->xy
|
|
1233
|
+
WordMorphism: a->, b->xz
|
|
1234
|
+
WordMorphism: a->, b->yx
|
|
1235
|
+
WordMorphism: a->, b->yy
|
|
1236
|
+
WordMorphism: a->, b->yz
|
|
1237
|
+
WordMorphism: a->, b->zx
|
|
1238
|
+
WordMorphism: a->, b->zy
|
|
1239
|
+
WordMorphism: a->, b->zz
|
|
1240
|
+
sage: for m in Y.iter_morphisms([0,2,1], codomain=W): m
|
|
1241
|
+
WordMorphism: x->, y->aa, z->a
|
|
1242
|
+
WordMorphism: x->, y->aa, z->b
|
|
1243
|
+
WordMorphism: x->, y->ab, z->a
|
|
1244
|
+
WordMorphism: x->, y->ab, z->b
|
|
1245
|
+
WordMorphism: x->, y->ba, z->a
|
|
1246
|
+
WordMorphism: x->, y->ba, z->b
|
|
1247
|
+
WordMorphism: x->, y->bb, z->a
|
|
1248
|
+
WordMorphism: x->, y->bb, z->b
|
|
1249
|
+
sage: it = W.iter_morphisms(codomain=Y)
|
|
1250
|
+
sage: for _ in range(10): next(it)
|
|
1251
|
+
WordMorphism: a->x, b->x
|
|
1252
|
+
WordMorphism: a->x, b->y
|
|
1253
|
+
WordMorphism: a->x, b->z
|
|
1254
|
+
WordMorphism: a->y, b->x
|
|
1255
|
+
WordMorphism: a->y, b->y
|
|
1256
|
+
WordMorphism: a->y, b->z
|
|
1257
|
+
WordMorphism: a->z, b->x
|
|
1258
|
+
WordMorphism: a->z, b->y
|
|
1259
|
+
WordMorphism: a->z, b->z
|
|
1260
|
+
WordMorphism: a->xx, b->x
|
|
1261
|
+
|
|
1262
|
+
TESTS::
|
|
1263
|
+
|
|
1264
|
+
sage: list(W.iter_morphisms([1,0]))
|
|
1265
|
+
[WordMorphism: a->a, b->, WordMorphism: a->b, b->]
|
|
1266
|
+
sage: list(W.iter_morphisms([0,0], codomain=Y))
|
|
1267
|
+
[WordMorphism: a->, b->]
|
|
1268
|
+
sage: list(W.iter_morphisms([0, 1, 2]))
|
|
1269
|
+
Traceback (most recent call last):
|
|
1270
|
+
...
|
|
1271
|
+
TypeError: arg (=[0, 1, 2]) must be an iterable of 2 integers
|
|
1272
|
+
sage: list(W.iter_morphisms([0, 'a']))
|
|
1273
|
+
Traceback (most recent call last):
|
|
1274
|
+
...
|
|
1275
|
+
TypeError: arg (=[0, 'a']) must be an iterable of 2 integers
|
|
1276
|
+
sage: list(W.iter_morphisms([0, 1], codomain='a'))
|
|
1277
|
+
Traceback (most recent call last):
|
|
1278
|
+
...
|
|
1279
|
+
TypeError: codomain (=a) must be an instance of FiniteWords
|
|
1280
|
+
"""
|
|
1281
|
+
n = self.alphabet().cardinality()
|
|
1282
|
+
min_length = max(min_length, 0)
|
|
1283
|
+
# create an iterable of compositions (all "compositions" if arg is
|
|
1284
|
+
# None, or [arg] otherwise)
|
|
1285
|
+
if arg is None:
|
|
1286
|
+
from sage.combinat.integer_lists.nn import IntegerListsNN
|
|
1287
|
+
compositions = IntegerListsNN(length=n, min_part=min_length)
|
|
1288
|
+
elif isinstance(arg, tuple):
|
|
1289
|
+
from sage.combinat.integer_lists import IntegerListsLex
|
|
1290
|
+
a, b = arg
|
|
1291
|
+
compositions = IntegerListsLex(min_sum=a, max_sum=b - 1,
|
|
1292
|
+
length=n, min_part=min_length)
|
|
1293
|
+
else:
|
|
1294
|
+
arg = list(arg)
|
|
1295
|
+
if (not len(arg) == n or not
|
|
1296
|
+
all(isinstance(a, (int, Integer)) for a in arg)):
|
|
1297
|
+
raise TypeError(
|
|
1298
|
+
"arg (=%s) must be an iterable of %s integers" % (arg, n))
|
|
1299
|
+
compositions = [arg]
|
|
1300
|
+
|
|
1301
|
+
# set the codomain
|
|
1302
|
+
if codomain is None:
|
|
1303
|
+
codomain = self
|
|
1304
|
+
elif isinstance(codomain, FiniteOrInfiniteWords):
|
|
1305
|
+
codomain = codomain.finite_words()
|
|
1306
|
+
elif not isinstance(codomain, FiniteWords):
|
|
1307
|
+
raise TypeError("codomain (=%s) must be an instance of FiniteWords" % codomain)
|
|
1308
|
+
|
|
1309
|
+
# iterate through the morphisms
|
|
1310
|
+
from sage.combinat.words.morphism import WordMorphism
|
|
1311
|
+
for composition in compositions:
|
|
1312
|
+
cuts = [0] + list(composition)
|
|
1313
|
+
for i in range(1, len(cuts)):
|
|
1314
|
+
cuts[i] += cuts[i - 1]
|
|
1315
|
+
s = cuts[-1] # same but better than s = sum(composition)
|
|
1316
|
+
for big_word in codomain.iterate_by_length(s):
|
|
1317
|
+
d = {}
|
|
1318
|
+
i = 0
|
|
1319
|
+
for a in self.alphabet():
|
|
1320
|
+
d[a] = big_word[cuts[i]:cuts[i + 1]]
|
|
1321
|
+
i += 1
|
|
1322
|
+
yield WordMorphism(d, codomain=codomain)
|
|
1323
|
+
|
|
1324
|
+
|
|
1325
|
+
class InfiniteWords(AbstractLanguage):
|
|
1326
|
+
def cardinality(self):
|
|
1327
|
+
r"""
|
|
1328
|
+
Return the cardinality of this set.
|
|
1329
|
+
|
|
1330
|
+
EXAMPLES::
|
|
1331
|
+
|
|
1332
|
+
sage: InfiniteWords('ab').cardinality()
|
|
1333
|
+
+Infinity
|
|
1334
|
+
sage: InfiniteWords('a').cardinality()
|
|
1335
|
+
1
|
|
1336
|
+
sage: InfiniteWords('').cardinality()
|
|
1337
|
+
0
|
|
1338
|
+
"""
|
|
1339
|
+
if not self.alphabet().cardinality():
|
|
1340
|
+
return ZZ.zero()
|
|
1341
|
+
elif self.alphabet().cardinality().is_one():
|
|
1342
|
+
return ZZ.one()
|
|
1343
|
+
else:
|
|
1344
|
+
return Infinity
|
|
1345
|
+
|
|
1346
|
+
def __hash__(self):
|
|
1347
|
+
r"""
|
|
1348
|
+
TESTS::
|
|
1349
|
+
|
|
1350
|
+
sage: hash(InfiniteWords('ab')) # random
|
|
1351
|
+
12
|
|
1352
|
+
"""
|
|
1353
|
+
return hash(self.alphabet()) ^ hash('infinite words')
|
|
1354
|
+
|
|
1355
|
+
@cached_method
|
|
1356
|
+
def factors(self):
|
|
1357
|
+
r"""
|
|
1358
|
+
Return the set of finite words on the same alphabet.
|
|
1359
|
+
|
|
1360
|
+
EXAMPLES::
|
|
1361
|
+
|
|
1362
|
+
sage: InfiniteWords('ab').factors()
|
|
1363
|
+
Finite words over {'a', 'b'}
|
|
1364
|
+
"""
|
|
1365
|
+
return FiniteWords(self.alphabet())
|
|
1366
|
+
|
|
1367
|
+
def shift(self):
|
|
1368
|
+
r"""
|
|
1369
|
+
Return itself.
|
|
1370
|
+
|
|
1371
|
+
EXAMPLES::
|
|
1372
|
+
|
|
1373
|
+
sage: InfiniteWords('ab').shift()
|
|
1374
|
+
Infinite words over {'a', 'b'}
|
|
1375
|
+
"""
|
|
1376
|
+
return self
|
|
1377
|
+
|
|
1378
|
+
@lazy_attribute
|
|
1379
|
+
def _element_classes(self):
|
|
1380
|
+
r"""
|
|
1381
|
+
Return a dictionary that gives the class of the element of ``self``.
|
|
1382
|
+
|
|
1383
|
+
The word may be finite, infinite or of unknown length.
|
|
1384
|
+
Its data may be string, list, tuple, a callable or an iterable.
|
|
1385
|
+
For callable and iterable, the data may be cached.
|
|
1386
|
+
|
|
1387
|
+
EXAMPLES:
|
|
1388
|
+
|
|
1389
|
+
Once you get the class, it can be used to create a new word::
|
|
1390
|
+
|
|
1391
|
+
sage: W = InfiniteWords([0,1,2])
|
|
1392
|
+
sage: cls = W._element_classes['iter_with_caching']
|
|
1393
|
+
sage: from itertools import count
|
|
1394
|
+
sage: w = cls(W, (i%3 for i in count()))
|
|
1395
|
+
sage: type(w)
|
|
1396
|
+
<class 'sage.combinat.words.word.InfiniteWord_iter_with_caching'>
|
|
1397
|
+
sage: w
|
|
1398
|
+
word: 0120120120120120120120120120120120120120...
|
|
1399
|
+
sage: w.parent()
|
|
1400
|
+
Infinite words over {0, 1, 2}
|
|
1401
|
+
|
|
1402
|
+
TESTS::
|
|
1403
|
+
|
|
1404
|
+
sage: d = InfiniteWords()._element_classes
|
|
1405
|
+
sage: type(d)
|
|
1406
|
+
<class 'dict'>
|
|
1407
|
+
sage: len(d)
|
|
1408
|
+
4
|
|
1409
|
+
sage: e = InfiniteWords('abcdefg')._element_classes
|
|
1410
|
+
sage: d == e
|
|
1411
|
+
True
|
|
1412
|
+
"""
|
|
1413
|
+
import sage.combinat.words.word as word
|
|
1414
|
+
return {
|
|
1415
|
+
'callable_with_caching': word.InfiniteWord_callable_with_caching,
|
|
1416
|
+
'callable': word.InfiniteWord_callable,
|
|
1417
|
+
'iter_with_caching': word.InfiniteWord_iter_with_caching,
|
|
1418
|
+
'iter': word.InfiniteWord_iter}
|
|
1419
|
+
|
|
1420
|
+
def random_element(self, *args, **kwds):
|
|
1421
|
+
r"""
|
|
1422
|
+
Return a random infinite word.
|
|
1423
|
+
|
|
1424
|
+
EXAMPLES::
|
|
1425
|
+
|
|
1426
|
+
sage: W = InfiniteWords('ab')
|
|
1427
|
+
sage: W.random_element() # random
|
|
1428
|
+
word: abbbabbaabbbabbabbaabaabbabbbbbbbbaabbbb...
|
|
1429
|
+
|
|
1430
|
+
sage: W = InfiniteWords(ZZ)
|
|
1431
|
+
sage: W.random_element(x=2,y=4) # random
|
|
1432
|
+
word: 3333223322232233333223323223222233233233...
|
|
1433
|
+
"""
|
|
1434
|
+
rd = self.alphabet().random_element
|
|
1435
|
+
from itertools import count
|
|
1436
|
+
return self._word_from_iter(rd(*args, **kwds) for i in count())
|
|
1437
|
+
|
|
1438
|
+
def _word_from_word(self, data):
|
|
1439
|
+
r"""
|
|
1440
|
+
Return a word from a word.
|
|
1441
|
+
|
|
1442
|
+
The data is assumed to be ok, no check is performed.
|
|
1443
|
+
|
|
1444
|
+
INPUT:
|
|
1445
|
+
|
|
1446
|
+
- ``data`` -- word
|
|
1447
|
+
|
|
1448
|
+
EXAMPLES::
|
|
1449
|
+
|
|
1450
|
+
sage: W = InfiniteWords([0,1,2])
|
|
1451
|
+
sage: w = W(words.FibonacciWord())
|
|
1452
|
+
sage: w
|
|
1453
|
+
word: 0100101001001010010100100101001001010010...
|
|
1454
|
+
sage: w.parent() is W
|
|
1455
|
+
True
|
|
1456
|
+
sage: z = W._word_from_word(w)
|
|
1457
|
+
sage: w is z
|
|
1458
|
+
True
|
|
1459
|
+
"""
|
|
1460
|
+
####################
|
|
1461
|
+
# If `data` is already a word and if its parent is self, then
|
|
1462
|
+
# return `data` (no matter what the parameter length, datatype)
|
|
1463
|
+
###########################
|
|
1464
|
+
if data.parent() is self or data.parent() == self:
|
|
1465
|
+
return data
|
|
1466
|
+
elif data.length() != Infinity:
|
|
1467
|
+
raise ValueError("cannot build an infinite word from a finite one")
|
|
1468
|
+
|
|
1469
|
+
###########################
|
|
1470
|
+
# Otherwise, if self is not the parent of `data`, then we try to
|
|
1471
|
+
# recover the data, the length and the datatype of the input `data`
|
|
1472
|
+
###########################
|
|
1473
|
+
from sage.combinat.words.word_infinite_datatypes import (WordDatatype_callable,
|
|
1474
|
+
WordDatatype_iter)
|
|
1475
|
+
if isinstance(data, WordDatatype_callable):
|
|
1476
|
+
data = data._func
|
|
1477
|
+
return self._word_from_callable(data, caching=False)
|
|
1478
|
+
elif isinstance(data, WordDatatype_iter):
|
|
1479
|
+
data = iter(data)
|
|
1480
|
+
return self._word_from_iter(data, caching=False)
|
|
1481
|
+
else:
|
|
1482
|
+
raise TypeError("any instance of Word_class must be an instance of WordDatatype")
|
|
1483
|
+
|
|
1484
|
+
def _word_from_callable(self, data, caching=True):
|
|
1485
|
+
r"""
|
|
1486
|
+
Return a word represented by a callable.
|
|
1487
|
+
|
|
1488
|
+
The data is assumed to be ok, no check is performed.
|
|
1489
|
+
|
|
1490
|
+
INPUT:
|
|
1491
|
+
|
|
1492
|
+
- ``data`` -- callable
|
|
1493
|
+
|
|
1494
|
+
- ``caching`` -- boolean (default: ``True``); whether to keep a cache
|
|
1495
|
+
of the letters computed by the callable
|
|
1496
|
+
|
|
1497
|
+
EXAMPLES::
|
|
1498
|
+
|
|
1499
|
+
sage: W = InfiniteWords([0,1,2])
|
|
1500
|
+
sage: f = lambda n : n % 3
|
|
1501
|
+
sage: W._word_from_callable(f)
|
|
1502
|
+
word: 0120120120120120120120120120120120120120...
|
|
1503
|
+
"""
|
|
1504
|
+
wc = '_with_caching' if caching else ""
|
|
1505
|
+
return self._element_classes['callable' + wc](self, data, Infinity)
|
|
1506
|
+
|
|
1507
|
+
def _word_from_iter(self, data, caching=True):
|
|
1508
|
+
r"""
|
|
1509
|
+
Return a word represented by an iterator.
|
|
1510
|
+
|
|
1511
|
+
The data is assumed to be ok, no check is performed.
|
|
1512
|
+
|
|
1513
|
+
INPUT:
|
|
1514
|
+
|
|
1515
|
+
- ``data`` -- iterable
|
|
1516
|
+
|
|
1517
|
+
- ``caching`` -- boolean (default: ``True``); whether to keep a cache
|
|
1518
|
+
of the letters computed by the iterator
|
|
1519
|
+
|
|
1520
|
+
EXAMPLES::
|
|
1521
|
+
|
|
1522
|
+
sage: W = InfiniteWords([0,1,2])
|
|
1523
|
+
sage: from itertools import count
|
|
1524
|
+
sage: W._word_from_iter((i % 3 for i in count()))
|
|
1525
|
+
word: 0120120120120120120120120120120120120120...
|
|
1526
|
+
"""
|
|
1527
|
+
wc = '_with_caching' if caching else ""
|
|
1528
|
+
return self._element_classes['iter' + wc](self, data, Infinity)
|
|
1529
|
+
|
|
1530
|
+
def __call__(self, data=None, datatype=None, caching=True, check=True):
|
|
1531
|
+
r"""
|
|
1532
|
+
Construct a new word object with parent ``self``.
|
|
1533
|
+
|
|
1534
|
+
INPUT:
|
|
1535
|
+
|
|
1536
|
+
- ``data`` -- iterator or a callable
|
|
1537
|
+
|
|
1538
|
+
- ``datatype`` -- (default: ``None``) ``None``, "iter", "callable" or
|
|
1539
|
+
"pickled_function"; if ``None``, then the function tries to guess
|
|
1540
|
+
this from the data
|
|
1541
|
+
|
|
1542
|
+
- ``caching`` -- boolean (default: ``True``); whether to keep a
|
|
1543
|
+
cache of the letters computed by an iterator or callable
|
|
1544
|
+
|
|
1545
|
+
- ``check`` -- boolean (default: ``True``); whether to check if
|
|
1546
|
+
the 40 first letters are in the parent alphabet. This is a
|
|
1547
|
+
check done to test for small programming errors. Since we also
|
|
1548
|
+
support infinite words, we cannot really implement a more
|
|
1549
|
+
accurate check.
|
|
1550
|
+
|
|
1551
|
+
.. NOTE::
|
|
1552
|
+
|
|
1553
|
+
The check makes this method about 10 times slower (20µs instead
|
|
1554
|
+
of 2µs), so make sure to set it to False if you know the
|
|
1555
|
+
alphabet is OK. Fast creation (about 1µs) of a word can be
|
|
1556
|
+
done using the class directly (see :meth:`_element_classes`).
|
|
1557
|
+
|
|
1558
|
+
.. WARNING::
|
|
1559
|
+
|
|
1560
|
+
Be careful when defining words using callables and iterators. It
|
|
1561
|
+
appears that islice does not pickle correctly causing various errors
|
|
1562
|
+
when reloading. Also, most iterators do not support copying and
|
|
1563
|
+
should not support pickling by extension.
|
|
1564
|
+
|
|
1565
|
+
EXAMPLES:
|
|
1566
|
+
|
|
1567
|
+
Word with iterator::
|
|
1568
|
+
|
|
1569
|
+
sage: from itertools import count
|
|
1570
|
+
sage: InfiniteWords()(count())
|
|
1571
|
+
word: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,...
|
|
1572
|
+
|
|
1573
|
+
Word with function (a 'callable')::
|
|
1574
|
+
|
|
1575
|
+
sage: f = lambda n : add(Integer(n).digits(2)) % 2
|
|
1576
|
+
sage: InfiniteWords()(f)
|
|
1577
|
+
word: 0110100110010110100101100110100110010110...
|
|
1578
|
+
|
|
1579
|
+
The fourty first letters of the word are checked if they are in the
|
|
1580
|
+
parent alphabet::
|
|
1581
|
+
|
|
1582
|
+
sage: from itertools import count
|
|
1583
|
+
sage: InfiniteWords("ab")(("c" if i == 0 else "a" for i in count()))
|
|
1584
|
+
Traceback (most recent call last):
|
|
1585
|
+
...
|
|
1586
|
+
ValueError: c not in alphabet
|
|
1587
|
+
|
|
1588
|
+
Creation of a word from a word::
|
|
1589
|
+
|
|
1590
|
+
sage: w = InfiniteWords([0,1,2,3])(words.FibonacciWord())
|
|
1591
|
+
sage: w
|
|
1592
|
+
word: 0100101001001010010100100101001001010010...
|
|
1593
|
+
sage: w.parent()
|
|
1594
|
+
Infinite words over {0, 1, 2, 3}
|
|
1595
|
+
sage: InfiniteWords([0,1,2,3])(w) is w
|
|
1596
|
+
True
|
|
1597
|
+
|
|
1598
|
+
Creation of a word from a pickled function::
|
|
1599
|
+
|
|
1600
|
+
sage: f = lambda n : n % 10
|
|
1601
|
+
sage: from sage.misc.fpickle import pickle_function
|
|
1602
|
+
sage: s = pickle_function(f)
|
|
1603
|
+
sage: Word(s, datatype='pickled_function')
|
|
1604
|
+
word: 0123456789012345678901234567890123456789...
|
|
1605
|
+
"""
|
|
1606
|
+
if datatype is not None:
|
|
1607
|
+
if datatype == 'callable':
|
|
1608
|
+
w = self._word_from_callable(data, caching)
|
|
1609
|
+
elif datatype == 'iter':
|
|
1610
|
+
w = self._word_from_iter(data, caching)
|
|
1611
|
+
elif datatype == 'pickled_function':
|
|
1612
|
+
from sage.misc.fpickle import unpickle_function
|
|
1613
|
+
data = unpickle_function(data)
|
|
1614
|
+
w = self._word_from_callable(data, caching)
|
|
1615
|
+
else:
|
|
1616
|
+
raise ValueError("unknown datatype (={})".format(datatype))
|
|
1617
|
+
|
|
1618
|
+
elif callable(data):
|
|
1619
|
+
w = self._word_from_callable(data, caching)
|
|
1620
|
+
|
|
1621
|
+
elif isinstance(data, Iterable):
|
|
1622
|
+
from sage.combinat.words.abstract_word import Word_class
|
|
1623
|
+
if isinstance(data, Word_class):
|
|
1624
|
+
w = self._word_from_word(data)
|
|
1625
|
+
else:
|
|
1626
|
+
w = self._word_from_iter(data, caching)
|
|
1627
|
+
|
|
1628
|
+
else:
|
|
1629
|
+
raise ValueError("cannot guess a datatype from data (=%s); please specify one" % data)
|
|
1630
|
+
|
|
1631
|
+
if check:
|
|
1632
|
+
self._check(w)
|
|
1633
|
+
return w
|
|
1634
|
+
|
|
1635
|
+
def _repr_(self):
|
|
1636
|
+
r"""
|
|
1637
|
+
Return a string representation of ``self``.
|
|
1638
|
+
|
|
1639
|
+
EXAMPLES::
|
|
1640
|
+
|
|
1641
|
+
sage: Words('ab', finite=False) # indirect doctest
|
|
1642
|
+
Infinite words over {'a', 'b'}
|
|
1643
|
+
"""
|
|
1644
|
+
return "Infinite words over {!r}".format(self.alphabet())
|
|
1645
|
+
|
|
1646
|
+
def _an_element_(self):
|
|
1647
|
+
r"""
|
|
1648
|
+
Return an element of ``self``.
|
|
1649
|
+
|
|
1650
|
+
EXAMPLES::
|
|
1651
|
+
|
|
1652
|
+
sage: W = Words('ac', finite=False); W
|
|
1653
|
+
Infinite words over {'a', 'c'}
|
|
1654
|
+
sage: W.an_element()
|
|
1655
|
+
word: accacaaccaacaccacaacaccaaccacaaccaacacca...
|
|
1656
|
+
|
|
1657
|
+
sage: W = Words(NN, finite=False); W
|
|
1658
|
+
Infinite words over Non negative integer semiring
|
|
1659
|
+
sage: W.an_element()
|
|
1660
|
+
word: 0110100110010110100101100110100110010110...
|
|
1661
|
+
|
|
1662
|
+
sage: W = Words('z', finite=False); W
|
|
1663
|
+
Infinite words over {'z'}
|
|
1664
|
+
sage: W.an_element()
|
|
1665
|
+
word: zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz...
|
|
1666
|
+
"""
|
|
1667
|
+
some_letters = list(self.alphabet().some_elements())
|
|
1668
|
+
if len(some_letters) > 1:
|
|
1669
|
+
from sage.combinat.words.word_generators import words
|
|
1670
|
+
letters = some_letters[:2]
|
|
1671
|
+
return self(words.ThueMorseWord(alphabet=letters))
|
|
1672
|
+
else:
|
|
1673
|
+
letter = some_letters[0]
|
|
1674
|
+
return self(lambda n: letter)
|
|
1675
|
+
|
|
1676
|
+
|
|
1677
|
+
class FiniteOrInfiniteWords(AbstractLanguage):
|
|
1678
|
+
def __init__(self, alphabet):
|
|
1679
|
+
r"""
|
|
1680
|
+
INPUT:
|
|
1681
|
+
|
|
1682
|
+
- ``alphabet`` -- the underlying alphabet
|
|
1683
|
+
|
|
1684
|
+
TESTS::
|
|
1685
|
+
|
|
1686
|
+
sage: loads(dumps(Words())) == Words()
|
|
1687
|
+
True
|
|
1688
|
+
"""
|
|
1689
|
+
AbstractLanguage.__init__(self, alphabet)
|
|
1690
|
+
|
|
1691
|
+
def __setstate__(self, state):
|
|
1692
|
+
r"""
|
|
1693
|
+
TESTS::
|
|
1694
|
+
|
|
1695
|
+
sage: import os, tempfile
|
|
1696
|
+
sage: W = Words('ab')
|
|
1697
|
+
sage: with tempfile.TemporaryDirectory() as d:
|
|
1698
|
+
....: filename = os.path.join(d, 'test.sobj')
|
|
1699
|
+
....: W.save(filename)
|
|
1700
|
+
....: load(filename)
|
|
1701
|
+
Finite and infinite words over {'a', 'b'}
|
|
1702
|
+
"""
|
|
1703
|
+
# add a default to support old pickles from #19619
|
|
1704
|
+
self._alphabet = state.get('_alphabet', build_alphabet())
|
|
1705
|
+
|
|
1706
|
+
def cardinality(self):
|
|
1707
|
+
r"""
|
|
1708
|
+
Return the cardinality of this set of words.
|
|
1709
|
+
|
|
1710
|
+
EXAMPLES::
|
|
1711
|
+
|
|
1712
|
+
sage: Words('abcd').cardinality()
|
|
1713
|
+
+Infinity
|
|
1714
|
+
sage: Words('a').cardinality()
|
|
1715
|
+
+Infinity
|
|
1716
|
+
sage: Words('').cardinality()
|
|
1717
|
+
1
|
|
1718
|
+
"""
|
|
1719
|
+
return self.finite_words().cardinality()
|
|
1720
|
+
|
|
1721
|
+
@lazy_attribute
|
|
1722
|
+
def _element_classes(self):
|
|
1723
|
+
r"""
|
|
1724
|
+
Return the element classes corresponding to words of unknown length.
|
|
1725
|
+
|
|
1726
|
+
EXAMPLES::
|
|
1727
|
+
|
|
1728
|
+
sage: Words('ab')._element_classes
|
|
1729
|
+
{'iter': <class 'sage.combinat.words.word.Word_iter'>,
|
|
1730
|
+
'iter_with_caching': <class 'sage.combinat.words.word.Word_iter_with_caching'>}
|
|
1731
|
+
"""
|
|
1732
|
+
import sage.combinat.words.word as word
|
|
1733
|
+
return {'iter_with_caching': word.Word_iter_with_caching,
|
|
1734
|
+
'iter': word.Word_iter}
|
|
1735
|
+
|
|
1736
|
+
def __hash__(self):
|
|
1737
|
+
r"""
|
|
1738
|
+
TESTS::
|
|
1739
|
+
|
|
1740
|
+
sage: hash(Words('ab')) # random
|
|
1741
|
+
12
|
|
1742
|
+
"""
|
|
1743
|
+
return hash(self.alphabet()) ^ hash('words')
|
|
1744
|
+
|
|
1745
|
+
@cached_method
|
|
1746
|
+
def finite_words(self):
|
|
1747
|
+
r"""
|
|
1748
|
+
Return the set of finite words.
|
|
1749
|
+
|
|
1750
|
+
EXAMPLES::
|
|
1751
|
+
|
|
1752
|
+
sage: Words('ab').finite_words()
|
|
1753
|
+
Finite words over {'a', 'b'}
|
|
1754
|
+
"""
|
|
1755
|
+
return FiniteWords(self.alphabet())
|
|
1756
|
+
|
|
1757
|
+
factors = finite_words
|
|
1758
|
+
|
|
1759
|
+
@cached_method
|
|
1760
|
+
def infinite_words(self):
|
|
1761
|
+
r"""
|
|
1762
|
+
Return the set of infinite words.
|
|
1763
|
+
|
|
1764
|
+
EXAMPLES::
|
|
1765
|
+
|
|
1766
|
+
sage: Words('ab').infinite_words()
|
|
1767
|
+
Infinite words over {'a', 'b'}
|
|
1768
|
+
"""
|
|
1769
|
+
return InfiniteWords(self.alphabet())
|
|
1770
|
+
|
|
1771
|
+
shift = infinite_words
|
|
1772
|
+
|
|
1773
|
+
def iterate_by_length(self, length):
|
|
1774
|
+
r"""
|
|
1775
|
+
Return an iterator over the words of given length.
|
|
1776
|
+
|
|
1777
|
+
EXAMPLES::
|
|
1778
|
+
|
|
1779
|
+
sage: [w.string_rep() for w in Words('ab').iterate_by_length(3)]
|
|
1780
|
+
['aaa', 'aab', 'aba', 'abb', 'baa', 'bab', 'bba', 'bbb']
|
|
1781
|
+
"""
|
|
1782
|
+
return self.finite_words().iterate_by_length(length)
|
|
1783
|
+
|
|
1784
|
+
def _word_from_word(self, data):
|
|
1785
|
+
r"""
|
|
1786
|
+
TESTS::
|
|
1787
|
+
|
|
1788
|
+
sage: W = Words('ab')
|
|
1789
|
+
sage: w = FiniteWords('abc')('abba')
|
|
1790
|
+
sage: W._word_from_word(w)
|
|
1791
|
+
word: abba
|
|
1792
|
+
sage: _.parent()
|
|
1793
|
+
Finite words over {'a', 'b'}
|
|
1794
|
+
|
|
1795
|
+
sage: w = InfiniteWords('abc')(lambda i: 'a')
|
|
1796
|
+
sage: W._word_from_word(w)
|
|
1797
|
+
word: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...
|
|
1798
|
+
sage: _.parent()
|
|
1799
|
+
Infinite words over {'a', 'b'}
|
|
1800
|
+
"""
|
|
1801
|
+
P = data.parent()
|
|
1802
|
+
if P is self or P is self.finite_words() or P is self.infinite_words() or \
|
|
1803
|
+
P == self or P == self.finite_words() or P == self.infinite_words():
|
|
1804
|
+
return data
|
|
1805
|
+
elif data.is_finite():
|
|
1806
|
+
return self.finite_words()._word_from_word(data)
|
|
1807
|
+
else:
|
|
1808
|
+
return self.infinite_words()._word_from_word(data)
|
|
1809
|
+
|
|
1810
|
+
def _word_from_iter(self, data, caching=True):
|
|
1811
|
+
r"""
|
|
1812
|
+
TESTS::
|
|
1813
|
+
|
|
1814
|
+
sage: W = Words([0,1,2])
|
|
1815
|
+
sage: u = Word(iter("abcabc"*100))
|
|
1816
|
+
sage: type(u)
|
|
1817
|
+
<class 'sage.combinat.words.word.Word_iter_with_caching'>
|
|
1818
|
+
sage: u.length() is None
|
|
1819
|
+
True
|
|
1820
|
+
|
|
1821
|
+
sage: u = Word(iter("abcabc"))
|
|
1822
|
+
sage: type(u)
|
|
1823
|
+
<class 'sage.combinat.words.word.FiniteWord_iter_with_caching'>
|
|
1824
|
+
sage: u.length()
|
|
1825
|
+
6
|
|
1826
|
+
"""
|
|
1827
|
+
wc = '_with_caching' if caching else ''
|
|
1828
|
+
cls = self._element_classes['iter' + wc]
|
|
1829
|
+
return cls(self, data, None)
|
|
1830
|
+
|
|
1831
|
+
def __call__(self, data=None, length=None, datatype=None, caching=True, check=True):
|
|
1832
|
+
r"""
|
|
1833
|
+
Construct a new word object with parent ``self``.
|
|
1834
|
+
|
|
1835
|
+
INPUT:
|
|
1836
|
+
|
|
1837
|
+
- ``data`` -- (default: ``None``) list, string, tuple, iterator, ``None``
|
|
1838
|
+
(shorthand for []), or a callable defined on [0,1,...,length]
|
|
1839
|
+
|
|
1840
|
+
- ``length`` -- (default: ``None``) this is dependent on the type of data.
|
|
1841
|
+
It is ignored for words defined by lists, strings, tuples,
|
|
1842
|
+
etc., because they have a naturally defined length.
|
|
1843
|
+
For callables, this defines the domain of definition,
|
|
1844
|
+
which is assumed to be [0, 1, 2, ..., length-1].
|
|
1845
|
+
For iterators: Infinity if you know the iterator will not
|
|
1846
|
+
terminate (default); ``'unknown'`` if you do not know whether the
|
|
1847
|
+
iterator terminates; ``'finite'`` if you know that the iterator
|
|
1848
|
+
terminates, but do not know the length.
|
|
1849
|
+
|
|
1850
|
+
- ``datatype`` -- (default: ``None``) ``None``, "char", "list", "str",
|
|
1851
|
+
"tuple", "iter", "callable" or "pickled_function"; if ``None``, then
|
|
1852
|
+
the function tries to guess this from the data.
|
|
1853
|
+
|
|
1854
|
+
- ``caching`` -- boolean (default: ``True``); whether to keep a cache
|
|
1855
|
+
of the letters computed by an iterator or callable
|
|
1856
|
+
|
|
1857
|
+
- ``check`` -- boolean (default: ``True``); whether to check if
|
|
1858
|
+
the 40 first letters are in the parent alphabet. This is a
|
|
1859
|
+
check done to test for small programming errors. Since we also
|
|
1860
|
+
support infinite words, we cannot really implement a more
|
|
1861
|
+
accurate check.
|
|
1862
|
+
|
|
1863
|
+
.. NOTE::
|
|
1864
|
+
|
|
1865
|
+
The check makes this method about 10 times slower (20µs instead
|
|
1866
|
+
of 2µs), so make sure to set it to False if you know the
|
|
1867
|
+
alphabet is OK. Fast creation (about 1µs) of a word can be
|
|
1868
|
+
done using the class directly (see :meth:`_element_classes`).
|
|
1869
|
+
|
|
1870
|
+
.. WARNING::
|
|
1871
|
+
|
|
1872
|
+
Be careful when defining words using callables and iterators. It
|
|
1873
|
+
appears that islice does not pickle correctly causing various errors
|
|
1874
|
+
when reloading. Also, most iterators do not support copying and
|
|
1875
|
+
should not support pickling by extension.
|
|
1876
|
+
|
|
1877
|
+
EXAMPLES:
|
|
1878
|
+
|
|
1879
|
+
Empty word::
|
|
1880
|
+
|
|
1881
|
+
sage: Words()()
|
|
1882
|
+
word:
|
|
1883
|
+
|
|
1884
|
+
Word with string::
|
|
1885
|
+
|
|
1886
|
+
sage: Words()("abbabaab")
|
|
1887
|
+
word: abbabaab
|
|
1888
|
+
|
|
1889
|
+
Word with string constructed from other types::
|
|
1890
|
+
|
|
1891
|
+
sage: Words()([0,1,1,0,1,0,0,1], datatype='str')
|
|
1892
|
+
word: 01101001
|
|
1893
|
+
sage: Words()((0,1,1,0,1,0,0,1), datatype='str')
|
|
1894
|
+
word: 01101001
|
|
1895
|
+
|
|
1896
|
+
Word with list::
|
|
1897
|
+
|
|
1898
|
+
sage: Words()([0,1,1,0,1,0,0,1])
|
|
1899
|
+
word: 01101001
|
|
1900
|
+
|
|
1901
|
+
Word with list constructed from other types::
|
|
1902
|
+
|
|
1903
|
+
sage: Words()("01101001", datatype='list')
|
|
1904
|
+
word: 01101001
|
|
1905
|
+
sage: Words()((0,1,1,0,1,0,0,1), datatype='list')
|
|
1906
|
+
word: 01101001
|
|
1907
|
+
|
|
1908
|
+
Word with tuple::
|
|
1909
|
+
|
|
1910
|
+
sage: Words()((0,1,1,0,1,0,0,1))
|
|
1911
|
+
word: 01101001
|
|
1912
|
+
|
|
1913
|
+
Word with tuple constructed from other types::
|
|
1914
|
+
|
|
1915
|
+
sage: Words()([0,1,1,0,1,0,0,1], datatype='tuple')
|
|
1916
|
+
word: 01101001
|
|
1917
|
+
sage: Words()("01101001", datatype='str')
|
|
1918
|
+
word: 01101001
|
|
1919
|
+
|
|
1920
|
+
Word with iterator::
|
|
1921
|
+
|
|
1922
|
+
sage: from itertools import count
|
|
1923
|
+
sage: Words()(count())
|
|
1924
|
+
word: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,...
|
|
1925
|
+
sage: Words()(iter("abbabaab")) # iterators default to infinite words
|
|
1926
|
+
word: abbabaab
|
|
1927
|
+
sage: Words()(iter("abbabaab"), length='unknown')
|
|
1928
|
+
word: abbabaab
|
|
1929
|
+
sage: Words()(iter("abbabaab"), length='finite')
|
|
1930
|
+
word: abbabaab
|
|
1931
|
+
|
|
1932
|
+
Word with function (a 'callable')::
|
|
1933
|
+
|
|
1934
|
+
sage: f = lambda n : add(Integer(n).digits(2)) % 2
|
|
1935
|
+
sage: Words()(f)
|
|
1936
|
+
word: 0110100110010110100101100110100110010110...
|
|
1937
|
+
sage: Words()(f, length=8)
|
|
1938
|
+
word: 01101001
|
|
1939
|
+
|
|
1940
|
+
Word over a string with a parent::
|
|
1941
|
+
|
|
1942
|
+
sage: w = Words('abc')("abbabaab"); w
|
|
1943
|
+
word: abbabaab
|
|
1944
|
+
sage: w.parent()
|
|
1945
|
+
Finite words over {'a', 'b', 'c'}
|
|
1946
|
+
|
|
1947
|
+
The fourty first letters of the word are checked if they are in the
|
|
1948
|
+
parent alphabet::
|
|
1949
|
+
|
|
1950
|
+
sage: Words("ab")("abca")
|
|
1951
|
+
Traceback (most recent call last):
|
|
1952
|
+
...
|
|
1953
|
+
ValueError: c not in alphabet
|
|
1954
|
+
sage: Words("ab")("abca", check=False)
|
|
1955
|
+
word: abca
|
|
1956
|
+
|
|
1957
|
+
The default parent is the combinatorial class of all words::
|
|
1958
|
+
|
|
1959
|
+
sage: w = Words()("abbabaab"); w
|
|
1960
|
+
word: abbabaab
|
|
1961
|
+
sage: w.parent()
|
|
1962
|
+
Finite words over Set of Python objects of class 'object'
|
|
1963
|
+
|
|
1964
|
+
Creation of a word from a word::
|
|
1965
|
+
|
|
1966
|
+
sage: Words([0,1,2,3])(Words([2,3])([2,2,2,3,3,2]))
|
|
1967
|
+
word: 222332
|
|
1968
|
+
sage: _.parent()
|
|
1969
|
+
Finite words over {0, 1, 2, 3}
|
|
1970
|
+
|
|
1971
|
+
::
|
|
1972
|
+
|
|
1973
|
+
sage: Words([3,2,1])(Words([2,3])([2,2,2,3,3,2]))
|
|
1974
|
+
word: 222332
|
|
1975
|
+
sage: _.parent()
|
|
1976
|
+
Finite words over {3, 2, 1}
|
|
1977
|
+
|
|
1978
|
+
Construction of a word from a word when the parents are the same::
|
|
1979
|
+
|
|
1980
|
+
sage: W = Words()
|
|
1981
|
+
sage: w = W(range(8))
|
|
1982
|
+
sage: z = W(w)
|
|
1983
|
+
sage: w is z
|
|
1984
|
+
True
|
|
1985
|
+
|
|
1986
|
+
Construction of a word path from a finite word::
|
|
1987
|
+
|
|
1988
|
+
sage: W = Words('abcd')
|
|
1989
|
+
sage: P = WordPaths('abcd') # needs sage.modules
|
|
1990
|
+
sage: w = W('aaab')
|
|
1991
|
+
sage: P(w) # needs sage.modules
|
|
1992
|
+
Path: aaab
|
|
1993
|
+
|
|
1994
|
+
Construction of a word path from a Christoffel word::
|
|
1995
|
+
|
|
1996
|
+
sage: w = words.ChristoffelWord(5,8)
|
|
1997
|
+
sage: w
|
|
1998
|
+
word: 0010010100101
|
|
1999
|
+
sage: P = WordPaths([0,1,2,3]) # needs sage.modules
|
|
2000
|
+
sage: P(w) # needs sage.modules
|
|
2001
|
+
Path: 0010010100101
|
|
2002
|
+
|
|
2003
|
+
Construction of a word represented by a list from a word
|
|
2004
|
+
represented by a str ::
|
|
2005
|
+
|
|
2006
|
+
sage: w = Word('ababbbabab')
|
|
2007
|
+
sage: type(w)
|
|
2008
|
+
<class 'sage.combinat.words.word.FiniteWord_str'>
|
|
2009
|
+
sage: z = Word(w, datatype='list')
|
|
2010
|
+
sage: type(z)
|
|
2011
|
+
<class 'sage.combinat.words.word.FiniteWord_list'>
|
|
2012
|
+
sage: y = Word(w, alphabet='abc', datatype='list')
|
|
2013
|
+
sage: type(y)
|
|
2014
|
+
<class 'sage.combinat.words.word.FiniteWord_list'>
|
|
2015
|
+
|
|
2016
|
+
Creation of a word from a concatenation of words::
|
|
2017
|
+
|
|
2018
|
+
sage: W = Words()
|
|
2019
|
+
sage: w = W() * W('a')
|
|
2020
|
+
sage: Z = Words('ab')
|
|
2021
|
+
sage: Z(w)
|
|
2022
|
+
word: a
|
|
2023
|
+
|
|
2024
|
+
Creation of a word path from a FiniteWord_iter::
|
|
2025
|
+
|
|
2026
|
+
sage: w = words.FibonacciWord()
|
|
2027
|
+
sage: f = w[:100]
|
|
2028
|
+
sage: P = WordPaths([0,1,2,3]) # needs sage.modules
|
|
2029
|
+
sage: p = P(f); p # needs sage.modules
|
|
2030
|
+
Path: 0100101001001010010100100101001001010010...
|
|
2031
|
+
sage: p.length() # needs sage.modules
|
|
2032
|
+
100
|
|
2033
|
+
|
|
2034
|
+
Creation of a word path from a :class:`FiniteWord_callable`::
|
|
2035
|
+
|
|
2036
|
+
sage: g = Word(lambda n: n%2, length=100)
|
|
2037
|
+
sage: P = WordPaths([0,1,2,3]) # needs sage.modules
|
|
2038
|
+
sage: p = P(g); p # needs sage.modules
|
|
2039
|
+
Path: 0101010101010101010101010101010101010101...
|
|
2040
|
+
sage: p.length() # needs sage.modules
|
|
2041
|
+
100
|
|
2042
|
+
|
|
2043
|
+
Creation of a word from a pickled function::
|
|
2044
|
+
|
|
2045
|
+
sage: f = lambda n: n % 10
|
|
2046
|
+
sage: from sage.misc.fpickle import pickle_function
|
|
2047
|
+
sage: s = pickle_function(f)
|
|
2048
|
+
sage: Word(s, datatype='pickled_function')
|
|
2049
|
+
word: 0123456789012345678901234567890123456789...
|
|
2050
|
+
|
|
2051
|
+
If the alphabet is a subset of [0, 255], then it uses char as datatype::
|
|
2052
|
+
|
|
2053
|
+
sage: type(Word([0,1,1,2,0], alphabet=list(range(256))))
|
|
2054
|
+
<class 'sage.combinat.words.word.FiniteWord_char'>
|
|
2055
|
+
|
|
2056
|
+
If the alphabet is a subset of [0, 255], then the letters must
|
|
2057
|
+
convert to an unsigned char. Otherwise an error is raised before
|
|
2058
|
+
the check is done::
|
|
2059
|
+
|
|
2060
|
+
sage: type(Word([0,1,1,2,0,257], alphabet=list(range(256))))
|
|
2061
|
+
Traceback (most recent call last):
|
|
2062
|
+
...
|
|
2063
|
+
OverflowError: value too large to convert to unsigned char
|
|
2064
|
+
sage: type(Word([0,1,1,2,0,258], alphabet=list(range(257))))
|
|
2065
|
+
Traceback (most recent call last):
|
|
2066
|
+
...
|
|
2067
|
+
ValueError: 258 not in alphabet
|
|
2068
|
+
sage: type(Word([0,1,1,2,0,103], alphabet=list(range(100))))
|
|
2069
|
+
Traceback (most recent call last):
|
|
2070
|
+
...
|
|
2071
|
+
ValueError: 103 not in alphabet
|
|
2072
|
+
|
|
2073
|
+
Check that the type is rightly guessed for parking functions which are
|
|
2074
|
+
callable::
|
|
2075
|
+
|
|
2076
|
+
sage: p = ParkingFunction([2,2,1])
|
|
2077
|
+
sage: Word(p).parent()
|
|
2078
|
+
Finite words over Set of Python objects of class 'object'
|
|
2079
|
+
"""
|
|
2080
|
+
# try to guess `length` from the `datatype` or `data` if not given
|
|
2081
|
+
if length is None or length == 'unknown':
|
|
2082
|
+
if data is None:
|
|
2083
|
+
length = 'finite'
|
|
2084
|
+
elif datatype in ('callable', 'pickled_function'):
|
|
2085
|
+
length = 'infinite'
|
|
2086
|
+
elif datatype in ('list', 'char', 'str', 'tuple'):
|
|
2087
|
+
length = 'finite'
|
|
2088
|
+
elif datatype is None:
|
|
2089
|
+
try:
|
|
2090
|
+
length = len(data)
|
|
2091
|
+
except TypeError:
|
|
2092
|
+
if callable(data):
|
|
2093
|
+
length = 'infinite'
|
|
2094
|
+
|
|
2095
|
+
# now build finite/infinite or unknown length words
|
|
2096
|
+
if length == 'finite' or length in ZZ:
|
|
2097
|
+
return self.finite_words()(data, datatype=datatype, length=length, caching=caching, check=check)
|
|
2098
|
+
|
|
2099
|
+
elif length == 'infinite' or length == Infinity:
|
|
2100
|
+
return self.infinite_words()(data, datatype=datatype, check=check, caching=caching)
|
|
2101
|
+
|
|
2102
|
+
elif length == 'unknown' or length is None:
|
|
2103
|
+
from sage.combinat.words.abstract_word import Word_class
|
|
2104
|
+
if isinstance(data, Word_class):
|
|
2105
|
+
w = self._word_from_word(data)
|
|
2106
|
+
elif isinstance(data, Iterable):
|
|
2107
|
+
w = self._word_from_iter(data, caching)
|
|
2108
|
+
else:
|
|
2109
|
+
raise ValueError("cannot guess a datatype from data (={!r}); please specify one".format(data))
|
|
2110
|
+
|
|
2111
|
+
if check:
|
|
2112
|
+
w.parent()._check(w)
|
|
2113
|
+
return w
|
|
2114
|
+
|
|
2115
|
+
else:
|
|
2116
|
+
raise ValueError("invalid argument length (={!r})".format(length))
|
|
2117
|
+
|
|
2118
|
+
def _repr_(self):
|
|
2119
|
+
r"""
|
|
2120
|
+
Return a string representation of ``self``.
|
|
2121
|
+
|
|
2122
|
+
EXAMPLES::
|
|
2123
|
+
|
|
2124
|
+
sage: Words('ab', finite=False)._repr_()
|
|
2125
|
+
"Infinite words over {'a', 'b'}"
|
|
2126
|
+
"""
|
|
2127
|
+
return "Finite and infinite words over {!r}".format(self.alphabet())
|
|
2128
|
+
|
|
2129
|
+
|
|
2130
|
+
class Words_n(Parent):
|
|
2131
|
+
r"""
|
|
2132
|
+
The set of words of fixed length on a given alphabet.
|
|
2133
|
+
"""
|
|
2134
|
+
def __init__(self, words, n):
|
|
2135
|
+
r"""
|
|
2136
|
+
INPUT:
|
|
2137
|
+
|
|
2138
|
+
- ``words`` -- set of finite words
|
|
2139
|
+
|
|
2140
|
+
- ``n`` -- nonnegative integer
|
|
2141
|
+
|
|
2142
|
+
TESTS::
|
|
2143
|
+
|
|
2144
|
+
sage: Words([0,1], length=-42)
|
|
2145
|
+
Traceback (most recent call last):
|
|
2146
|
+
...
|
|
2147
|
+
ValueError: n = -42 must be nonnegative
|
|
2148
|
+
"""
|
|
2149
|
+
n = ZZ(n)
|
|
2150
|
+
if n < 0:
|
|
2151
|
+
raise ValueError("n = {} must be nonnegative".format(n))
|
|
2152
|
+
self._words = words
|
|
2153
|
+
self._n = n
|
|
2154
|
+
|
|
2155
|
+
Parent.__init__(self, category=Sets(), facade=(words,))
|
|
2156
|
+
|
|
2157
|
+
def __setstate__(self, state):
|
|
2158
|
+
r"""
|
|
2159
|
+
TESTS::
|
|
2160
|
+
|
|
2161
|
+
sage: import os, tempfile
|
|
2162
|
+
sage: W = Words('ab', 10)
|
|
2163
|
+
sage: with tempfile.TemporaryDirectory() as d:
|
|
2164
|
+
....: filename = os.path.join(d, 'test.sobj')
|
|
2165
|
+
....: W.save(filename)
|
|
2166
|
+
....: load(filename)
|
|
2167
|
+
Words of length 10 over {'a', 'b'}
|
|
2168
|
+
"""
|
|
2169
|
+
# add a default to support old pickles from #19619
|
|
2170
|
+
self._n = state.get('_n')
|
|
2171
|
+
self._words = state.get('_words', FiniteWords())
|
|
2172
|
+
|
|
2173
|
+
def alphabet(self):
|
|
2174
|
+
r"""
|
|
2175
|
+
Return the underlying alphabet.
|
|
2176
|
+
|
|
2177
|
+
EXAMPLES::
|
|
2178
|
+
|
|
2179
|
+
sage: Words([0,1], 4).alphabet()
|
|
2180
|
+
{0, 1}
|
|
2181
|
+
"""
|
|
2182
|
+
return self._words.alphabet()
|
|
2183
|
+
|
|
2184
|
+
def __call__(self, data, *args, **kwds):
|
|
2185
|
+
r"""
|
|
2186
|
+
INPUT:
|
|
2187
|
+
|
|
2188
|
+
- all arguments are sent directly to the underlying set of finite words.
|
|
2189
|
+
See the documentation there for the actual input.
|
|
2190
|
+
|
|
2191
|
+
TESTS::
|
|
2192
|
+
|
|
2193
|
+
sage: Words(5,3)([1,2,3])
|
|
2194
|
+
word: 123
|
|
2195
|
+
sage: Words(5,3)([1,2,3,1])
|
|
2196
|
+
Traceback (most recent call last):
|
|
2197
|
+
...
|
|
2198
|
+
ValueError: wrong length
|
|
2199
|
+
"""
|
|
2200
|
+
if 'length' in kwds:
|
|
2201
|
+
if kwds['length'] != self._n:
|
|
2202
|
+
raise ValueError("wrong length")
|
|
2203
|
+
else:
|
|
2204
|
+
kwds['length'] = self._n
|
|
2205
|
+
w = self._words(data, *args, **kwds)
|
|
2206
|
+
|
|
2207
|
+
if kwds.get('check', True):
|
|
2208
|
+
if w.length() != self._n:
|
|
2209
|
+
raise ValueError("wrong length")
|
|
2210
|
+
return w
|
|
2211
|
+
|
|
2212
|
+
def list(self):
|
|
2213
|
+
r"""
|
|
2214
|
+
Return a list of all the words contained in ``self``.
|
|
2215
|
+
|
|
2216
|
+
EXAMPLES::
|
|
2217
|
+
|
|
2218
|
+
sage: Words(0,0).list()
|
|
2219
|
+
[word: ]
|
|
2220
|
+
sage: Words(5,0).list()
|
|
2221
|
+
[word: ]
|
|
2222
|
+
sage: Words(['a','b','c'],0).list()
|
|
2223
|
+
[word: ]
|
|
2224
|
+
sage: Words(5,1).list()
|
|
2225
|
+
[word: 1, word: 2, word: 3, word: 4, word: 5]
|
|
2226
|
+
sage: Words(['a','b','c'],2).list()
|
|
2227
|
+
[word: aa, word: ab, word: ac, word: ba, word: bb, word: bc, word: ca, word: cb, word: cc]
|
|
2228
|
+
"""
|
|
2229
|
+
return list(self)
|
|
2230
|
+
|
|
2231
|
+
def _an_element_(self):
|
|
2232
|
+
r"""
|
|
2233
|
+
Return an element of ``self``.
|
|
2234
|
+
|
|
2235
|
+
EXAMPLES::
|
|
2236
|
+
|
|
2237
|
+
sage: W = Words(2, 3); W
|
|
2238
|
+
Words of length 3 over {1, 2}
|
|
2239
|
+
sage: W.an_element()
|
|
2240
|
+
word: 121
|
|
2241
|
+
|
|
2242
|
+
sage: W = Words("bac", 7); W
|
|
2243
|
+
Words of length 7 over {'b', 'a', 'c'}
|
|
2244
|
+
sage: W.an_element()
|
|
2245
|
+
word: bacbacb
|
|
2246
|
+
|
|
2247
|
+
sage: W = Words("baczxy", 5); W
|
|
2248
|
+
Words of length 5 over {'b', 'a', 'c', 'z', 'x', 'y'}
|
|
2249
|
+
sage: W.an_element()
|
|
2250
|
+
word: baczx
|
|
2251
|
+
"""
|
|
2252
|
+
letters = list(self.alphabet().some_elements())
|
|
2253
|
+
r = self._n % len(letters)
|
|
2254
|
+
q = (self._n - r) / len(letters)
|
|
2255
|
+
return self(letters * int(q) + letters[:r])
|
|
2256
|
+
|
|
2257
|
+
def random_element(self, *args, **kwds):
|
|
2258
|
+
r"""
|
|
2259
|
+
Return a random word in this set.
|
|
2260
|
+
|
|
2261
|
+
EXAMPLES::
|
|
2262
|
+
|
|
2263
|
+
sage: W = Words('ab', 4)
|
|
2264
|
+
sage: W.random_element() # random
|
|
2265
|
+
word: bbab
|
|
2266
|
+
sage: W.random_element() in W
|
|
2267
|
+
True
|
|
2268
|
+
|
|
2269
|
+
sage: W = Words(ZZ, 5)
|
|
2270
|
+
sage: W.random_element() # random
|
|
2271
|
+
word: 1,2,2,-1,12
|
|
2272
|
+
sage: W.random_element() in W
|
|
2273
|
+
True
|
|
2274
|
+
|
|
2275
|
+
TESTS::
|
|
2276
|
+
|
|
2277
|
+
sage: _ = Words(GF(5),4).random_element() # needs sage.rings.finite_rings
|
|
2278
|
+
|
|
2279
|
+
Check that :issue:`18283` is fixed::
|
|
2280
|
+
|
|
2281
|
+
sage: w = Words('abc', 5).random_element()
|
|
2282
|
+
sage: w.length()
|
|
2283
|
+
5
|
|
2284
|
+
"""
|
|
2285
|
+
return self._words.random_element(length=self._n, *args, **kwds)
|
|
2286
|
+
|
|
2287
|
+
def _repr_(self):
|
|
2288
|
+
"""
|
|
2289
|
+
EXAMPLES::
|
|
2290
|
+
|
|
2291
|
+
sage: Words(3,5) # indirect doctest
|
|
2292
|
+
Words of length 5 over {1, 2, 3}
|
|
2293
|
+
"""
|
|
2294
|
+
from sage.combinat.words.word_options import word_options
|
|
2295
|
+
if word_options['old_repr']:
|
|
2296
|
+
return "Words over {} of length {}".format(self.alphabet(), self._n)
|
|
2297
|
+
return "Words of length {} over {}".format(self._n, self.alphabet())
|
|
2298
|
+
|
|
2299
|
+
def __contains__(self, x):
|
|
2300
|
+
"""
|
|
2301
|
+
EXAMPLES::
|
|
2302
|
+
|
|
2303
|
+
sage: W = Words(3,5)
|
|
2304
|
+
sage: W.an_element() in W
|
|
2305
|
+
True
|
|
2306
|
+
|
|
2307
|
+
sage: 2 in Words(length=3)
|
|
2308
|
+
False
|
|
2309
|
+
sage: [1,'a',3] in Words(length=3)
|
|
2310
|
+
False
|
|
2311
|
+
sage: [1,2] in Words(length=3)
|
|
2312
|
+
False
|
|
2313
|
+
sage: "abc" in Words(length=3)
|
|
2314
|
+
False
|
|
2315
|
+
sage: Words("abc")("ababc") in Words(length=3)
|
|
2316
|
+
False
|
|
2317
|
+
sage: Words([0,1])([1,0,1]) in Words([0,1], length=3)
|
|
2318
|
+
True
|
|
2319
|
+
"""
|
|
2320
|
+
return x in self._words and x.length() == self._n
|
|
2321
|
+
|
|
2322
|
+
def cardinality(self):
|
|
2323
|
+
r"""
|
|
2324
|
+
Return the number of words of length `n` from alphabet.
|
|
2325
|
+
|
|
2326
|
+
EXAMPLES::
|
|
2327
|
+
|
|
2328
|
+
sage: Words(['a','b','c'], 4).cardinality()
|
|
2329
|
+
81
|
|
2330
|
+
sage: Words(3, 4).cardinality()
|
|
2331
|
+
81
|
|
2332
|
+
sage: Words(0,0).cardinality()
|
|
2333
|
+
1
|
|
2334
|
+
sage: Words(5,0).cardinality()
|
|
2335
|
+
1
|
|
2336
|
+
sage: Words(['a','b','c'],0).cardinality()
|
|
2337
|
+
1
|
|
2338
|
+
sage: Words(0,1).cardinality()
|
|
2339
|
+
0
|
|
2340
|
+
sage: Words(5,1).cardinality()
|
|
2341
|
+
5
|
|
2342
|
+
sage: Words(['a','b','c'],1).cardinality()
|
|
2343
|
+
3
|
|
2344
|
+
sage: Words(7,13).cardinality()
|
|
2345
|
+
96889010407
|
|
2346
|
+
sage: Words(['a','b','c','d','e','f','g'],13).cardinality()
|
|
2347
|
+
96889010407
|
|
2348
|
+
"""
|
|
2349
|
+
return self.alphabet().cardinality() ** self._n
|
|
2350
|
+
|
|
2351
|
+
__len__ = cardinality
|
|
2352
|
+
|
|
2353
|
+
def __iter__(self):
|
|
2354
|
+
r"""
|
|
2355
|
+
TESTS::
|
|
2356
|
+
|
|
2357
|
+
sage: [w for w in Words(['a', 'b'], 2)]
|
|
2358
|
+
[word: aa, word: ab, word: ba, word: bb]
|
|
2359
|
+
sage: [w for w in Words(['b', 'a'], 2)]
|
|
2360
|
+
[word: bb, word: ba, word: ab, word: aa]
|
|
2361
|
+
sage: [w for w in Words(['a', 'b'], 0)]
|
|
2362
|
+
[word: ]
|
|
2363
|
+
sage: [w for w in Words([], 3)]
|
|
2364
|
+
[]
|
|
2365
|
+
"""
|
|
2366
|
+
return self._words.iterate_by_length(self._n)
|
|
2367
|
+
|
|
2368
|
+
def iterate_by_length(self, length):
|
|
2369
|
+
r"""
|
|
2370
|
+
All words in this class are of the same length, so use iterator
|
|
2371
|
+
instead.
|
|
2372
|
+
|
|
2373
|
+
TESTS::
|
|
2374
|
+
|
|
2375
|
+
sage: W = Words(['a', 'b'], 2)
|
|
2376
|
+
sage: list(W.iterate_by_length(2))
|
|
2377
|
+
[word: aa, word: ab, word: ba, word: bb]
|
|
2378
|
+
sage: list(W.iterate_by_length(1))
|
|
2379
|
+
[]
|
|
2380
|
+
"""
|
|
2381
|
+
if length == self._n:
|
|
2382
|
+
return iter(self)
|
|
2383
|
+
else:
|
|
2384
|
+
return iter([])
|
|
2385
|
+
|
|
2386
|
+
|
|
2387
|
+
###############
|
|
2388
|
+
# old pickles #
|
|
2389
|
+
###############
|
|
2390
|
+
|
|
2391
|
+
|
|
2392
|
+
register_unpickle_override("sage.combinat.words.words", "Words_over_OrderedAlphabet", FiniteOrInfiniteWords)
|
|
2393
|
+
register_unpickle_override("sage.combinat.words.words", "Words_over_Alphabet", FiniteOrInfiniteWords)
|
|
2394
|
+
register_unpickle_override("sage.combinat.words.words", "FiniteWords_length_k_over_OrderedAlphabet", Words_n)
|
|
2395
|
+
register_unpickle_override("sage.combinat.words.words", "FiniteWords_over_OrderedAlphabet", FiniteWords)
|
|
2396
|
+
register_unpickle_override("sage.combinat.words.words", "InfiniteWords_over_OrderedAlphabet", InfiniteWords)
|