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,1474 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
# sage.doctest: needs sage.combinat sage.modules
|
|
3
|
+
r"""
|
|
4
|
+
`\nu`-Dyck words
|
|
5
|
+
|
|
6
|
+
A class of the `\nu`-Dyck word, see [PRV2017]_ for details.
|
|
7
|
+
|
|
8
|
+
This file is based off the class
|
|
9
|
+
:func:`DyckWords<sage.combinat.dyck_word.DyckWord>` written by Mike Hansen, Dan
|
|
10
|
+
Drake, Florent Hivert, Christian Stump, Mike Zabrocki, Jean--Baptiste Priez
|
|
11
|
+
and Travis Scrimshaw.
|
|
12
|
+
|
|
13
|
+
AUTHORS:
|
|
14
|
+
|
|
15
|
+
- Aram Dermenjian (2020-09-26)
|
|
16
|
+
"""
|
|
17
|
+
# ****************************************************************************
|
|
18
|
+
# Copyright (C) 2020 Aram Dermenjian <aram.dermenjian@gmail.com>,
|
|
19
|
+
#
|
|
20
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
21
|
+
#
|
|
22
|
+
# This code is distributed in the hope that it will be useful,
|
|
23
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
24
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
25
|
+
# General Public License for more details.
|
|
26
|
+
#
|
|
27
|
+
# The full text of the GPL is available at:
|
|
28
|
+
#
|
|
29
|
+
# https://www.gnu.org/licenses/
|
|
30
|
+
# ****************************************************************************
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
from sage.structure.element import Element
|
|
33
|
+
from sage.rings.integer import Integer
|
|
34
|
+
from sage.combinat.combinat import CombinatorialElement
|
|
35
|
+
from sage.sets.recursively_enumerated_set import RecursivelyEnumeratedSet
|
|
36
|
+
from sage.structure.global_options import GlobalOptions
|
|
37
|
+
from sage.structure.parent import Parent
|
|
38
|
+
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
|
|
39
|
+
from sage.misc.latex import latex
|
|
40
|
+
|
|
41
|
+
from sage.combinat.words.paths import WordPaths_north_east
|
|
42
|
+
from sage.combinat.words.paths import FiniteWordPath_north_east
|
|
43
|
+
|
|
44
|
+
ndw_open_symbol = 1
|
|
45
|
+
ndw_close_symbol = 0
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def update_ndw_symbols(os, cs):
|
|
49
|
+
r"""
|
|
50
|
+
A way to alter the open and close symbols from sage.
|
|
51
|
+
|
|
52
|
+
INPUT:
|
|
53
|
+
|
|
54
|
+
- ``os`` -- the open symbol
|
|
55
|
+
- ``cs`` -- the close symbol
|
|
56
|
+
|
|
57
|
+
EXAMPLES::
|
|
58
|
+
|
|
59
|
+
sage: from sage.combinat.nu_dyck_word import update_ndw_symbols
|
|
60
|
+
sage: update_ndw_symbols(0,1)
|
|
61
|
+
sage: dw = NuDyckWord('0101001','0110010'); dw
|
|
62
|
+
[0, 1, 0, 1, 0, 0, 1]
|
|
63
|
+
|
|
64
|
+
sage: dw = NuDyckWord('1010110','1001101'); dw
|
|
65
|
+
Traceback (most recent call last):
|
|
66
|
+
...
|
|
67
|
+
ValueError: invalid nu-Dyck word
|
|
68
|
+
sage: update_ndw_symbols(1,0)
|
|
69
|
+
"""
|
|
70
|
+
global ndw_open_symbol
|
|
71
|
+
global ndw_close_symbol
|
|
72
|
+
ndw_open_symbol = os
|
|
73
|
+
ndw_close_symbol = cs
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def replace_dyck_char(x):
|
|
77
|
+
r"""
|
|
78
|
+
A map sending an opening character (``'1'``, ``'N'``, and ``'('``) to
|
|
79
|
+
``ndw_open_symbol``, a closing character (``'0'``, ``'E'``, and ``')'``) to
|
|
80
|
+
``ndw_close_symbol``, and raising an error on any input other than one of
|
|
81
|
+
the opening or closing characters.
|
|
82
|
+
|
|
83
|
+
This is the inverse map of :func:`replace_dyck_symbol`.
|
|
84
|
+
|
|
85
|
+
INPUT:
|
|
86
|
+
|
|
87
|
+
- ``x`` -- string; a ``'1'``, ``'0'``, ``'N'``, ``'E'``, ``'('`` or ``')'``
|
|
88
|
+
|
|
89
|
+
OUTPUT:
|
|
90
|
+
|
|
91
|
+
- If ``x`` is an opening character, replace ``x`` with the
|
|
92
|
+
constant ``ndw_open_symbol``.
|
|
93
|
+
|
|
94
|
+
- If ``x`` is a closing character, replace ``x`` with the
|
|
95
|
+
constant ``ndw_close_symbol``.
|
|
96
|
+
|
|
97
|
+
- Raise a :exc:`ValueError` if ``x`` is neither an opening nor a
|
|
98
|
+
closing character.
|
|
99
|
+
|
|
100
|
+
.. SEEALSO:: :func:`replace_dyck_symbol`
|
|
101
|
+
|
|
102
|
+
EXAMPLES::
|
|
103
|
+
|
|
104
|
+
sage: from sage.combinat.nu_dyck_word import replace_dyck_char
|
|
105
|
+
sage: replace_dyck_char('(')
|
|
106
|
+
1
|
|
107
|
+
sage: replace_dyck_char(')')
|
|
108
|
+
0
|
|
109
|
+
sage: replace_dyck_char(1)
|
|
110
|
+
Traceback (most recent call last):
|
|
111
|
+
...
|
|
112
|
+
ValueError
|
|
113
|
+
"""
|
|
114
|
+
if x == '(' or x == 'N' or x == str(ndw_open_symbol):
|
|
115
|
+
return ndw_open_symbol
|
|
116
|
+
if x == ')' or x == 'E' or x == str(ndw_close_symbol):
|
|
117
|
+
return ndw_close_symbol
|
|
118
|
+
raise ValueError
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def replace_dyck_symbol(x, open_char='N', close_char='E') -> str:
|
|
122
|
+
r"""
|
|
123
|
+
A map sending ``ndw_open_symbol`` to ``open_char`` and ``ndw_close_symbol``
|
|
124
|
+
to ``close_char``, and raising an error on any input other than
|
|
125
|
+
``ndw_open_symbol`` and ``ndw_close_symbol``. The values of the constants
|
|
126
|
+
``ndw_open_symbol`` and ``ndw_close_symbol`` are subject to change.
|
|
127
|
+
|
|
128
|
+
This is the inverse map of :func:`replace_dyck_char`.
|
|
129
|
+
|
|
130
|
+
INPUT:
|
|
131
|
+
|
|
132
|
+
- ``x`` -- either ``ndw_open_symbol`` or ``ndw_close_symbol``
|
|
133
|
+
|
|
134
|
+
- ``open_char`` -- string (optional) default ``'N'``
|
|
135
|
+
|
|
136
|
+
- ``close_char`` -- string (optional) default ``'E'``
|
|
137
|
+
|
|
138
|
+
OUTPUT: if ``x`` is ``ndw_open_symbol``, replace ``x`` with ``open_char``
|
|
139
|
+
|
|
140
|
+
- If ``x`` is ``ndw_close_symbol``, replace ``x`` with ``close_char``.
|
|
141
|
+
|
|
142
|
+
- If ``x`` is neither ``ndw_open_symbol`` nor ``ndw_close_symbol``, a
|
|
143
|
+
:exc:`ValueError` is raised.
|
|
144
|
+
|
|
145
|
+
.. SEEALSO:: :func:`replace_dyck_char`
|
|
146
|
+
|
|
147
|
+
EXAMPLES::
|
|
148
|
+
|
|
149
|
+
sage: from sage.combinat.nu_dyck_word import replace_dyck_symbol
|
|
150
|
+
sage: replace_dyck_symbol(1)
|
|
151
|
+
'N'
|
|
152
|
+
sage: replace_dyck_symbol(0)
|
|
153
|
+
'E'
|
|
154
|
+
sage: replace_dyck_symbol(3)
|
|
155
|
+
Traceback (most recent call last):
|
|
156
|
+
...
|
|
157
|
+
ValueError
|
|
158
|
+
"""
|
|
159
|
+
if x == ndw_open_symbol:
|
|
160
|
+
return open_char
|
|
161
|
+
if x == ndw_close_symbol:
|
|
162
|
+
return close_char
|
|
163
|
+
raise ValueError
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class NuDyckWord(CombinatorialElement):
|
|
167
|
+
r"""
|
|
168
|
+
A `\nu`-Dyck word.
|
|
169
|
+
|
|
170
|
+
Given a lattice path `\nu` in the `\ZZ^2` grid starting at the origin
|
|
171
|
+
`(0,0)` consisting of North `N = (0,1)` and East `E = (1,0)` steps, a
|
|
172
|
+
`\nu`-Dyck path is a lattice path in the `\ZZ^2` grid starting at the
|
|
173
|
+
origin `(0,0)` and ending at the same coordinate as `\nu` such that it is
|
|
174
|
+
weakly above `\nu`. A `\nu`-Dyck word is the representation of a
|
|
175
|
+
`\nu`-Dyck path where a North step is represented by a 1 and an East step
|
|
176
|
+
is represented by a 0.
|
|
177
|
+
|
|
178
|
+
INPUT:
|
|
179
|
+
|
|
180
|
+
- ``k1`` -- a path for the `\nu`-Dyck word
|
|
181
|
+
|
|
182
|
+
- ``k2`` -- a path for `\nu`
|
|
183
|
+
|
|
184
|
+
EXAMPLES::
|
|
185
|
+
|
|
186
|
+
sage: dw = NuDyckWord([1,0,1,0],[1,0,0,1]); dw
|
|
187
|
+
[1, 0, 1, 0]
|
|
188
|
+
sage: print(dw)
|
|
189
|
+
NENE
|
|
190
|
+
sage: dw.height()
|
|
191
|
+
2
|
|
192
|
+
|
|
193
|
+
sage: dw = NuDyckWord('1010',[1,0,0,1]); dw
|
|
194
|
+
[1, 0, 1, 0]
|
|
195
|
+
|
|
196
|
+
sage: dw = NuDyckWord('NENE',[1,0,0,1]); dw
|
|
197
|
+
[1, 0, 1, 0]
|
|
198
|
+
|
|
199
|
+
sage: NuDyckWord([1,0,1,0],[1,0,0,1]).pretty_print()
|
|
200
|
+
__
|
|
201
|
+
_|x
|
|
202
|
+
| . .
|
|
203
|
+
|
|
204
|
+
sage: from sage.combinat.nu_dyck_word import update_ndw_symbols
|
|
205
|
+
sage: update_ndw_symbols(0,1)
|
|
206
|
+
sage: dw = NuDyckWord('0101001','0110010'); dw
|
|
207
|
+
[0, 1, 0, 1, 0, 0, 1]
|
|
208
|
+
sage: dw.pp()
|
|
209
|
+
__
|
|
210
|
+
|x
|
|
211
|
+
_| .
|
|
212
|
+
_|x .
|
|
213
|
+
| . . .
|
|
214
|
+
sage: update_ndw_symbols(1,0)
|
|
215
|
+
"""
|
|
216
|
+
@staticmethod
|
|
217
|
+
def __classcall_private__(cls, dw=None, nu=None, **kwargs):
|
|
218
|
+
"""
|
|
219
|
+
Return an element with the appropriate parent.
|
|
220
|
+
|
|
221
|
+
EXAMPLES::
|
|
222
|
+
|
|
223
|
+
sage: NuDyckWord('110100','101010')
|
|
224
|
+
[1, 1, 0, 1, 0, 0]
|
|
225
|
+
sage: NuDyckWord('010','010')
|
|
226
|
+
[0, 1, 0]
|
|
227
|
+
"""
|
|
228
|
+
# if dw is none, then we might have a normal Dyck word
|
|
229
|
+
if dw is None:
|
|
230
|
+
from sage.combinat.dyck_word import DyckWord
|
|
231
|
+
return DyckWord(dw, kwargs)
|
|
232
|
+
|
|
233
|
+
if isinstance(dw, NuDyckWord):
|
|
234
|
+
return dw
|
|
235
|
+
|
|
236
|
+
if nu is None:
|
|
237
|
+
raise ValueError("nu required")
|
|
238
|
+
|
|
239
|
+
dw = to_word_path(dw)
|
|
240
|
+
nu = to_word_path(nu)
|
|
241
|
+
|
|
242
|
+
if path_weakly_above_other(dw, nu):
|
|
243
|
+
return NuDyckWords(nu)(dw)
|
|
244
|
+
|
|
245
|
+
raise ValueError("invalid nu-Dyck word")
|
|
246
|
+
|
|
247
|
+
def __init__(self, parent, dw, latex_options=None):
|
|
248
|
+
"""
|
|
249
|
+
Initialize a nu-Dyck word.
|
|
250
|
+
|
|
251
|
+
EXAMPLES::
|
|
252
|
+
|
|
253
|
+
sage: NuDyckWord('010', '010')
|
|
254
|
+
[0, 1, 0]
|
|
255
|
+
sage: NuDyckWord('110100','101010')
|
|
256
|
+
[1, 1, 0, 1, 0, 0]
|
|
257
|
+
"""
|
|
258
|
+
Element.__init__(self, parent)
|
|
259
|
+
self._path = to_word_path(dw)
|
|
260
|
+
self._list = list(self._path)
|
|
261
|
+
|
|
262
|
+
if parent is None:
|
|
263
|
+
raise ValueError("need parent object")
|
|
264
|
+
|
|
265
|
+
self._nu = parent._nu
|
|
266
|
+
|
|
267
|
+
if latex_options is None:
|
|
268
|
+
latex_options = {}
|
|
269
|
+
self._latex_options = dict(latex_options)
|
|
270
|
+
|
|
271
|
+
def __eq__(self, other):
|
|
272
|
+
"""
|
|
273
|
+
Return if two paths are equal.
|
|
274
|
+
|
|
275
|
+
EXAMPLES::
|
|
276
|
+
|
|
277
|
+
sage: u = NuDyckWord('010','010')
|
|
278
|
+
sage: w = NuDyckWord('110100','101010')
|
|
279
|
+
sage: w == w
|
|
280
|
+
True
|
|
281
|
+
sage: u == w
|
|
282
|
+
False
|
|
283
|
+
sage: u == 4
|
|
284
|
+
False
|
|
285
|
+
"""
|
|
286
|
+
if not isinstance(other, NuDyckWord):
|
|
287
|
+
return False
|
|
288
|
+
return self._path == other._path and self._nu == other._nu
|
|
289
|
+
|
|
290
|
+
def __neq__(self, other):
|
|
291
|
+
"""
|
|
292
|
+
Return if two paths are not equal.
|
|
293
|
+
|
|
294
|
+
EXAMPLES::
|
|
295
|
+
|
|
296
|
+
sage: u = NuDyckWord('010','010')
|
|
297
|
+
sage: w = NuDyckWord('110100','101010')
|
|
298
|
+
sage: w != w
|
|
299
|
+
False
|
|
300
|
+
sage: u != w
|
|
301
|
+
True
|
|
302
|
+
sage: u != 4
|
|
303
|
+
True
|
|
304
|
+
"""
|
|
305
|
+
return not self.__eq__(other)
|
|
306
|
+
|
|
307
|
+
def __le__(self, other):
|
|
308
|
+
"""
|
|
309
|
+
Return if one path is included in another.
|
|
310
|
+
|
|
311
|
+
EXAMPLES::
|
|
312
|
+
|
|
313
|
+
sage: ND1 = NuDyckWord('101', '011')
|
|
314
|
+
sage: ND2 = NuDyckWord('110', '011')
|
|
315
|
+
sage: ND3 = NuDyckWord('011', '011')
|
|
316
|
+
sage: ND1 <= ND1
|
|
317
|
+
True
|
|
318
|
+
sage: ND1 <= ND2
|
|
319
|
+
True
|
|
320
|
+
sage: ND2 <= ND1
|
|
321
|
+
False
|
|
322
|
+
sage: ND3 <= ND2
|
|
323
|
+
True
|
|
324
|
+
sage: ND3 <= ND1
|
|
325
|
+
True
|
|
326
|
+
"""
|
|
327
|
+
if self._nu == other._nu:
|
|
328
|
+
return path_weakly_above_other(other._path, self._path)
|
|
329
|
+
return False
|
|
330
|
+
|
|
331
|
+
def __lt__(self, other):
|
|
332
|
+
"""
|
|
333
|
+
Return if one path is strictly included in another.
|
|
334
|
+
|
|
335
|
+
EXAMPLES::
|
|
336
|
+
|
|
337
|
+
sage: ND1 = NuDyckWord('101', '011')
|
|
338
|
+
sage: ND2 = NuDyckWord('110', '011')
|
|
339
|
+
sage: ND3 = NuDyckWord('011', '011')
|
|
340
|
+
sage: ND1 < ND1
|
|
341
|
+
False
|
|
342
|
+
sage: ND1 < ND2
|
|
343
|
+
True
|
|
344
|
+
sage: ND2 < ND1
|
|
345
|
+
False
|
|
346
|
+
sage: ND3 < ND2
|
|
347
|
+
True
|
|
348
|
+
sage: ND3 < ND1
|
|
349
|
+
True
|
|
350
|
+
"""
|
|
351
|
+
return self.__le__(other) and not self.__eq__(other)
|
|
352
|
+
|
|
353
|
+
def __ge__(self, other):
|
|
354
|
+
"""
|
|
355
|
+
Return if one path is included in another.
|
|
356
|
+
|
|
357
|
+
EXAMPLES::
|
|
358
|
+
|
|
359
|
+
sage: ND1 = NuDyckWord('101', '011')
|
|
360
|
+
sage: ND2 = NuDyckWord('110', '011')
|
|
361
|
+
sage: ND3 = NuDyckWord('011', '011')
|
|
362
|
+
sage: ND1 >= ND1
|
|
363
|
+
True
|
|
364
|
+
sage: ND1 >= ND2
|
|
365
|
+
False
|
|
366
|
+
sage: ND2 >= ND1
|
|
367
|
+
True
|
|
368
|
+
sage: ND1 >= ND3
|
|
369
|
+
True
|
|
370
|
+
sage: ND2 >= ND3
|
|
371
|
+
True
|
|
372
|
+
"""
|
|
373
|
+
if self._nu == other._nu:
|
|
374
|
+
return path_weakly_above_other(self._path, other._path)
|
|
375
|
+
return False
|
|
376
|
+
|
|
377
|
+
def __gt__(self, other):
|
|
378
|
+
"""
|
|
379
|
+
Return if one path is strictly included in another.
|
|
380
|
+
|
|
381
|
+
EXAMPLES::
|
|
382
|
+
|
|
383
|
+
sage: ND1 = NuDyckWord('101', '011')
|
|
384
|
+
sage: ND2 = NuDyckWord('110', '011')
|
|
385
|
+
sage: ND3 = NuDyckWord('011', '011')
|
|
386
|
+
sage: ND1 > ND1
|
|
387
|
+
False
|
|
388
|
+
sage: ND1 > ND2
|
|
389
|
+
False
|
|
390
|
+
sage: ND2 > ND1
|
|
391
|
+
True
|
|
392
|
+
sage: ND1 > ND3
|
|
393
|
+
True
|
|
394
|
+
sage: ND2 > ND3
|
|
395
|
+
True
|
|
396
|
+
"""
|
|
397
|
+
return self.__ge__(other) and not self.__eq__(other)
|
|
398
|
+
|
|
399
|
+
def _cache_key(self) -> tuple:
|
|
400
|
+
"""
|
|
401
|
+
Return a cache key for ``self``.
|
|
402
|
+
|
|
403
|
+
EXAMPLES::
|
|
404
|
+
|
|
405
|
+
sage: u = NuDyckWord('010','010')
|
|
406
|
+
sage: u._cache_key()
|
|
407
|
+
(0, 1, 0, 0, 1, 0)
|
|
408
|
+
"""
|
|
409
|
+
return tuple(self._path) + tuple(self._nu)
|
|
410
|
+
|
|
411
|
+
def __hash__(self) -> int:
|
|
412
|
+
"""
|
|
413
|
+
Return a hash for ``self``.
|
|
414
|
+
|
|
415
|
+
EXAMPLES::
|
|
416
|
+
|
|
417
|
+
sage: u = NuDyckWord('010','010')
|
|
418
|
+
sage: hash(u) # random
|
|
419
|
+
-4577085166836515071
|
|
420
|
+
"""
|
|
421
|
+
return hash(''.join(str(i) for i in self._list))
|
|
422
|
+
|
|
423
|
+
def set_latex_options(self, D):
|
|
424
|
+
r"""
|
|
425
|
+
Set the latex options for use in the ``_latex_`` function.
|
|
426
|
+
|
|
427
|
+
The default values are set in the ``__init__`` function.
|
|
428
|
+
|
|
429
|
+
- ``color`` -- (default: black) the line color
|
|
430
|
+
|
|
431
|
+
- ``line width`` -- (default: `2 \times` ``tikz_scale``) value
|
|
432
|
+
representing the line width
|
|
433
|
+
|
|
434
|
+
- ``nu_options`` -- (default: ``'rounded corners=1, color=red, line
|
|
435
|
+
width=1'``) string to indicate what the tikz options should be for
|
|
436
|
+
path of `\nu`
|
|
437
|
+
|
|
438
|
+
- ``points_color`` -- (default: ``'black'``) str to indicate color
|
|
439
|
+
points should be drawn with
|
|
440
|
+
|
|
441
|
+
- ``show_grid`` -- boolean (default: ``True``); value to indicate if
|
|
442
|
+
grid should be shown
|
|
443
|
+
|
|
444
|
+
- ``show_nu`` -- boolean (default: ``True``); value to indicate if `\nu`
|
|
445
|
+
should be shown
|
|
446
|
+
|
|
447
|
+
- ``show_points`` -- boolean (default: ``False``); value to indicate
|
|
448
|
+
if points should be shown on path
|
|
449
|
+
|
|
450
|
+
- ``tikz_scale`` -- (default: 1) scale for use with the tikz package
|
|
451
|
+
|
|
452
|
+
INPUT:
|
|
453
|
+
|
|
454
|
+
- ``D`` -- dictionary with a list of latex parameters to change
|
|
455
|
+
|
|
456
|
+
EXAMPLES::
|
|
457
|
+
|
|
458
|
+
sage: NDW = NuDyckWord('010','010')
|
|
459
|
+
sage: NDW.set_latex_options({"tikz_scale":2})
|
|
460
|
+
sage: NDW.set_latex_options({"color":"blue", "show_points":True})
|
|
461
|
+
|
|
462
|
+
.. TODO::
|
|
463
|
+
|
|
464
|
+
This should probably be merged into NuDyckWord.options.
|
|
465
|
+
"""
|
|
466
|
+
for opt in D:
|
|
467
|
+
self._latex_options[opt] = D[opt]
|
|
468
|
+
|
|
469
|
+
def latex_options(self) -> dict:
|
|
470
|
+
r"""
|
|
471
|
+
Return the latex options for use in the ``_latex_`` function as a
|
|
472
|
+
dictionary.
|
|
473
|
+
|
|
474
|
+
The default values are set using the options.
|
|
475
|
+
|
|
476
|
+
- ``color`` -- (default: black) the line color
|
|
477
|
+
|
|
478
|
+
- ``line width`` -- (default: 2*``tikz_scale``) value representing the
|
|
479
|
+
line width
|
|
480
|
+
|
|
481
|
+
- ``nu_options`` -- (default: ``'rounded corners=1, color=red, line
|
|
482
|
+
width=1'``) string to indicate what the tikz options should be for
|
|
483
|
+
path of `\nu`
|
|
484
|
+
|
|
485
|
+
- ``points_color`` -- (default: ``'black'``) str to indicate color
|
|
486
|
+
points should be drawn with
|
|
487
|
+
|
|
488
|
+
- ``show_grid`` -- boolean (default: ``True``); value to indicate if
|
|
489
|
+
grid should be shown
|
|
490
|
+
|
|
491
|
+
- ``show_nu`` -- boolean (default: ``True``); value to indicate if `\nu`
|
|
492
|
+
should be shown
|
|
493
|
+
|
|
494
|
+
- ``show_points`` -- boolean (default: ``False``); value to indicate
|
|
495
|
+
if points should be shown on path
|
|
496
|
+
|
|
497
|
+
- ``tikz_scale`` -- (default: 1) scale for use with the tikz package
|
|
498
|
+
|
|
499
|
+
EXAMPLES::
|
|
500
|
+
|
|
501
|
+
sage: NDW = NuDyckWord('010','010')
|
|
502
|
+
sage: NDW.latex_options()
|
|
503
|
+
{'color': black,
|
|
504
|
+
'line width': 2,
|
|
505
|
+
'nu_options': rounded corners=1, color=red, line width=1,
|
|
506
|
+
'points_color': black,
|
|
507
|
+
'show_grid': True,
|
|
508
|
+
'show_nu': True,
|
|
509
|
+
'show_points': False,
|
|
510
|
+
'tikz_scale': 1}
|
|
511
|
+
|
|
512
|
+
.. TODO::
|
|
513
|
+
|
|
514
|
+
This should probably be merged into NuDyckWord.options.
|
|
515
|
+
"""
|
|
516
|
+
d = self._latex_options.copy()
|
|
517
|
+
opts = self.parent().options
|
|
518
|
+
if "tikz_scale" not in d:
|
|
519
|
+
d["tikz_scale"] = opts.latex_tikz_scale
|
|
520
|
+
if "line width" not in d:
|
|
521
|
+
d["line width"] = opts.latex_line_width_scalar * d["tikz_scale"]
|
|
522
|
+
if "color" not in d:
|
|
523
|
+
d["color"] = opts.latex_color
|
|
524
|
+
if "show_points" not in d:
|
|
525
|
+
d["show_points"] = opts.latex_show_points
|
|
526
|
+
if "points_color" not in d:
|
|
527
|
+
d["points_color"] = opts.latex_points_color
|
|
528
|
+
if "show_grid" not in d:
|
|
529
|
+
d["show_grid"] = opts.latex_show_grid
|
|
530
|
+
if "show_nu" not in d:
|
|
531
|
+
d["show_nu"] = opts.latex_show_nu
|
|
532
|
+
if "nu_options" not in d:
|
|
533
|
+
d["nu_options"] = opts.latex_nu_options
|
|
534
|
+
return d
|
|
535
|
+
|
|
536
|
+
def _repr_(self) -> str:
|
|
537
|
+
r"""
|
|
538
|
+
Return a string representation of ``self`` depending on
|
|
539
|
+
:meth:`NuDyckWords.options`.
|
|
540
|
+
|
|
541
|
+
TESTS::
|
|
542
|
+
|
|
543
|
+
sage: NuDyckWord('01010','00011')
|
|
544
|
+
[0, 1, 0, 1, 0]
|
|
545
|
+
sage: NuDyckWord('10010','00011')
|
|
546
|
+
[1, 0, 0, 1, 0]
|
|
547
|
+
sage: NuDyckWords.options.display="lattice"
|
|
548
|
+
sage: NuDyckWord('10010','00011')
|
|
549
|
+
__
|
|
550
|
+
___|x
|
|
551
|
+
|x x x
|
|
552
|
+
|
|
553
|
+
sage: NuDyckWords.options._reset()
|
|
554
|
+
"""
|
|
555
|
+
return self.parent().options._dispatch(self, '_repr_', 'display')
|
|
556
|
+
|
|
557
|
+
def _repr_list(self) -> str:
|
|
558
|
+
r"""
|
|
559
|
+
Return a string representation of ``self`` as a list.
|
|
560
|
+
|
|
561
|
+
TESTS::
|
|
562
|
+
|
|
563
|
+
sage: NuDyckWord([1,1,0],[1,0,1]) # indirect doctest
|
|
564
|
+
[1, 1, 0]
|
|
565
|
+
sage: NuDyckWord('NNEE','NENE')
|
|
566
|
+
[1, 1, 0, 0]
|
|
567
|
+
"""
|
|
568
|
+
return str(list(self._path))
|
|
569
|
+
|
|
570
|
+
def _repr_lattice(self, style=None, labelling=None):
|
|
571
|
+
r"""
|
|
572
|
+
See :meth:`pretty_print()`.
|
|
573
|
+
|
|
574
|
+
TESTS::
|
|
575
|
+
|
|
576
|
+
sage: n = NuDyckWord('00011001000100','00011001000100')
|
|
577
|
+
sage: print(n._repr_lattice(style='N-E', labelling=[1,2,3,4]))
|
|
578
|
+
____
|
|
579
|
+
_____| . . 4
|
|
580
|
+
___| . . . . . 3
|
|
581
|
+
| . . . . . . . 2
|
|
582
|
+
______| . . . . . . . 1
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
sage: print(NuDyckWord('100101','010011')._repr_lattice())
|
|
586
|
+
_|
|
|
587
|
+
___|x
|
|
588
|
+
|x . .
|
|
589
|
+
|
|
590
|
+
sage: print(NuDyckWord('110010','001011')._repr_lattice())
|
|
591
|
+
__
|
|
592
|
+
___|x
|
|
593
|
+
|x x x
|
|
594
|
+
|x x .
|
|
595
|
+
"""
|
|
596
|
+
if style is None:
|
|
597
|
+
style = self.parent().options.diagram_style
|
|
598
|
+
if style == "grid":
|
|
599
|
+
style = "N-E"
|
|
600
|
+
|
|
601
|
+
if style == "N-E":
|
|
602
|
+
path_length = self._path.length()
|
|
603
|
+
height = self._path.height()
|
|
604
|
+
width = self._path.width()
|
|
605
|
+
if path_length == 0:
|
|
606
|
+
return ".\n"
|
|
607
|
+
|
|
608
|
+
# Handle right-hand side labels
|
|
609
|
+
if labelling is None:
|
|
610
|
+
labels = [" "] * height
|
|
611
|
+
else:
|
|
612
|
+
if len(labelling) != height:
|
|
613
|
+
raise ValueError(f"the given labelling has the wrong length: {height} needed")
|
|
614
|
+
labels = [str(label) for label in labelling]
|
|
615
|
+
max_length = max(len(label) for label in labels)
|
|
616
|
+
labels = [lbl.rjust(max_length + 1) for lbl in labels]
|
|
617
|
+
|
|
618
|
+
rev_path = list(self._path.reversal())
|
|
619
|
+
rev_nu_path = list(self._nu.reversal())
|
|
620
|
+
ts = ""
|
|
621
|
+
|
|
622
|
+
# Grab first line
|
|
623
|
+
cur_pos = rev_path.index(ndw_open_symbol)
|
|
624
|
+
cur_nu_pos = rev_nu_path.index(ndw_open_symbol)
|
|
625
|
+
if cur_pos > 0:
|
|
626
|
+
ts += " " * (width - cur_pos)
|
|
627
|
+
ts += " _" + "__" * (cur_pos - 1)
|
|
628
|
+
ts += "_\n"
|
|
629
|
+
|
|
630
|
+
# Middle Lines
|
|
631
|
+
for i in range(height - 1):
|
|
632
|
+
old_pos = cur_pos
|
|
633
|
+
old_nu_pos = cur_nu_pos
|
|
634
|
+
cur_pos = rev_path.index(ndw_open_symbol, cur_pos + 1)
|
|
635
|
+
cur_nu_pos = rev_nu_path.index(ndw_open_symbol, cur_nu_pos + 1)
|
|
636
|
+
|
|
637
|
+
ts += " " * (width - cur_pos + i + 1)
|
|
638
|
+
if cur_pos != old_pos + 1:
|
|
639
|
+
ts += " _" + "__" * (cur_pos - old_pos - 2)
|
|
640
|
+
ts += "|"
|
|
641
|
+
if old_pos >= 0:
|
|
642
|
+
ts += "x " * (old_pos - old_nu_pos)
|
|
643
|
+
ts += " ." * (old_nu_pos - i)
|
|
644
|
+
ts += labels[height - i - 1]
|
|
645
|
+
ts += "\n"
|
|
646
|
+
|
|
647
|
+
# Final line
|
|
648
|
+
ts += "__" * (path_length - cur_pos - 1)
|
|
649
|
+
ts += "|"
|
|
650
|
+
ts += "x " * (cur_pos - cur_nu_pos)
|
|
651
|
+
ts += " ." * (cur_nu_pos - i - 1)
|
|
652
|
+
ts += labels[0]
|
|
653
|
+
ts += "\n"
|
|
654
|
+
return ts
|
|
655
|
+
raise ValueError(f"the given style (={style}) is not valid")
|
|
656
|
+
|
|
657
|
+
def _ascii_art_(self):
|
|
658
|
+
r"""
|
|
659
|
+
Return an ASCII art representation of ``self``.
|
|
660
|
+
|
|
661
|
+
TESTS::
|
|
662
|
+
|
|
663
|
+
sage: ascii_art(NuDyckWord('00011001000100','00011001000100'))
|
|
664
|
+
____
|
|
665
|
+
_____| . .
|
|
666
|
+
___| . . . . .
|
|
667
|
+
| . . . . . . .
|
|
668
|
+
______| . . . . . . .
|
|
669
|
+
"""
|
|
670
|
+
from sage.typeset.ascii_art import AsciiArt
|
|
671
|
+
rep = self.parent().options.ascii_art
|
|
672
|
+
if rep == "pretty_output":
|
|
673
|
+
ret = self._repr_lattice()
|
|
674
|
+
return AsciiArt(ret.splitlines(), baseline=0)
|
|
675
|
+
|
|
676
|
+
def __str__(self) -> str:
|
|
677
|
+
r"""
|
|
678
|
+
Return a string consisting of N and E steps corresponding to
|
|
679
|
+
the `\nu`-Dyck word.
|
|
680
|
+
|
|
681
|
+
EXAMPLES::
|
|
682
|
+
|
|
683
|
+
sage: str(NuDyckWord('100101','010011'))
|
|
684
|
+
'NEENEN'
|
|
685
|
+
sage: str(NuDyckWord('101010','100110'))
|
|
686
|
+
'NENENE'
|
|
687
|
+
"""
|
|
688
|
+
return "".join(replace_dyck_symbol(let) for let in self._path)
|
|
689
|
+
|
|
690
|
+
def pretty_print(self, style=None, labelling=None):
|
|
691
|
+
r"""
|
|
692
|
+
Display a NuDyckWord as a lattice path in the `\ZZ^2` grid.
|
|
693
|
+
|
|
694
|
+
If the ``style`` is "N-E", then a cell below the diagonal is
|
|
695
|
+
indicated by a period, whereas a cell below the path but above
|
|
696
|
+
the diagonal is indicated by an x. If a list of labels is
|
|
697
|
+
included, they are displayed along the vertical edges of the
|
|
698
|
+
Dyck path.
|
|
699
|
+
|
|
700
|
+
INPUT:
|
|
701
|
+
|
|
702
|
+
- ``style`` -- (default: ``None``) can either be:
|
|
703
|
+
|
|
704
|
+
- ``None`` to use the option default
|
|
705
|
+
- "N-E" to show ``self`` as a path of north and east steps, or
|
|
706
|
+
|
|
707
|
+
- ``labelling`` -- (if style is "N-E") a list of labels assigned to
|
|
708
|
+
the up steps in ``self``
|
|
709
|
+
|
|
710
|
+
- ``underpath`` -- (if style is "N-E", default: ``True``) if ``True``,
|
|
711
|
+
an ``x`` to show the boxes between `\nu` and the `\nu`-Dyck Path
|
|
712
|
+
|
|
713
|
+
EXAMPLES::
|
|
714
|
+
|
|
715
|
+
sage: for ND in NuDyckWords('101010'): ND.pretty_print()
|
|
716
|
+
__
|
|
717
|
+
_| .
|
|
718
|
+
_| . .
|
|
719
|
+
| . . .
|
|
720
|
+
__
|
|
721
|
+
___| .
|
|
722
|
+
|x . .
|
|
723
|
+
| . . .
|
|
724
|
+
____
|
|
725
|
+
|x .
|
|
726
|
+
_| . .
|
|
727
|
+
| . . .
|
|
728
|
+
____
|
|
729
|
+
_|x .
|
|
730
|
+
|x . .
|
|
731
|
+
| . . .
|
|
732
|
+
______
|
|
733
|
+
|x x .
|
|
734
|
+
|x . .
|
|
735
|
+
| . . .
|
|
736
|
+
|
|
737
|
+
::
|
|
738
|
+
|
|
739
|
+
sage: nu = [1,0,1,0,1,0,1,0,1,0,1,0]
|
|
740
|
+
sage: ND = NuDyckWord([1,1,1,0,1,0,0,1,1,0,0,0],nu)
|
|
741
|
+
sage: ND.pretty_print()
|
|
742
|
+
______
|
|
743
|
+
|x x .
|
|
744
|
+
___|x . .
|
|
745
|
+
_|x x . . .
|
|
746
|
+
|x x . . . .
|
|
747
|
+
|x . . . . .
|
|
748
|
+
| . . . . . .
|
|
749
|
+
|
|
750
|
+
::
|
|
751
|
+
|
|
752
|
+
sage: NuDyckWord([1,1,0,0,1,0],[1,0,1,0,1,0]).pretty_print(
|
|
753
|
+
....: labelling=[1,3,2])
|
|
754
|
+
__
|
|
755
|
+
___| . 2
|
|
756
|
+
|x . . 3
|
|
757
|
+
| . . . 1
|
|
758
|
+
|
|
759
|
+
::
|
|
760
|
+
|
|
761
|
+
sage: NuDyckWord('1101110011010010001101111000110000',
|
|
762
|
+
....: '1010101010101010101010101010101010').pretty_print(
|
|
763
|
+
....: labelling=list(range(1,18)))
|
|
764
|
+
________
|
|
765
|
+
|x x x . 17
|
|
766
|
+
_____|x x . . 16
|
|
767
|
+
|x x x x . . . 15
|
|
768
|
+
|x x x . . . . 14
|
|
769
|
+
|x x . . . . . 13
|
|
770
|
+
_|x . . . . . . 12
|
|
771
|
+
|x . . . . . . . 11
|
|
772
|
+
_____| . . . . . . . . 10
|
|
773
|
+
___|x x . . . . . . . . . 9
|
|
774
|
+
_|x x x . . . . . . . . . . 8
|
|
775
|
+
|x x x . . . . . . . . . . . 7
|
|
776
|
+
___|x x . . . . . . . . . . . . 6
|
|
777
|
+
|x x x . . . . . . . . . . . . . 5
|
|
778
|
+
|x x . . . . . . . . . . . . . . 4
|
|
779
|
+
_|x . . . . . . . . . . . . . . . 3
|
|
780
|
+
|x . . . . . . . . . . . . . . . . 2
|
|
781
|
+
| . . . . . . . . . . . . . . . . . 1
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
::
|
|
785
|
+
|
|
786
|
+
sage: NuDyckWord().pretty_print()
|
|
787
|
+
.
|
|
788
|
+
"""
|
|
789
|
+
print(self._repr_lattice(style, labelling))
|
|
790
|
+
|
|
791
|
+
pp = pretty_print
|
|
792
|
+
|
|
793
|
+
def _latex_(self):
|
|
794
|
+
r"""
|
|
795
|
+
A latex representation of ``self`` using the tikzpicture package.
|
|
796
|
+
|
|
797
|
+
EXAMPLES::
|
|
798
|
+
|
|
799
|
+
sage: NDW = NuDyckWord('010','010')
|
|
800
|
+
sage: NDW.set_latex_options({"show_points":True})
|
|
801
|
+
sage: latex(NDW)
|
|
802
|
+
\vcenter{\hbox{$\begin{tikzpicture}[scale=1]
|
|
803
|
+
\draw[dotted] (0, 0) grid (2, 1);
|
|
804
|
+
\draw[line width=2,color=black,fill=black](0, 0) circle (0.21);
|
|
805
|
+
\draw[line width=2,color=black,fill=black](1, 0) circle (0.21);
|
|
806
|
+
\draw[line width=2,color=black,fill=black](1, 1) circle (0.21);
|
|
807
|
+
\draw[line width=2,color=black,fill=black](2, 1) circle (0.21);
|
|
808
|
+
\draw[rounded corners=1, color=red, line width=1] (0, 0) -- (1, 0) -- (1, 1) -- (2, 1);
|
|
809
|
+
\draw[rounded corners=1, color=black, line width=2] (0, 0) -- (1, 0) -- (1, 1) -- (2, 1);
|
|
810
|
+
\end{tikzpicture}$}}
|
|
811
|
+
sage: NuDyckWord('01','01')._latex_()
|
|
812
|
+
'\\vcenter{\\hbox{$\\begin{tikzpicture}[scale=1]\n \\draw[dotted] (0, 0) grid (1, 1);\n \\draw[rounded corners=1, color=red, line width=1] (0, 0) -- (1, 0) -- (1, 1);\n \\draw[rounded corners=1, color=black, line width=2] (0, 0) -- (1, 0) -- (1, 1);\n\\end{tikzpicture}$}}'
|
|
813
|
+
sage: NuDyckWord('101100','101010')._latex_()
|
|
814
|
+
'\\vcenter{\\hbox{$\\begin{tikzpicture}[scale=1]\n \\draw[dotted] (0, 0) grid (3, 3);\n \\draw[rounded corners=1, color=red, line width=1] (0, 0) -- (0, 1) -- (1, 1) -- (1, 2) -- (2, 2) -- (2, 3) -- (3, 3);\n \\draw[rounded corners=1, color=black, line width=2] (0, 0) -- (0, 1) -- (1, 1) -- (1, 2) -- (1, 3) -- (2, 3) -- (3, 3);\n\\end{tikzpicture}$}}'
|
|
815
|
+
"""
|
|
816
|
+
latex.add_package_to_preamble_if_available("tikz")
|
|
817
|
+
latex_options = self.latex_options()
|
|
818
|
+
|
|
819
|
+
# Start setting up tikz
|
|
820
|
+
res = "\\vcenter{\\hbox{$\\begin{tikzpicture}"
|
|
821
|
+
res += "[scale=" + str(latex_options['tikz_scale']) + "]"
|
|
822
|
+
res += "\n"
|
|
823
|
+
|
|
824
|
+
# Setup background grid
|
|
825
|
+
if latex_options['show_grid']:
|
|
826
|
+
grid = [((0, 0), (self.width(), self.height()))]
|
|
827
|
+
for v1, v2 in grid:
|
|
828
|
+
res += f" \\draw[dotted] {v1} grid {v2};"
|
|
829
|
+
res += "\n"
|
|
830
|
+
|
|
831
|
+
# Add points if wanted
|
|
832
|
+
if latex_options['show_points']:
|
|
833
|
+
pt_color = latex_options['points_color']
|
|
834
|
+
radius = 0.15 + .03 * latex_options['line width']
|
|
835
|
+
for v in self.points():
|
|
836
|
+
res += " \\draw[line width=2,"
|
|
837
|
+
res += f"color={pt_color},fill={pt_color}]"
|
|
838
|
+
res += f"{v} circle ({radius});"
|
|
839
|
+
res += "\n"
|
|
840
|
+
|
|
841
|
+
# Add nu if wanted
|
|
842
|
+
if latex_options['show_nu']:
|
|
843
|
+
res += " \\draw[%s]" % (str(latex_options['nu_options']))
|
|
844
|
+
for k, p in enumerate(self._nu.points()):
|
|
845
|
+
if k == 0:
|
|
846
|
+
res += " %s" % (str(p))
|
|
847
|
+
else:
|
|
848
|
+
res += " -- %s" % (str(p))
|
|
849
|
+
res += ";\n"
|
|
850
|
+
|
|
851
|
+
# setup Path
|
|
852
|
+
res += " \\draw[rounded corners=1, color={}, line width={}]".format(
|
|
853
|
+
latex_options['color'],
|
|
854
|
+
str(latex_options['line width'])
|
|
855
|
+
)
|
|
856
|
+
for k, p in enumerate(self._path.points()):
|
|
857
|
+
if k == 0:
|
|
858
|
+
res += " %s" % (str(p))
|
|
859
|
+
else:
|
|
860
|
+
res += " -- %s" % (str(p))
|
|
861
|
+
res += ";\n"
|
|
862
|
+
res += "\\end{tikzpicture}$}}"
|
|
863
|
+
return res
|
|
864
|
+
|
|
865
|
+
def plot(self, **kwds):
|
|
866
|
+
r"""
|
|
867
|
+
Plot a `\nu`-Dyck word as a continuous path.
|
|
868
|
+
|
|
869
|
+
EXAMPLES::
|
|
870
|
+
|
|
871
|
+
sage: NDW = NuDyckWord('010','010')
|
|
872
|
+
sage: NDW.plot() # needs sage.plot
|
|
873
|
+
Graphics object consisting of 1 graphics primitive
|
|
874
|
+
"""
|
|
875
|
+
from sage.plot.plot import list_plot
|
|
876
|
+
return list_plot(list(self.points()), plotjoined=True, **kwds)
|
|
877
|
+
|
|
878
|
+
def path(self):
|
|
879
|
+
r"""
|
|
880
|
+
Return the underlying path object.
|
|
881
|
+
|
|
882
|
+
EXAMPLES::
|
|
883
|
+
|
|
884
|
+
sage: NDW = NuDyckWord('10011001000','00100101001')
|
|
885
|
+
sage: NDW.path()
|
|
886
|
+
Path: 10011001000
|
|
887
|
+
"""
|
|
888
|
+
return self._path
|
|
889
|
+
|
|
890
|
+
def height(self):
|
|
891
|
+
r"""
|
|
892
|
+
Return the height of ``self``.
|
|
893
|
+
|
|
894
|
+
The height is the number of ``north`` steps.
|
|
895
|
+
|
|
896
|
+
EXAMPLES::
|
|
897
|
+
|
|
898
|
+
sage: NuDyckWord('1101110011010010001101111000110000',
|
|
899
|
+
....: '1010101010101010101010101010101010').height()
|
|
900
|
+
17
|
|
901
|
+
"""
|
|
902
|
+
return self._path.height()
|
|
903
|
+
|
|
904
|
+
def width(self):
|
|
905
|
+
r"""
|
|
906
|
+
Return the width of ``self``.
|
|
907
|
+
|
|
908
|
+
The width is the number of ``east`` steps.
|
|
909
|
+
|
|
910
|
+
EXAMPLES::
|
|
911
|
+
|
|
912
|
+
sage: NuDyckWord('110111001101001000110111100011000',
|
|
913
|
+
....: '101010101010101010101010101010101').width()
|
|
914
|
+
16
|
|
915
|
+
"""
|
|
916
|
+
return self._path.width()
|
|
917
|
+
|
|
918
|
+
def length(self):
|
|
919
|
+
r"""
|
|
920
|
+
Return the length of ``self``.
|
|
921
|
+
|
|
922
|
+
The length is the total number of steps.
|
|
923
|
+
|
|
924
|
+
EXAMPLES::
|
|
925
|
+
|
|
926
|
+
sage: NDW = NuDyckWord('10011001000','00100101001')
|
|
927
|
+
sage: NDW.length()
|
|
928
|
+
11
|
|
929
|
+
"""
|
|
930
|
+
return self._path.length()
|
|
931
|
+
|
|
932
|
+
def points(self):
|
|
933
|
+
r"""
|
|
934
|
+
Return an iterator for the points on the `\nu`-Dyck path.
|
|
935
|
+
|
|
936
|
+
EXAMPLES::
|
|
937
|
+
|
|
938
|
+
sage: list(NuDyckWord('110111001101001000110111100011000',
|
|
939
|
+
....: '101010101010101010101010101010101')._path.points())
|
|
940
|
+
[(0, 0),
|
|
941
|
+
(0, 1),
|
|
942
|
+
(0, 2),
|
|
943
|
+
(1, 2),
|
|
944
|
+
(1, 3),
|
|
945
|
+
(1, 4),
|
|
946
|
+
(1, 5),
|
|
947
|
+
(2, 5),
|
|
948
|
+
(3, 5),
|
|
949
|
+
(3, 6),
|
|
950
|
+
(3, 7),
|
|
951
|
+
(4, 7),
|
|
952
|
+
(4, 8),
|
|
953
|
+
(5, 8),
|
|
954
|
+
(6, 8),
|
|
955
|
+
(6, 9),
|
|
956
|
+
(7, 9),
|
|
957
|
+
(8, 9),
|
|
958
|
+
(9, 9),
|
|
959
|
+
(9, 10),
|
|
960
|
+
(9, 11),
|
|
961
|
+
(10, 11),
|
|
962
|
+
(10, 12),
|
|
963
|
+
(10, 13),
|
|
964
|
+
(10, 14),
|
|
965
|
+
(10, 15),
|
|
966
|
+
(11, 15),
|
|
967
|
+
(12, 15),
|
|
968
|
+
(13, 15),
|
|
969
|
+
(13, 16),
|
|
970
|
+
(13, 17),
|
|
971
|
+
(14, 17),
|
|
972
|
+
(15, 17),
|
|
973
|
+
(16, 17)]
|
|
974
|
+
"""
|
|
975
|
+
return self._path.points()
|
|
976
|
+
|
|
977
|
+
def heights(self):
|
|
978
|
+
r"""
|
|
979
|
+
Return the heights of each point on ``self``.
|
|
980
|
+
|
|
981
|
+
We view the Dyck word as a Dyck path from `(0,0)` to
|
|
982
|
+
`(x,y)` in the first quadrant by letting ``1``'s represent
|
|
983
|
+
steps in the direction `(0,1)` and ``0``'s represent steps in
|
|
984
|
+
the direction `(1,0)`.
|
|
985
|
+
|
|
986
|
+
The heights is the sequence of the `y`-coordinates of all
|
|
987
|
+
`x+y` lattice points along the path.
|
|
988
|
+
|
|
989
|
+
EXAMPLES::
|
|
990
|
+
|
|
991
|
+
sage: NuDyckWord('010','010').heights()
|
|
992
|
+
[0, 0, 1, 1]
|
|
993
|
+
sage: NuDyckWord('110100','101010').heights()
|
|
994
|
+
[0, 1, 2, 2, 3, 3, 3]
|
|
995
|
+
"""
|
|
996
|
+
return self._path.height_vector()
|
|
997
|
+
|
|
998
|
+
def widths(self):
|
|
999
|
+
r"""
|
|
1000
|
+
Return the widths of each point on ``self``.
|
|
1001
|
+
|
|
1002
|
+
We view the Dyck word as a Dyck path from `(0,0)` to
|
|
1003
|
+
`(x,y)` in the first quadrant by letting ``1``'s represent
|
|
1004
|
+
steps in the direction `(0,1)` and ``0``'s represent steps in
|
|
1005
|
+
the direction `(1,0)`.
|
|
1006
|
+
|
|
1007
|
+
The widths is the sequence of the `x`-coordinates of all
|
|
1008
|
+
`x+y` lattice points along the path.
|
|
1009
|
+
|
|
1010
|
+
EXAMPLES::
|
|
1011
|
+
|
|
1012
|
+
sage: NuDyckWord('010','010').widths()
|
|
1013
|
+
[0, 1, 1, 2]
|
|
1014
|
+
sage: NuDyckWord('110100','101010').widths()
|
|
1015
|
+
[0, 0, 0, 1, 1, 2, 3]
|
|
1016
|
+
"""
|
|
1017
|
+
return self._path.width_vector()
|
|
1018
|
+
|
|
1019
|
+
def horizontal_distance(self):
|
|
1020
|
+
r"""
|
|
1021
|
+
Return a list of how far each point is from `\nu`.
|
|
1022
|
+
|
|
1023
|
+
EXAMPLES::
|
|
1024
|
+
|
|
1025
|
+
sage: NDW = NuDyckWord('10010100','00000111')
|
|
1026
|
+
sage: NDW.horizontal_distance()
|
|
1027
|
+
[5, 5, 4, 3, 3, 2, 2, 1, 0]
|
|
1028
|
+
sage: NDW = NuDyckWord('10010100','00001011')
|
|
1029
|
+
sage: NDW.horizontal_distance()
|
|
1030
|
+
[4, 5, 4, 3, 3, 2, 2, 1, 0]
|
|
1031
|
+
sage: NDW = NuDyckWord('10011001000','00100101001')
|
|
1032
|
+
sage: NDW.horizontal_distance()
|
|
1033
|
+
[2, 4, 3, 2, 3, 5, 4, 3, 3, 2, 1, 0]
|
|
1034
|
+
"""
|
|
1035
|
+
# Grab furthest east point at each height of nu
|
|
1036
|
+
nu_points = list(self._nu.points())
|
|
1037
|
+
nu_easts = [max(i for i, j in nu_points if j == k)
|
|
1038
|
+
for k in range(self._nu.height() + 1)]
|
|
1039
|
+
|
|
1040
|
+
points = list(self._path.points())
|
|
1041
|
+
return [nu_easts[j] - i for i, j in points]
|
|
1042
|
+
|
|
1043
|
+
def can_mutate(self, i) -> bool | int:
|
|
1044
|
+
"""
|
|
1045
|
+
Return True/False based off if mutable at height `i`.
|
|
1046
|
+
|
|
1047
|
+
Can only mutate if an east step is followed by a north step at height
|
|
1048
|
+
`i`.
|
|
1049
|
+
|
|
1050
|
+
OUTPUT: whether we can mutate at height of `i`
|
|
1051
|
+
|
|
1052
|
+
EXAMPLES::
|
|
1053
|
+
|
|
1054
|
+
sage: NDW = NuDyckWord('10010100','00000111')
|
|
1055
|
+
sage: NDW.can_mutate(1)
|
|
1056
|
+
False
|
|
1057
|
+
sage: NDW.can_mutate(3)
|
|
1058
|
+
5
|
|
1059
|
+
|
|
1060
|
+
TESTS::
|
|
1061
|
+
|
|
1062
|
+
sage: NDW = NuDyckWord('10010100','00000111')
|
|
1063
|
+
sage: NDW.can_mutate(33)
|
|
1064
|
+
Traceback (most recent call last):
|
|
1065
|
+
...
|
|
1066
|
+
ValueError: cannot mutate above or below path
|
|
1067
|
+
"""
|
|
1068
|
+
if i > self.height() or i <= 0:
|
|
1069
|
+
raise ValueError('cannot mutate above or below path')
|
|
1070
|
+
|
|
1071
|
+
# Find the ith north step
|
|
1072
|
+
level = 0
|
|
1073
|
+
ndw = self._list
|
|
1074
|
+
for j, k in enumerate(ndw):
|
|
1075
|
+
if k == ndw_open_symbol:
|
|
1076
|
+
level += 1
|
|
1077
|
+
if level == i:
|
|
1078
|
+
break
|
|
1079
|
+
if j > 0 and ndw[j - 1] == ndw_close_symbol:
|
|
1080
|
+
return j
|
|
1081
|
+
return False
|
|
1082
|
+
|
|
1083
|
+
def mutate(self, i) -> None | NuDyckWord:
|
|
1084
|
+
r"""
|
|
1085
|
+
Return a new `\nu`-Dyck Word if possible.
|
|
1086
|
+
|
|
1087
|
+
If at height `i` we have an east step E meeting a north step N then we
|
|
1088
|
+
calculate all horizontal distances from this point until we find
|
|
1089
|
+
the first point that has the same horizontal distance to `\nu`. We let
|
|
1090
|
+
|
|
1091
|
+
- d is everything up until EN (not including EN)
|
|
1092
|
+
|
|
1093
|
+
- f be everything between N and the point with the same horizontal
|
|
1094
|
+
distance (including N)
|
|
1095
|
+
|
|
1096
|
+
- g is everything after f
|
|
1097
|
+
|
|
1098
|
+
.. SEEALSO:: :meth:`can_mutate`
|
|
1099
|
+
|
|
1100
|
+
EXAMPLES::
|
|
1101
|
+
|
|
1102
|
+
sage: NDW = NuDyckWord('10010100','00000111')
|
|
1103
|
+
sage: NDW.mutate(1)
|
|
1104
|
+
sage: NDW.mutate(3)
|
|
1105
|
+
[1, 0, 0, 1, 1, 0, 0, 0]
|
|
1106
|
+
"""
|
|
1107
|
+
mutation_index = self.can_mutate(i)
|
|
1108
|
+
if not mutation_index:
|
|
1109
|
+
return None
|
|
1110
|
+
|
|
1111
|
+
horiz = self.horizontal_distance()
|
|
1112
|
+
# Find horiz in between East and North Step
|
|
1113
|
+
horiz_num = horiz[mutation_index]
|
|
1114
|
+
other_index = len(horiz)
|
|
1115
|
+
for i in range(mutation_index + 1, len(horiz)):
|
|
1116
|
+
if horiz[i] == horiz_num:
|
|
1117
|
+
other_index = i
|
|
1118
|
+
break
|
|
1119
|
+
ndw = self._list
|
|
1120
|
+
d = ndw[0:mutation_index - 1]
|
|
1121
|
+
e = ndw[mutation_index:other_index]
|
|
1122
|
+
f = ndw[other_index:]
|
|
1123
|
+
return NuDyckWord(d + e + [ndw_close_symbol] + f, self._nu)
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
class NuDyckWords(Parent):
|
|
1127
|
+
r"""
|
|
1128
|
+
`\nu`-Dyck words.
|
|
1129
|
+
|
|
1130
|
+
Given a lattice path `\nu` in the `\ZZ^2` grid starting at the origin
|
|
1131
|
+
`(0,0)` consisting of North `N = (0,1)` and East `E = (1,0)` steps, a
|
|
1132
|
+
`\nu`-Dyck path is a lattice path in the`\ZZ^2` grid starting at the
|
|
1133
|
+
origin `(0,0)` and ending at the same coordinate as `\nu` such that it is
|
|
1134
|
+
weakly above `\nu`. A `\nu`-Dyck word is the representation of a
|
|
1135
|
+
`\nu`-Dyck path where a North step is represented by a 1 and an East step
|
|
1136
|
+
is represented by a 0.
|
|
1137
|
+
|
|
1138
|
+
INPUT:
|
|
1139
|
+
|
|
1140
|
+
- ``nu`` -- the base lattice path
|
|
1141
|
+
|
|
1142
|
+
EXAMPLES::
|
|
1143
|
+
|
|
1144
|
+
sage: NDW = NuDyckWords('1010'); NDW
|
|
1145
|
+
[1, 0, 1, 0] Dyck words
|
|
1146
|
+
sage: [1,0,1,0] in NDW
|
|
1147
|
+
True
|
|
1148
|
+
sage: [1,1,0,0] in NDW
|
|
1149
|
+
True
|
|
1150
|
+
sage: [1,0,0,1] in NDW
|
|
1151
|
+
False
|
|
1152
|
+
sage: [0,1,0,1] in NDW
|
|
1153
|
+
False
|
|
1154
|
+
sage: NDW.cardinality()
|
|
1155
|
+
2
|
|
1156
|
+
"""
|
|
1157
|
+
|
|
1158
|
+
Element = NuDyckWord
|
|
1159
|
+
|
|
1160
|
+
def __init__(self, nu=()) -> None:
|
|
1161
|
+
"""
|
|
1162
|
+
Initialize ``self``.
|
|
1163
|
+
|
|
1164
|
+
EXAMPLES::
|
|
1165
|
+
|
|
1166
|
+
sage: TestSuite(NuDyckWords(nu=[1,0,1])).run()
|
|
1167
|
+
"""
|
|
1168
|
+
Parent.__init__(self, category=FiniteEnumeratedSets())
|
|
1169
|
+
|
|
1170
|
+
self._nu = to_word_path(nu)
|
|
1171
|
+
if self._nu is None:
|
|
1172
|
+
raise ValueError("invalid nu supplied")
|
|
1173
|
+
|
|
1174
|
+
# add options to class
|
|
1175
|
+
class options(GlobalOptions):
|
|
1176
|
+
r"""
|
|
1177
|
+
Set and display the options for `\nu`-Dyck words. If no parameters
|
|
1178
|
+
are set, then the function returns a copy of the options dictionary.
|
|
1179
|
+
|
|
1180
|
+
The ``options`` to `\nu`-Dyck words can be accessed as the method
|
|
1181
|
+
:meth:`NuDyckWords.options` of :class:`NuDyckWords` and
|
|
1182
|
+
related parent classes.
|
|
1183
|
+
|
|
1184
|
+
@OPTIONS
|
|
1185
|
+
|
|
1186
|
+
EXAMPLES::
|
|
1187
|
+
|
|
1188
|
+
sage: ND = NuDyckWords('101')
|
|
1189
|
+
sage: ND
|
|
1190
|
+
[1, 0, 1] Dyck words
|
|
1191
|
+
sage: ND.options
|
|
1192
|
+
Current options for NuDyckWords
|
|
1193
|
+
- ascii_art: pretty_output
|
|
1194
|
+
- diagram_style: grid
|
|
1195
|
+
- display: list
|
|
1196
|
+
- latex_color: black
|
|
1197
|
+
- latex_line_width_scalar: 2
|
|
1198
|
+
- latex_nu_options: rounded corners=1, color=red, line width=1
|
|
1199
|
+
- latex_points_color: black
|
|
1200
|
+
- latex_show_grid: True
|
|
1201
|
+
- latex_show_nu: True
|
|
1202
|
+
- latex_show_points: False
|
|
1203
|
+
- latex_tikz_scale: 1
|
|
1204
|
+
"""
|
|
1205
|
+
NAME = 'NuDyckWords'
|
|
1206
|
+
module = 'sage.combinat.nu_dyck_path'
|
|
1207
|
+
display = {'default': "list",
|
|
1208
|
+
'description': 'Specifies how nu Dyck words should be printed',
|
|
1209
|
+
'values': {'list': 'displayed as a list',
|
|
1210
|
+
'lattice': 'displayed on the lattice defined by ``diagram_style``'},
|
|
1211
|
+
'case_sensitive': False}
|
|
1212
|
+
ascii_art = {'default': "pretty_output",
|
|
1213
|
+
'description': 'Specifies how the ascii art of nu Dyck words should be printed',
|
|
1214
|
+
'values': {'pretty_output': "Using pretty printing"},
|
|
1215
|
+
'alias': {'pretty_print': "pretty_output"},
|
|
1216
|
+
'case_sensitive': False}
|
|
1217
|
+
diagram_style = {'default': "grid",
|
|
1218
|
+
'values': {
|
|
1219
|
+
'grid': 'printing as paths on a grid using N and E steps'},
|
|
1220
|
+
'alias': {'N-E': 'grid'},
|
|
1221
|
+
'case_sensitive': False}
|
|
1222
|
+
latex_tikz_scale = {'default': 1,
|
|
1223
|
+
'description': 'The default value for the tikz scale when latexed',
|
|
1224
|
+
'checker': lambda x: True} # More trouble than it's worth to check
|
|
1225
|
+
latex_line_width_scalar = {'default': 2,
|
|
1226
|
+
'description': 'The default value for the line width as a '
|
|
1227
|
+
'multiple of the tikz scale when latexed',
|
|
1228
|
+
'checker': lambda x: True} # More trouble than it's worth to check
|
|
1229
|
+
latex_color = {'default': "black",
|
|
1230
|
+
'description': 'The default value for the color when latexed',
|
|
1231
|
+
'checker': lambda x: isinstance(x, str)}
|
|
1232
|
+
latex_show_points = {'default': False,
|
|
1233
|
+
'description': 'The default value for showing points',
|
|
1234
|
+
'checker': lambda x: isinstance(x, bool)}
|
|
1235
|
+
latex_points_color = {'default': 'black',
|
|
1236
|
+
'description': 'The default value for path color.',
|
|
1237
|
+
'checker': lambda x: isinstance(x, str)}
|
|
1238
|
+
latex_show_grid = {'default': True,
|
|
1239
|
+
'description': 'The default value for showing grid',
|
|
1240
|
+
'checker': lambda x: isinstance(x, bool)}
|
|
1241
|
+
latex_show_nu = {'default': True,
|
|
1242
|
+
'description': 'The default value for showing nu',
|
|
1243
|
+
'checker': lambda x: isinstance(x, bool)}
|
|
1244
|
+
latex_nu_options = {'default': 'rounded corners=1, color=red, line width=1',
|
|
1245
|
+
'description': 'The default value for options for nu path',
|
|
1246
|
+
'checker': lambda x: isinstance(x, str)}
|
|
1247
|
+
|
|
1248
|
+
def _element_constructor_(self, word):
|
|
1249
|
+
"""
|
|
1250
|
+
Construct an element of ``self``.
|
|
1251
|
+
|
|
1252
|
+
EXAMPLES::
|
|
1253
|
+
|
|
1254
|
+
sage: NDW = NuDyckWords('101')
|
|
1255
|
+
sage: elt = NDW('110'); elt
|
|
1256
|
+
[1, 1, 0]
|
|
1257
|
+
sage: elt.parent() is NDW
|
|
1258
|
+
True
|
|
1259
|
+
"""
|
|
1260
|
+
if isinstance(word, NuDyckWord) and word.parent() is self:
|
|
1261
|
+
return word
|
|
1262
|
+
return self.element_class(self, to_word_path(word))
|
|
1263
|
+
|
|
1264
|
+
def __contains__(self, x) -> bool:
|
|
1265
|
+
r"""
|
|
1266
|
+
Check for containment.
|
|
1267
|
+
|
|
1268
|
+
TESTS::
|
|
1269
|
+
|
|
1270
|
+
sage: NDW = NuDyckWords([1,0,1,1])
|
|
1271
|
+
sage: [1,1,0,1] in NDW
|
|
1272
|
+
True
|
|
1273
|
+
sage: [1,0,1,1] in NDW
|
|
1274
|
+
True
|
|
1275
|
+
sage: [0] in NDW
|
|
1276
|
+
False
|
|
1277
|
+
sage: [1, 0] in NDW
|
|
1278
|
+
False
|
|
1279
|
+
"""
|
|
1280
|
+
return path_weakly_above_other(to_word_path(x), self._nu)
|
|
1281
|
+
|
|
1282
|
+
def __eq__(self, other):
|
|
1283
|
+
"""
|
|
1284
|
+
Return equality.
|
|
1285
|
+
|
|
1286
|
+
TESTS::
|
|
1287
|
+
|
|
1288
|
+
sage: A = NuDyckWords([1,0,1,1])
|
|
1289
|
+
sage: B = NuDyckWords([1,0,1,1])
|
|
1290
|
+
sage: C = NuDyckWords([1,0,1,1,1])
|
|
1291
|
+
sage: A == B
|
|
1292
|
+
True
|
|
1293
|
+
sage: A == C
|
|
1294
|
+
False
|
|
1295
|
+
"""
|
|
1296
|
+
if not isinstance(other, NuDyckWords):
|
|
1297
|
+
return False
|
|
1298
|
+
return self._nu == other._nu
|
|
1299
|
+
|
|
1300
|
+
def __neq__(self, other):
|
|
1301
|
+
"""
|
|
1302
|
+
Return inequality.
|
|
1303
|
+
|
|
1304
|
+
TESTS::
|
|
1305
|
+
|
|
1306
|
+
sage: A = NuDyckWords([1,0,1,1])
|
|
1307
|
+
sage: B = NuDyckWords([1,0,1,1])
|
|
1308
|
+
sage: C = NuDyckWords([1,0,1,1,1])
|
|
1309
|
+
sage: A != B
|
|
1310
|
+
False
|
|
1311
|
+
sage: A != C
|
|
1312
|
+
True
|
|
1313
|
+
"""
|
|
1314
|
+
return not self.__eq__(other)
|
|
1315
|
+
|
|
1316
|
+
def _repr_(self) -> str:
|
|
1317
|
+
r"""
|
|
1318
|
+
TESTS::
|
|
1319
|
+
|
|
1320
|
+
sage: NuDyckWords([1,0,1,1])
|
|
1321
|
+
[1, 0, 1, 1] Dyck words
|
|
1322
|
+
"""
|
|
1323
|
+
return f"{list(self._nu)} Dyck words"
|
|
1324
|
+
|
|
1325
|
+
def _cache_key(self) -> str:
|
|
1326
|
+
"""
|
|
1327
|
+
Return a cache key
|
|
1328
|
+
|
|
1329
|
+
TESTS::
|
|
1330
|
+
|
|
1331
|
+
sage: NuDyckWords([1,0,1,1])._cache_key()
|
|
1332
|
+
'1011'
|
|
1333
|
+
"""
|
|
1334
|
+
return str(self._nu)
|
|
1335
|
+
|
|
1336
|
+
def _an_element_(self):
|
|
1337
|
+
r"""
|
|
1338
|
+
Return an element.
|
|
1339
|
+
|
|
1340
|
+
TESTS::
|
|
1341
|
+
|
|
1342
|
+
sage: NuDyckWords('101').an_element()
|
|
1343
|
+
[1, 0, 1]
|
|
1344
|
+
"""
|
|
1345
|
+
return self.element_class(self, self._nu)
|
|
1346
|
+
|
|
1347
|
+
def __iter__(self, N=[], D=[], i=None, X=None):
|
|
1348
|
+
"""
|
|
1349
|
+
Iterate over ``self``.
|
|
1350
|
+
|
|
1351
|
+
The iterator interchanges a 0,1 pair whenever the 0 comes before a 1
|
|
1352
|
+
|
|
1353
|
+
EXAMPLES::
|
|
1354
|
+
|
|
1355
|
+
sage: it = NuDyckWords('101010').__iter__()
|
|
1356
|
+
sage: [i for i in it]
|
|
1357
|
+
[[1, 0, 1, 0, 1, 0],
|
|
1358
|
+
[1, 1, 0, 0, 1, 0],
|
|
1359
|
+
[1, 0, 1, 1, 0, 0],
|
|
1360
|
+
[1, 1, 0, 1, 0, 0],
|
|
1361
|
+
[1, 1, 1, 0, 0, 0]]
|
|
1362
|
+
"""
|
|
1363
|
+
# Define successor function for recursion
|
|
1364
|
+
def transpose_close_open(N):
|
|
1365
|
+
for k, v in enumerate(N._list):
|
|
1366
|
+
if k > 0 and v == ndw_open_symbol:
|
|
1367
|
+
w = N._list[k - 1]
|
|
1368
|
+
if w == ndw_close_symbol:
|
|
1369
|
+
new = N._list[:k - 1] + [v, w] + N._list[k + 1:]
|
|
1370
|
+
yield self.element_class(self, new)
|
|
1371
|
+
|
|
1372
|
+
RES = RecursivelyEnumeratedSet([self.element_class(self, self._nu)],
|
|
1373
|
+
transpose_close_open)
|
|
1374
|
+
return RES.breadth_first_search_iterator()
|
|
1375
|
+
|
|
1376
|
+
def cardinality(self):
|
|
1377
|
+
r"""
|
|
1378
|
+
Return the number of `\nu`-Dyck words.
|
|
1379
|
+
|
|
1380
|
+
EXAMPLES::
|
|
1381
|
+
|
|
1382
|
+
sage: NDW = NuDyckWords('101010'); NDW.cardinality()
|
|
1383
|
+
5
|
|
1384
|
+
sage: NDW = NuDyckWords('1010010'); NDW.cardinality()
|
|
1385
|
+
7
|
|
1386
|
+
sage: NDW = NuDyckWords('100100100'); NDW.cardinality()
|
|
1387
|
+
12
|
|
1388
|
+
"""
|
|
1389
|
+
return Integer(len([1 for _ in self.__iter__()]))
|
|
1390
|
+
|
|
1391
|
+
|
|
1392
|
+
def to_word_path(word):
|
|
1393
|
+
r"""
|
|
1394
|
+
Convert input into a word path over an appropriate alphabet.
|
|
1395
|
+
|
|
1396
|
+
Helper function.
|
|
1397
|
+
|
|
1398
|
+
INPUT:
|
|
1399
|
+
|
|
1400
|
+
- ``word`` -- word to convert to wordpath
|
|
1401
|
+
|
|
1402
|
+
OUTPUT: a ``FiniteWordPath_north_east`` object
|
|
1403
|
+
|
|
1404
|
+
EXAMPLES::
|
|
1405
|
+
|
|
1406
|
+
sage: from sage.combinat.nu_dyck_word import to_word_path
|
|
1407
|
+
sage: wp = to_word_path('NEENENEN'); wp
|
|
1408
|
+
Path: 10010101
|
|
1409
|
+
sage: from sage.combinat.words.paths import FiniteWordPath_north_east
|
|
1410
|
+
sage: isinstance(wp,FiniteWordPath_north_east)
|
|
1411
|
+
True
|
|
1412
|
+
sage: to_word_path('1001')
|
|
1413
|
+
Path: 1001
|
|
1414
|
+
sage: to_word_path([0,1,0,0,1,0])
|
|
1415
|
+
Path: 010010
|
|
1416
|
+
"""
|
|
1417
|
+
# If we already have the object, don't worry
|
|
1418
|
+
if isinstance(word, FiniteWordPath_north_east):
|
|
1419
|
+
return word
|
|
1420
|
+
|
|
1421
|
+
# If we have a Nu Dyck Path, return the path it contains
|
|
1422
|
+
if isinstance(word, NuDyckWord):
|
|
1423
|
+
return word.path()
|
|
1424
|
+
|
|
1425
|
+
# if we have a string, convert to list
|
|
1426
|
+
if isinstance(word, str):
|
|
1427
|
+
word = map(replace_dyck_char, word)
|
|
1428
|
+
|
|
1429
|
+
# By default "north" is first symbol, "east" is second symbol
|
|
1430
|
+
P = WordPaths_north_east([ndw_open_symbol, ndw_close_symbol])
|
|
1431
|
+
|
|
1432
|
+
return P(word)
|
|
1433
|
+
|
|
1434
|
+
|
|
1435
|
+
def path_weakly_above_other(path, other) -> bool:
|
|
1436
|
+
r"""
|
|
1437
|
+
Test if ``path`` is weakly above ``other``.
|
|
1438
|
+
|
|
1439
|
+
A path `P` is wealy above another path `Q` if `P` and `Q` are the same
|
|
1440
|
+
length and if any prefix of length `n` of `Q` contains more North steps
|
|
1441
|
+
than the prefix of length `n` of `P`.
|
|
1442
|
+
|
|
1443
|
+
INPUT:
|
|
1444
|
+
|
|
1445
|
+
- ``path`` -- the path to verify is weakly above the other path
|
|
1446
|
+
|
|
1447
|
+
- ``other`` -- the other path to verify is weakly below the path
|
|
1448
|
+
|
|
1449
|
+
OUTPUT: boolean
|
|
1450
|
+
|
|
1451
|
+
EXAMPLES::
|
|
1452
|
+
|
|
1453
|
+
sage: from sage.combinat.nu_dyck_word import path_weakly_above_other
|
|
1454
|
+
sage: path_weakly_above_other('1001','0110')
|
|
1455
|
+
False
|
|
1456
|
+
sage: path_weakly_above_other('1001','0101')
|
|
1457
|
+
True
|
|
1458
|
+
sage: path_weakly_above_other('1111','0101')
|
|
1459
|
+
False
|
|
1460
|
+
sage: path_weakly_above_other('111100','0101')
|
|
1461
|
+
False
|
|
1462
|
+
"""
|
|
1463
|
+
# Ensure we have word paths:
|
|
1464
|
+
path = to_word_path(path)
|
|
1465
|
+
other = to_word_path(other)
|
|
1466
|
+
|
|
1467
|
+
# Must be same length and must have same height
|
|
1468
|
+
if path.length() != other.length() or path.height() != other.height():
|
|
1469
|
+
return False
|
|
1470
|
+
|
|
1471
|
+
# path is above other if height is always >= height of other
|
|
1472
|
+
p_height = path.height_vector()
|
|
1473
|
+
o_height = other.height_vector()
|
|
1474
|
+
return all(p_h >= o_h for p_h, o_h in zip(p_height, o_height))
|