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,1602 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-combinat
|
|
2
|
+
r"""
|
|
3
|
+
Parking functions
|
|
4
|
+
|
|
5
|
+
INFORMALLY (reference [Beck]_):
|
|
6
|
+
|
|
7
|
+
Imagine a one-way cul-de-sac with `n` parking spots. We will give the
|
|
8
|
+
first parking spot the number 1, the next one number 2, etc., down to
|
|
9
|
+
the last one, number `n`. Initially they are all free, but there are
|
|
10
|
+
`n` cars approaching the street, and they would all like to park there.
|
|
11
|
+
To make life interesting, every car has a parking preference, and we
|
|
12
|
+
record the preferences in a sequence; For example, if `n = 3`, the
|
|
13
|
+
sequence `(2, 1, 1)` means that the first car would like to park at
|
|
14
|
+
spot number 2, the second car prefers parking spot number 1, and the
|
|
15
|
+
last car would also like to part at number 1. The street is very
|
|
16
|
+
narrow, so there is no way to back up. Now each car enters the street
|
|
17
|
+
and approaches its preferred parking spot; if it is free, it parks
|
|
18
|
+
there, and if not, it moves down the street to the first available
|
|
19
|
+
spot. We call a sequence a parking function (of length `n`) if all
|
|
20
|
+
cars end up finding a parking spot. For example, the sequence `(2, 1,
|
|
21
|
+
1)` is a parking sequence (of length 3), whereas the sequence `(2, 3,
|
|
22
|
+
2)` is not.
|
|
23
|
+
|
|
24
|
+
FORMALLY:
|
|
25
|
+
|
|
26
|
+
A parking function of size `n` is a sequence `(a_1, \ldots, a_n)` of
|
|
27
|
+
positive integers such that if `b_1 \leq b_2 \leq \cdots \leq b_n` is
|
|
28
|
+
the increasing rearrangement of `a_1, \ldots, a_n`, then `b_i \leq i`.
|
|
29
|
+
|
|
30
|
+
A parking function of size `n` is a pair `(L, D)` of two sequences `L`
|
|
31
|
+
and `D` where `L` is a permutation and `D` is an area sequence of a
|
|
32
|
+
Dyck path of size n such that `D[i] \geq 0`, `D[i+1] \leq D[i]+1` and
|
|
33
|
+
if `D[i+1] = D[i]+1` then `L[i+1] > L[i]`.
|
|
34
|
+
|
|
35
|
+
The number of parking functions of size `n` is equal to the number of
|
|
36
|
+
rooted forests on `n` vertices and is equal to `(n+1)^{n-1}`.
|
|
37
|
+
|
|
38
|
+
REFERENCES:
|
|
39
|
+
|
|
40
|
+
.. [Beck] \M. Beck, Stanford Math Circle - Parking Functions, October 2010,
|
|
41
|
+
http://math.stanford.edu/circle/parkingBeck.pdf
|
|
42
|
+
|
|
43
|
+
.. [Hag08] The `q,t` -- Catalan Numbers and the Space of Diagonal Harmonics:
|
|
44
|
+
With an Appendix on the Combinatorics of Macdonald Polynomials, James Haglund,
|
|
45
|
+
University of Pennsylvania, Philadelphia -- AMS, 2008, 167 pp.
|
|
46
|
+
|
|
47
|
+
.. [Shin] \H. Shin, Forests and Parking Functions, slides from talk September 24, 2008,
|
|
48
|
+
http://www.emis.de/journals/SLC/wpapers/s61vortrag/shin.pdf
|
|
49
|
+
|
|
50
|
+
.. [GXZ] \A. M. Garsia, G. Xin, M. Zabrocki, A three shuffle case of the
|
|
51
|
+
compositional parking function conjecture, :arxiv:`1208.5796v1`
|
|
52
|
+
|
|
53
|
+
AUTHORS:
|
|
54
|
+
|
|
55
|
+
- used non-decreasing_parking_functions code by Florent Hivert (2009 - 04)
|
|
56
|
+
- Dorota Mazur (2012 - 09)
|
|
57
|
+
"""
|
|
58
|
+
# ****************************************************************************
|
|
59
|
+
# Copyright (C) 2012 Dorota Mazur <dorota@yorku.ca>
|
|
60
|
+
#
|
|
61
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
62
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
63
|
+
# the License, or (at your option) any later version.
|
|
64
|
+
# https://www.gnu.org/licenses/
|
|
65
|
+
# ****************************************************************************
|
|
66
|
+
from __future__ import annotations
|
|
67
|
+
from collections.abc import Iterator
|
|
68
|
+
|
|
69
|
+
from sage.rings.integer import Integer
|
|
70
|
+
from sage.rings.rational_field import QQ
|
|
71
|
+
from sage.structure.list_clone import ClonableArray
|
|
72
|
+
from sage.combinat.permutation import Permutation, Permutations
|
|
73
|
+
from sage.combinat.non_decreasing_parking_function import is_a as check_NDPF
|
|
74
|
+
from sage.combinat.dyck_word import DyckWord
|
|
75
|
+
from sage.combinat.combinatorial_map import combinatorial_map
|
|
76
|
+
from sage.misc.prandom import randint
|
|
77
|
+
from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass
|
|
78
|
+
from sage.rings.finite_rings.integer_mod_ring import Zmod
|
|
79
|
+
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
|
|
80
|
+
from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets
|
|
81
|
+
from sage.categories.sets_with_grading import SetsWithGrading
|
|
82
|
+
from sage.structure.parent import Parent
|
|
83
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def is_a(x, n=None) -> bool:
|
|
87
|
+
r"""
|
|
88
|
+
Check whether a list is a parking function.
|
|
89
|
+
|
|
90
|
+
If a size `n` is specified, checks if a list is a parking function
|
|
91
|
+
of size `n`.
|
|
92
|
+
|
|
93
|
+
TESTS::
|
|
94
|
+
|
|
95
|
+
sage: from sage.combinat.parking_functions import is_a
|
|
96
|
+
sage: is_a([1,1,2])
|
|
97
|
+
True
|
|
98
|
+
sage: is_a([1,2,1])
|
|
99
|
+
True
|
|
100
|
+
sage: is_a([1,1,4])
|
|
101
|
+
False
|
|
102
|
+
sage: is_a([3,1,1], 3)
|
|
103
|
+
True
|
|
104
|
+
"""
|
|
105
|
+
if not isinstance(x, list): # from Florent Hivert non_decreasing_parking_function
|
|
106
|
+
return False
|
|
107
|
+
A = sorted(x)
|
|
108
|
+
return check_NDPF(A, n)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class ParkingFunction(ClonableArray, metaclass=InheritComparisonClasscallMetaclass):
|
|
112
|
+
r"""
|
|
113
|
+
A Parking Function.
|
|
114
|
+
|
|
115
|
+
A *parking function* of size `n` is a sequence `(a_1, \ldots,a_n)`
|
|
116
|
+
of positive integers such that if `b_1 \leq b_2 \leq \cdots \leq b_n` is
|
|
117
|
+
the increasing rearrangement of `a_1, \ldots, a_n`, then `b_i \leq i`.
|
|
118
|
+
|
|
119
|
+
A *parking function* of size `n` is a pair `(L, D)` of two sequences
|
|
120
|
+
`L` and `D` where `L` is a permutation and `D` is an area sequence
|
|
121
|
+
of a Dyck Path of size `n` such that `D[i] \geq 0`, `D[i+1] \leq D[i]+1`
|
|
122
|
+
and if `D[i+1] = D[i]+1` then `L[i+1] > L[i]`.
|
|
123
|
+
|
|
124
|
+
The number of parking functions of size `n` is equal to the number
|
|
125
|
+
of rooted forests on `n` vertices and is equal to `(n+1)^{n-1}`.
|
|
126
|
+
|
|
127
|
+
INPUT:
|
|
128
|
+
|
|
129
|
+
- ``pf`` -- (default: ``None``) a list whose increasing rearrangement
|
|
130
|
+
satisfies `b_i \leq i`
|
|
131
|
+
|
|
132
|
+
- ``labelling`` -- (default: ``None``) a labelling of the Dyck path
|
|
133
|
+
|
|
134
|
+
- ``area_sequence`` -- (default: ``None``) an area sequence of a Dyck path
|
|
135
|
+
|
|
136
|
+
- ``labelled_dyck_word`` -- (default: ``None``) a Dyck word with 1s
|
|
137
|
+
replaced by labelling
|
|
138
|
+
|
|
139
|
+
OUTPUT: a parking function
|
|
140
|
+
|
|
141
|
+
EXAMPLES::
|
|
142
|
+
|
|
143
|
+
sage: ParkingFunction([])
|
|
144
|
+
[]
|
|
145
|
+
sage: ParkingFunction([1])
|
|
146
|
+
[1]
|
|
147
|
+
sage: ParkingFunction([2])
|
|
148
|
+
Traceback (most recent call last):
|
|
149
|
+
...
|
|
150
|
+
ValueError: [2] is not a parking function
|
|
151
|
+
sage: ParkingFunction([1,2])
|
|
152
|
+
[1, 2]
|
|
153
|
+
sage: ParkingFunction([1,1,2])
|
|
154
|
+
[1, 1, 2]
|
|
155
|
+
sage: ParkingFunction([1,4,1])
|
|
156
|
+
Traceback (most recent call last):
|
|
157
|
+
...
|
|
158
|
+
ValueError: [1, 4, 1] is not a parking function
|
|
159
|
+
sage: ParkingFunction(labelling=[3,1,2], area_sequence=[0,0,1])
|
|
160
|
+
[2, 2, 1]
|
|
161
|
+
sage: ParkingFunction([2,2,1]).to_labelled_dyck_word()
|
|
162
|
+
[3, 0, 1, 2, 0, 0]
|
|
163
|
+
sage: ParkingFunction(labelled_dyck_word=[3,0,1,2,0,0])
|
|
164
|
+
[2, 2, 1]
|
|
165
|
+
sage: ParkingFunction(labelling=[3,1,2], area_sequence=[0,1,1])
|
|
166
|
+
Traceback (most recent call last):
|
|
167
|
+
...
|
|
168
|
+
ValueError: [3, 1, 2] is not a valid labeling of area sequence [0, 1, 1]
|
|
169
|
+
"""
|
|
170
|
+
@staticmethod
|
|
171
|
+
def __classcall_private__(cls, pf=None, labelling=None, area_sequence=None,
|
|
172
|
+
labelled_dyck_word=None):
|
|
173
|
+
"""
|
|
174
|
+
Construct a parking function based on the input.
|
|
175
|
+
|
|
176
|
+
TESTS::
|
|
177
|
+
|
|
178
|
+
sage: PF = ParkingFunction([1,2])
|
|
179
|
+
sage: isinstance(PF, ParkingFunctions().element_class)
|
|
180
|
+
True
|
|
181
|
+
"""
|
|
182
|
+
if isinstance(pf, ParkingFunction):
|
|
183
|
+
return pf
|
|
184
|
+
if pf is not None:
|
|
185
|
+
PF = ParkingFunctions()
|
|
186
|
+
return PF.element_class(PF, pf)
|
|
187
|
+
elif labelling is not None:
|
|
188
|
+
if (area_sequence is None):
|
|
189
|
+
raise ValueError("must also provide area sequence along with labelling")
|
|
190
|
+
if (len(area_sequence) != len(labelling)):
|
|
191
|
+
raise ValueError("%s must be the same size as the labelling %s" % (area_sequence, labelling))
|
|
192
|
+
if any(area_sequence[i] < area_sequence[i + 1] and labelling[i] > labelling[i + 1] for i in range(len(labelling) - 1)):
|
|
193
|
+
raise ValueError("%s is not a valid labeling of area sequence %s" % (labelling, area_sequence))
|
|
194
|
+
return from_labelling_and_area_sequence(labelling, area_sequence)
|
|
195
|
+
elif labelled_dyck_word is not None:
|
|
196
|
+
return from_labelled_dyck_word(labelled_dyck_word)
|
|
197
|
+
elif area_sequence is not None:
|
|
198
|
+
DW = DyckWord(area_sequence)
|
|
199
|
+
return ParkingFunction(labelling=list(range(1, DW.size() + 1)),
|
|
200
|
+
area_sequence=DW)
|
|
201
|
+
|
|
202
|
+
raise ValueError("did not manage to make this into a parking function")
|
|
203
|
+
|
|
204
|
+
def __init__(self, parent, lst):
|
|
205
|
+
"""
|
|
206
|
+
TESTS::
|
|
207
|
+
|
|
208
|
+
sage: ParkingFunction([1, 1, 2, 2, 5, 6])
|
|
209
|
+
[1, 1, 2, 2, 5, 6]
|
|
210
|
+
|
|
211
|
+
sage: PF = ParkingFunction([1, 1, 2, 2, 5, 6])
|
|
212
|
+
sage: PF[0]
|
|
213
|
+
1
|
|
214
|
+
sage: PF[2]
|
|
215
|
+
2
|
|
216
|
+
|
|
217
|
+
sage: PF4 = ParkingFunctions(4)
|
|
218
|
+
sage: a = PF4.list()[36]
|
|
219
|
+
sage: b = PF4([1,3,2,1])
|
|
220
|
+
sage: type(a)
|
|
221
|
+
<class 'sage.combinat.parking_functions.ParkingFunctions_n_with_category.element_class'>
|
|
222
|
+
sage: type(b)
|
|
223
|
+
<class 'sage.combinat.parking_functions.ParkingFunctions_n_with_category.element_class'>
|
|
224
|
+
|
|
225
|
+
Some checks for more general inputs::
|
|
226
|
+
|
|
227
|
+
sage: PF = ParkingFunction((1, 1, 2, 2, 5, 6))
|
|
228
|
+
sage: PF = ParkingFunction(Permutation([4,2,3,1]))
|
|
229
|
+
"""
|
|
230
|
+
if not isinstance(lst, list):
|
|
231
|
+
try:
|
|
232
|
+
lst = list(lst)
|
|
233
|
+
except TypeError:
|
|
234
|
+
raise TypeError('input must be convertible to a list')
|
|
235
|
+
if parent is None:
|
|
236
|
+
parent = ParkingFunctions_n(len(lst))
|
|
237
|
+
ClonableArray.__init__(self, parent, lst)
|
|
238
|
+
|
|
239
|
+
def check(self):
|
|
240
|
+
"""
|
|
241
|
+
Check that ``self`` is a valid parking function.
|
|
242
|
+
|
|
243
|
+
EXAMPLES::
|
|
244
|
+
|
|
245
|
+
sage: PF = ParkingFunction([1, 1, 2, 2, 5, 6])
|
|
246
|
+
sage: PF.check()
|
|
247
|
+
"""
|
|
248
|
+
if not check_NDPF(sorted(self), len(self)):
|
|
249
|
+
raise ValueError(f'{list(self)} is not a parking function')
|
|
250
|
+
|
|
251
|
+
def grade(self):
|
|
252
|
+
"""
|
|
253
|
+
Return the length of the parking function.
|
|
254
|
+
|
|
255
|
+
EXAMPLES::
|
|
256
|
+
|
|
257
|
+
sage: PF = ParkingFunction([1, 1, 2, 2, 5, 6])
|
|
258
|
+
sage: PF.grade()
|
|
259
|
+
6
|
|
260
|
+
"""
|
|
261
|
+
return len(self)
|
|
262
|
+
|
|
263
|
+
def __call__(self, n):
|
|
264
|
+
"""
|
|
265
|
+
Return the image of ``n`` under the parking function.
|
|
266
|
+
|
|
267
|
+
EXAMPLES::
|
|
268
|
+
|
|
269
|
+
sage: PF = ParkingFunction([1, 1, 2, 2, 5, 6])
|
|
270
|
+
sage: PF(3)
|
|
271
|
+
2
|
|
272
|
+
sage: PF(6)
|
|
273
|
+
6
|
|
274
|
+
"""
|
|
275
|
+
return self[n - 1]
|
|
276
|
+
|
|
277
|
+
def diagonal_reading_word(self) -> Permutation:
|
|
278
|
+
r"""
|
|
279
|
+
Return a diagonal word of the labelled Dyck path corresponding to parking
|
|
280
|
+
function (see [Hag08]_ p. 75).
|
|
281
|
+
|
|
282
|
+
OUTPUT:
|
|
283
|
+
|
|
284
|
+
- returns a word, read diagonally from NE to SW of the pretty
|
|
285
|
+
print of the labelled Dyck path that corresponds to ``self``
|
|
286
|
+
and the same size as ``self``
|
|
287
|
+
|
|
288
|
+
EXAMPLES::
|
|
289
|
+
|
|
290
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
291
|
+
sage: PF.diagonal_reading_word()
|
|
292
|
+
[5, 1, 7, 4, 6, 3, 2]
|
|
293
|
+
|
|
294
|
+
::
|
|
295
|
+
|
|
296
|
+
sage: ParkingFunction([1, 1, 1]).diagonal_reading_word()
|
|
297
|
+
[3, 2, 1]
|
|
298
|
+
sage: ParkingFunction([1, 2, 3]).diagonal_reading_word()
|
|
299
|
+
[3, 2, 1]
|
|
300
|
+
sage: ParkingFunction([1, 1, 3, 4]).diagonal_reading_word()
|
|
301
|
+
[2, 4, 3, 1]
|
|
302
|
+
|
|
303
|
+
::
|
|
304
|
+
|
|
305
|
+
sage: ParkingFunction([1, 1, 1]).diagonal_word()
|
|
306
|
+
[3, 2, 1]
|
|
307
|
+
sage: ParkingFunction([1, 2, 3]).diagonal_word()
|
|
308
|
+
[3, 2, 1]
|
|
309
|
+
sage: ParkingFunction([1, 4, 3, 1]).diagonal_word()
|
|
310
|
+
[4, 2, 3, 1]
|
|
311
|
+
"""
|
|
312
|
+
L = self.to_labelling_permutation()
|
|
313
|
+
D = self.to_area_sequence()
|
|
314
|
+
m = max(D)
|
|
315
|
+
data = [L[-j - 1] for i in range(m + 1)
|
|
316
|
+
for j in range(len(L)) if D[-j - 1] == m - i]
|
|
317
|
+
return Permutation(data) # type:ignore
|
|
318
|
+
|
|
319
|
+
diagonal_word = diagonal_reading_word
|
|
320
|
+
|
|
321
|
+
def parking_permutation(self) -> Permutation:
|
|
322
|
+
# indices are cars, entries are parking spaces
|
|
323
|
+
r"""
|
|
324
|
+
Return the sequence of parking spots that are taken by cars 1
|
|
325
|
+
through `n` and corresponding to the parking function.
|
|
326
|
+
|
|
327
|
+
For example, ``parking_permutation(PF) = [6, 1, 5, 2, 3, 4,
|
|
328
|
+
7]`` means that spot 6 is taken by car 1, spot 1 by car 2,
|
|
329
|
+
spot 5 by car 3, spot 2 is taken by car 4, spot 3 is taken by
|
|
330
|
+
car 5, spot 4 is taken by car 6 and spot 7 is taken by car 7.
|
|
331
|
+
|
|
332
|
+
OUTPUT:
|
|
333
|
+
|
|
334
|
+
- the permutation of parking spots that corresponds to
|
|
335
|
+
the parking function and which is the same size as parking
|
|
336
|
+
function
|
|
337
|
+
|
|
338
|
+
EXAMPLES::
|
|
339
|
+
|
|
340
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
341
|
+
sage: PF.parking_permutation()
|
|
342
|
+
[6, 1, 5, 2, 3, 4, 7]
|
|
343
|
+
|
|
344
|
+
::
|
|
345
|
+
|
|
346
|
+
sage: ParkingFunction([3,1,1,4]).parking_permutation()
|
|
347
|
+
[3, 1, 2, 4]
|
|
348
|
+
sage: ParkingFunction([4,1,1,1]).parking_permutation()
|
|
349
|
+
[4, 1, 2, 3]
|
|
350
|
+
sage: ParkingFunction([2,1,4,1]).parking_permutation()
|
|
351
|
+
[2, 1, 4, 3]
|
|
352
|
+
"""
|
|
353
|
+
return self.cars_permutation().inverse()
|
|
354
|
+
|
|
355
|
+
@combinatorial_map(name='to car permutation')
|
|
356
|
+
def cars_permutation(self) -> Permutation:
|
|
357
|
+
# indices are parking spaces, entries are car labels
|
|
358
|
+
r"""
|
|
359
|
+
Return the sequence of cars that take parking spots 1 through `n`
|
|
360
|
+
and corresponding to the parking function.
|
|
361
|
+
|
|
362
|
+
For example, ``cars_permutation(PF) = [2, 4, 5, 6, 3, 1, 7]``
|
|
363
|
+
means that car 2 takes spots 1, car 4 takes spot 2, ..., car 1
|
|
364
|
+
takes spot 6 and car 7 takes spot 7.
|
|
365
|
+
|
|
366
|
+
OUTPUT:
|
|
367
|
+
|
|
368
|
+
- the permutation of cars corresponding to the parking function
|
|
369
|
+
and which is the same size as parking function
|
|
370
|
+
|
|
371
|
+
EXAMPLES::
|
|
372
|
+
|
|
373
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
374
|
+
sage: PF.cars_permutation()
|
|
375
|
+
[2, 4, 5, 6, 3, 1, 7]
|
|
376
|
+
|
|
377
|
+
::
|
|
378
|
+
|
|
379
|
+
sage: ParkingFunction([3,1,1,4]).cars_permutation()
|
|
380
|
+
[2, 3, 1, 4]
|
|
381
|
+
sage: ParkingFunction([4,1,1,1]).cars_permutation()
|
|
382
|
+
[2, 3, 4, 1]
|
|
383
|
+
sage: ParkingFunction([2,1,4,1]).cars_permutation()
|
|
384
|
+
[2, 1, 4, 3]
|
|
385
|
+
"""
|
|
386
|
+
out = {}
|
|
387
|
+
for i in range(len(self)):
|
|
388
|
+
j = 0
|
|
389
|
+
while self[i] + j in out:
|
|
390
|
+
j += 1
|
|
391
|
+
out[self[i] + j] = i
|
|
392
|
+
data = [out[i + 1] + 1 for i in range(len(self))]
|
|
393
|
+
return Permutation(data) # type:ignore
|
|
394
|
+
|
|
395
|
+
def jump_list(self) -> list: # cars displacements
|
|
396
|
+
r"""
|
|
397
|
+
Return the displacements of cars that corresponds to the parking function.
|
|
398
|
+
|
|
399
|
+
For example, ``jump_list(PF) = [0, 0, 0, 0, 1, 3, 2]``
|
|
400
|
+
means that car 1 through 4 parked in their preferred spots,
|
|
401
|
+
car 5 had to park one spot farther (jumped or was displaced by one
|
|
402
|
+
spot), car 6 had to jump 3 spots, and car 7 had to jump two spots.
|
|
403
|
+
|
|
404
|
+
OUTPUT:
|
|
405
|
+
|
|
406
|
+
- the displacements sequence of parked cars which corresponds
|
|
407
|
+
to the parking function and which is the same size as parking function
|
|
408
|
+
|
|
409
|
+
EXAMPLES::
|
|
410
|
+
|
|
411
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
412
|
+
sage: PF.jump_list()
|
|
413
|
+
[0, 0, 0, 0, 1, 3, 2]
|
|
414
|
+
|
|
415
|
+
::
|
|
416
|
+
|
|
417
|
+
sage: ParkingFunction([3,1,1,4]).jump_list()
|
|
418
|
+
[0, 0, 1, 0]
|
|
419
|
+
sage: ParkingFunction([4,1,1,1]).jump_list()
|
|
420
|
+
[0, 0, 1, 2]
|
|
421
|
+
sage: ParkingFunction([2,1,4,1]).jump_list()
|
|
422
|
+
[0, 0, 0, 2]
|
|
423
|
+
"""
|
|
424
|
+
pi = self.parking_permutation()
|
|
425
|
+
return [pi[i] - self[i] for i in range(len(self))]
|
|
426
|
+
|
|
427
|
+
def jump(self) -> Integer: # sum of all jumps, sum of all displacements
|
|
428
|
+
r"""
|
|
429
|
+
Return the sum of the differences between the parked and
|
|
430
|
+
preferred parking spots.
|
|
431
|
+
|
|
432
|
+
See [Shin]_ p. 18.
|
|
433
|
+
|
|
434
|
+
OUTPUT:
|
|
435
|
+
|
|
436
|
+
- the sum of the differences between the parked and preferred parking
|
|
437
|
+
spots
|
|
438
|
+
|
|
439
|
+
EXAMPLES::
|
|
440
|
+
|
|
441
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
442
|
+
sage: PF.jump()
|
|
443
|
+
6
|
|
444
|
+
|
|
445
|
+
::
|
|
446
|
+
|
|
447
|
+
sage: ParkingFunction([3,1,1,4]).jump()
|
|
448
|
+
1
|
|
449
|
+
sage: ParkingFunction([4,1,1,1]).jump()
|
|
450
|
+
3
|
|
451
|
+
sage: ParkingFunction([2,1,4,1]).jump()
|
|
452
|
+
2
|
|
453
|
+
"""
|
|
454
|
+
return sum(self.jump_list())
|
|
455
|
+
|
|
456
|
+
def lucky_cars(self): # the set of cars that can park in their preferred spots
|
|
457
|
+
r"""
|
|
458
|
+
Return the cars that can park in their preferred spots. For example,
|
|
459
|
+
``lucky_cars(PF) = [1, 2, 7]`` means that cars 1, 2 and 7 parked in
|
|
460
|
+
their preferred spots and all the other cars did not.
|
|
461
|
+
|
|
462
|
+
OUTPUT: the cars that can park in their preferred spots
|
|
463
|
+
|
|
464
|
+
EXAMPLES::
|
|
465
|
+
|
|
466
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
467
|
+
sage: PF.lucky_cars()
|
|
468
|
+
[1, 2, 3, 4]
|
|
469
|
+
|
|
470
|
+
::
|
|
471
|
+
|
|
472
|
+
sage: ParkingFunction([3,1,1,4]).lucky_cars()
|
|
473
|
+
[1, 2, 4]
|
|
474
|
+
sage: ParkingFunction([4,1,1,1]).lucky_cars()
|
|
475
|
+
[1, 2]
|
|
476
|
+
sage: ParkingFunction([2,1,4,1]).lucky_cars()
|
|
477
|
+
[1, 2, 3]
|
|
478
|
+
"""
|
|
479
|
+
w = self.jump_list()
|
|
480
|
+
return [i + 1 for i in range(len(w)) if w[i] == 0]
|
|
481
|
+
|
|
482
|
+
def luck(self) -> Integer: # the number of lucky cars
|
|
483
|
+
r"""
|
|
484
|
+
Return the number of cars that parked in their preferred parking spots
|
|
485
|
+
(see [Shin]_ p. 33).
|
|
486
|
+
|
|
487
|
+
OUTPUT: the number of cars that parked in their preferred parking spots
|
|
488
|
+
|
|
489
|
+
EXAMPLES::
|
|
490
|
+
|
|
491
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
492
|
+
sage: PF.luck()
|
|
493
|
+
4
|
|
494
|
+
|
|
495
|
+
::
|
|
496
|
+
|
|
497
|
+
sage: ParkingFunction([3,1,1,4]).luck()
|
|
498
|
+
3
|
|
499
|
+
sage: ParkingFunction([4,1,1,1]).luck()
|
|
500
|
+
2
|
|
501
|
+
sage: ParkingFunction([2,1,4,1]).luck()
|
|
502
|
+
3
|
|
503
|
+
"""
|
|
504
|
+
return len(self.lucky_cars())
|
|
505
|
+
|
|
506
|
+
def primary_dinversion_pairs(self) -> list[tuple[int, int]]:
|
|
507
|
+
r"""
|
|
508
|
+
Return the primary descent inversion pairs of a labelled Dyck path
|
|
509
|
+
corresponding to the parking function.
|
|
510
|
+
|
|
511
|
+
OUTPUT:
|
|
512
|
+
|
|
513
|
+
The pairs `(i, j)` such that `i < j`, and `i`-th area = `j`-th area,
|
|
514
|
+
and `i`-th label < `j`-th label
|
|
515
|
+
|
|
516
|
+
EXAMPLES::
|
|
517
|
+
|
|
518
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
519
|
+
sage: PF.primary_dinversion_pairs()
|
|
520
|
+
[(0, 4), (1, 5), (2, 5)]
|
|
521
|
+
|
|
522
|
+
::
|
|
523
|
+
|
|
524
|
+
sage: ParkingFunction([3,1,1,4]).primary_dinversion_pairs()
|
|
525
|
+
[(0, 3), (2, 3)]
|
|
526
|
+
sage: ParkingFunction([4,1,1,1]).primary_dinversion_pairs()
|
|
527
|
+
[]
|
|
528
|
+
sage: ParkingFunction([2,1,4,1]).primary_dinversion_pairs()
|
|
529
|
+
[(0, 3)]
|
|
530
|
+
"""
|
|
531
|
+
L = self.to_labelling_permutation()
|
|
532
|
+
D = self.to_area_sequence()
|
|
533
|
+
return [(i, j) for j in range(len(D)) for i in range(j)
|
|
534
|
+
if D[i] == D[j] and L[i] < L[j]]
|
|
535
|
+
|
|
536
|
+
def secondary_dinversion_pairs(self) -> list[tuple[int, int]]:
|
|
537
|
+
r"""
|
|
538
|
+
Return the secondary descent inversion pairs of a labelled Dyck path
|
|
539
|
+
corresponding to the parking function.
|
|
540
|
+
|
|
541
|
+
OUTPUT:
|
|
542
|
+
|
|
543
|
+
The pairs `(i, j)` such that `i < j`, and `i`-th area = `j`-th area +1,
|
|
544
|
+
and `i`-th label > `j`-th label
|
|
545
|
+
|
|
546
|
+
EXAMPLES::
|
|
547
|
+
|
|
548
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
549
|
+
sage: PF.secondary_dinversion_pairs()
|
|
550
|
+
[(1, 4), (2, 4), (3, 6)]
|
|
551
|
+
|
|
552
|
+
::
|
|
553
|
+
|
|
554
|
+
sage: ParkingFunction([3,1,1,4]).secondary_dinversion_pairs()
|
|
555
|
+
[(1, 2)]
|
|
556
|
+
sage: ParkingFunction([4,1,1,1]).secondary_dinversion_pairs()
|
|
557
|
+
[(1, 3)]
|
|
558
|
+
sage: ParkingFunction([2,1,4,1]).secondary_dinversion_pairs()
|
|
559
|
+
[(1, 3)]
|
|
560
|
+
"""
|
|
561
|
+
L = self.to_labelling_permutation()
|
|
562
|
+
D = self.to_area_sequence()
|
|
563
|
+
return [(i, j) for j in range(len(D)) for i in range(j)
|
|
564
|
+
if D[i] == D[j] + 1 and L[i] > L[j]]
|
|
565
|
+
|
|
566
|
+
def dinversion_pairs(self) -> list[tuple[int, int]]:
|
|
567
|
+
r"""
|
|
568
|
+
Return the descent inversion pairs of a labelled Dyck path
|
|
569
|
+
corresponding to the parking function.
|
|
570
|
+
|
|
571
|
+
OUTPUT: the primary and secondary diversion pairs
|
|
572
|
+
|
|
573
|
+
EXAMPLES::
|
|
574
|
+
|
|
575
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
576
|
+
sage: PF.dinversion_pairs()
|
|
577
|
+
[(0, 4), (1, 5), (2, 5), (1, 4), (2, 4), (3, 6)]
|
|
578
|
+
|
|
579
|
+
::
|
|
580
|
+
|
|
581
|
+
sage: ParkingFunction([3,1,1,4]).dinversion_pairs()
|
|
582
|
+
[(0, 3), (2, 3), (1, 2)]
|
|
583
|
+
sage: ParkingFunction([4,1,1,1]).dinversion_pairs()
|
|
584
|
+
[(1, 3)]
|
|
585
|
+
sage: ParkingFunction([2,1,4,1]).dinversion_pairs()
|
|
586
|
+
[(0, 3), (1, 3)]
|
|
587
|
+
"""
|
|
588
|
+
return self.primary_dinversion_pairs() + self.secondary_dinversion_pairs()
|
|
589
|
+
|
|
590
|
+
def dinv(self) -> int:
|
|
591
|
+
r"""
|
|
592
|
+
Return the number of inversions of a labelled Dyck path corresponding
|
|
593
|
+
to the parking function (see [Hag08]_ p. 74).
|
|
594
|
+
|
|
595
|
+
Same as the cardinality of :meth:`dinversion_pairs`.
|
|
596
|
+
|
|
597
|
+
OUTPUT: the number of dinversion pairs
|
|
598
|
+
|
|
599
|
+
EXAMPLES::
|
|
600
|
+
|
|
601
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
602
|
+
sage: PF.dinv()
|
|
603
|
+
6
|
|
604
|
+
|
|
605
|
+
::
|
|
606
|
+
|
|
607
|
+
sage: ParkingFunction([3,1,1,4]).dinv()
|
|
608
|
+
3
|
|
609
|
+
sage: ParkingFunction([4,1,1,1]).dinv()
|
|
610
|
+
1
|
|
611
|
+
sage: ParkingFunction([2,1,4,1]).dinv()
|
|
612
|
+
2
|
|
613
|
+
"""
|
|
614
|
+
return len(self.dinversion_pairs())
|
|
615
|
+
|
|
616
|
+
def area(self) -> Integer:
|
|
617
|
+
r"""
|
|
618
|
+
Return the area of the labelled Dyck path corresponding to the
|
|
619
|
+
parking function.
|
|
620
|
+
|
|
621
|
+
OUTPUT:
|
|
622
|
+
|
|
623
|
+
- the sum of squares under and over the main diagonal the Dyck Path,
|
|
624
|
+
corresponding to the parking function
|
|
625
|
+
|
|
626
|
+
EXAMPLES::
|
|
627
|
+
|
|
628
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
629
|
+
sage: PF.area()
|
|
630
|
+
6
|
|
631
|
+
|
|
632
|
+
::
|
|
633
|
+
|
|
634
|
+
sage: ParkingFunction([3,1,1,4]).area()
|
|
635
|
+
1
|
|
636
|
+
sage: ParkingFunction([4,1,1,1]).area()
|
|
637
|
+
3
|
|
638
|
+
sage: ParkingFunction([2,1,4,1]).area()
|
|
639
|
+
2
|
|
640
|
+
"""
|
|
641
|
+
return sum(self.to_area_sequence())
|
|
642
|
+
|
|
643
|
+
@combinatorial_map(name='to ides composition')
|
|
644
|
+
def ides_composition(self):
|
|
645
|
+
r"""
|
|
646
|
+
Return the
|
|
647
|
+
:meth:`~sage.combinat.permutation.Permutation.descents_composition`
|
|
648
|
+
of the inverse of the :meth:`diagonal_reading_word` of
|
|
649
|
+
corresponding parking function.
|
|
650
|
+
|
|
651
|
+
For example, ``ides_composition(PF) = [4, 2, 1]`` means that
|
|
652
|
+
the descents of the inverse of the permutation
|
|
653
|
+
:meth:`diagonal_reading_word` of the parking function with
|
|
654
|
+
word ``PF`` are at the 4th and 6th positions.
|
|
655
|
+
|
|
656
|
+
OUTPUT:
|
|
657
|
+
|
|
658
|
+
- the descents composition of the inverse of the
|
|
659
|
+
:meth:`diagonal_reading_word` of the parking function
|
|
660
|
+
|
|
661
|
+
EXAMPLES::
|
|
662
|
+
|
|
663
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
664
|
+
sage: PF.ides_composition()
|
|
665
|
+
[2, 1, 1, 2, 1]
|
|
666
|
+
|
|
667
|
+
::
|
|
668
|
+
|
|
669
|
+
sage: ParkingFunction([3,1,1,4]).ides_composition()
|
|
670
|
+
[2, 2]
|
|
671
|
+
sage: ParkingFunction([4,1,1,1]).ides_composition()
|
|
672
|
+
[2, 1, 1]
|
|
673
|
+
sage: ParkingFunction([4,3,1,1]).ides_composition()
|
|
674
|
+
[3, 1]
|
|
675
|
+
"""
|
|
676
|
+
return self.diagonal_reading_word().inverse().descents_composition()
|
|
677
|
+
|
|
678
|
+
def ides(self):
|
|
679
|
+
r"""
|
|
680
|
+
Return the :meth:`~sage.combinat.permutation.Permutation.descents`
|
|
681
|
+
sequence of the inverse of the :meth:`diagonal_reading_word`
|
|
682
|
+
of ``self``.
|
|
683
|
+
|
|
684
|
+
.. WARNING::
|
|
685
|
+
|
|
686
|
+
Here we use the standard convention that descent labels
|
|
687
|
+
start at `1`. This behaviour has been changed in
|
|
688
|
+
:issue:`20555`.
|
|
689
|
+
|
|
690
|
+
For example, ``ides(PF) = [2, 3, 4, 6]`` means that descents are at
|
|
691
|
+
the 2nd, 3rd, 4th and 6th positions in the inverse of the
|
|
692
|
+
:meth:`diagonal_reading_word` of the parking function (see [GXZ]_ p. 2).
|
|
693
|
+
|
|
694
|
+
OUTPUT:
|
|
695
|
+
|
|
696
|
+
- the descents sequence of the inverse of the
|
|
697
|
+
:meth:`diagonal_reading_word` of the parking function
|
|
698
|
+
|
|
699
|
+
EXAMPLES::
|
|
700
|
+
|
|
701
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
702
|
+
sage: PF.ides()
|
|
703
|
+
[2, 3, 4, 6]
|
|
704
|
+
|
|
705
|
+
::
|
|
706
|
+
|
|
707
|
+
sage: ParkingFunction([3,1,1,4]).ides()
|
|
708
|
+
[2]
|
|
709
|
+
sage: ParkingFunction([4,1,1,1]).ides()
|
|
710
|
+
[2, 3]
|
|
711
|
+
sage: ParkingFunction([4,3,1,1]).ides()
|
|
712
|
+
[3]
|
|
713
|
+
"""
|
|
714
|
+
return self.diagonal_reading_word().inverse().descents()
|
|
715
|
+
|
|
716
|
+
def touch_points(self):
|
|
717
|
+
r"""
|
|
718
|
+
Return the sequence of touch points which corresponds to the
|
|
719
|
+
labelled Dyck path after initial step.
|
|
720
|
+
|
|
721
|
+
For example, ``touch_points(PF) = [4, 7]`` means that after
|
|
722
|
+
the initial step, the path touches the main diagonal at points
|
|
723
|
+
`(4, 4)` and `(7, 7)`.
|
|
724
|
+
|
|
725
|
+
OUTPUT:
|
|
726
|
+
|
|
727
|
+
- the sequence of touch points after the initial step of the
|
|
728
|
+
labelled Dyck path that corresponds to the parking function
|
|
729
|
+
|
|
730
|
+
EXAMPLES::
|
|
731
|
+
|
|
732
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
733
|
+
sage: PF.touch_points()
|
|
734
|
+
[4, 7]
|
|
735
|
+
|
|
736
|
+
::
|
|
737
|
+
|
|
738
|
+
sage: ParkingFunction([3,1,1,4]).touch_points()
|
|
739
|
+
[2, 3, 4]
|
|
740
|
+
sage: ParkingFunction([4,1,1,1]).touch_points()
|
|
741
|
+
[3, 4]
|
|
742
|
+
sage: ParkingFunction([2,1,4,1]).touch_points()
|
|
743
|
+
[3, 4]
|
|
744
|
+
"""
|
|
745
|
+
return self.to_dyck_word().touch_points()
|
|
746
|
+
|
|
747
|
+
@combinatorial_map(name='to touch composition')
|
|
748
|
+
def touch_composition(self):
|
|
749
|
+
r"""
|
|
750
|
+
Return the composition of the labelled Dyck path corresponding
|
|
751
|
+
to the parking function.
|
|
752
|
+
|
|
753
|
+
For example, ``touch_composition(PF) = [4, 3]`` means that the
|
|
754
|
+
first touch is four diagonal units from the starting point,
|
|
755
|
+
and the second is three units further (see [GXZ]_ p. 2).
|
|
756
|
+
|
|
757
|
+
OUTPUT:
|
|
758
|
+
|
|
759
|
+
- the length between the corresponding touch points which
|
|
760
|
+
of the labelled Dyck path that corresponds to the parking function
|
|
761
|
+
|
|
762
|
+
EXAMPLES::
|
|
763
|
+
|
|
764
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
765
|
+
sage: PF.touch_composition()
|
|
766
|
+
[4, 3]
|
|
767
|
+
|
|
768
|
+
::
|
|
769
|
+
|
|
770
|
+
sage: ParkingFunction([3,1,1,4]).touch_composition()
|
|
771
|
+
[2, 1, 1]
|
|
772
|
+
sage: ParkingFunction([4,1,1,1]).touch_composition()
|
|
773
|
+
[3, 1]
|
|
774
|
+
sage: ParkingFunction([2,1,4,1]).touch_composition()
|
|
775
|
+
[3, 1]
|
|
776
|
+
"""
|
|
777
|
+
return self.to_dyck_word().touch_composition()
|
|
778
|
+
|
|
779
|
+
diagonal_composition = touch_composition
|
|
780
|
+
|
|
781
|
+
@combinatorial_map(name='to labelling permutation')
|
|
782
|
+
def to_labelling_permutation(self) -> Permutation:
|
|
783
|
+
r"""
|
|
784
|
+
Return the labelling of the support Dyck path of the parking function.
|
|
785
|
+
|
|
786
|
+
OUTPUT: the labelling of the Dyck path
|
|
787
|
+
|
|
788
|
+
EXAMPLES::
|
|
789
|
+
|
|
790
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
791
|
+
sage: PF.to_labelling_permutation()
|
|
792
|
+
[2, 6, 4, 5, 3, 7, 1]
|
|
793
|
+
|
|
794
|
+
::
|
|
795
|
+
|
|
796
|
+
sage: ParkingFunction([3,1,1,4]).to_labelling_permutation()
|
|
797
|
+
[2, 3, 1, 4]
|
|
798
|
+
sage: ParkingFunction([4,1,1,1]).to_labelling_permutation()
|
|
799
|
+
[2, 3, 4, 1]
|
|
800
|
+
sage: ParkingFunction([2,1,4,1]).to_labelling_permutation()
|
|
801
|
+
[2, 4, 1, 3]
|
|
802
|
+
"""
|
|
803
|
+
from sage.combinat.words.word import Word
|
|
804
|
+
return Word(self).standard_permutation().inverse()
|
|
805
|
+
|
|
806
|
+
def to_area_sequence(self) -> list:
|
|
807
|
+
r"""
|
|
808
|
+
Return the area sequence of the support Dyck path of the
|
|
809
|
+
parking function.
|
|
810
|
+
|
|
811
|
+
OUTPUT: the area sequence of the Dyck path
|
|
812
|
+
|
|
813
|
+
EXAMPLES::
|
|
814
|
+
|
|
815
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
816
|
+
sage: PF.to_area_sequence()
|
|
817
|
+
[0, 1, 1, 2, 0, 1, 1]
|
|
818
|
+
|
|
819
|
+
::
|
|
820
|
+
|
|
821
|
+
sage: ParkingFunction([3,1,1,4]).to_area_sequence()
|
|
822
|
+
[0, 1, 0, 0]
|
|
823
|
+
sage: ParkingFunction([4,1,1,1]).to_area_sequence()
|
|
824
|
+
[0, 1, 2, 0]
|
|
825
|
+
sage: ParkingFunction([2,1,4,1]).to_area_sequence()
|
|
826
|
+
[0, 1, 1, 0]
|
|
827
|
+
"""
|
|
828
|
+
w = sorted(self)
|
|
829
|
+
return [i + 1 - wi for i, wi in enumerate(w)]
|
|
830
|
+
|
|
831
|
+
def to_labelling_area_sequence_pair(self):
|
|
832
|
+
r"""
|
|
833
|
+
Return a pair consisting of a labelling and an area sequence
|
|
834
|
+
of a Dyck path which corresponds to the given parking
|
|
835
|
+
function.
|
|
836
|
+
|
|
837
|
+
OUTPUT:
|
|
838
|
+
|
|
839
|
+
- returns a pair ``(L, D)`` where ``L`` is a labelling and ``D`` is the
|
|
840
|
+
area sequence of the underlying Dyck path
|
|
841
|
+
|
|
842
|
+
EXAMPLES::
|
|
843
|
+
|
|
844
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
845
|
+
sage: PF.to_labelling_area_sequence_pair()
|
|
846
|
+
([2, 6, 4, 5, 3, 7, 1], [0, 1, 1, 2, 0, 1, 1])
|
|
847
|
+
|
|
848
|
+
::
|
|
849
|
+
|
|
850
|
+
sage: ParkingFunction([1, 1, 1]).to_labelling_area_sequence_pair()
|
|
851
|
+
([1, 2, 3], [0, 1, 2])
|
|
852
|
+
sage: ParkingFunction([1, 2, 3]).to_labelling_area_sequence_pair()
|
|
853
|
+
([1, 2, 3], [0, 0, 0])
|
|
854
|
+
sage: ParkingFunction([1, 1, 2]).to_labelling_area_sequence_pair()
|
|
855
|
+
([1, 2, 3], [0, 1, 1])
|
|
856
|
+
sage: ParkingFunction([1, 1, 3, 1]).to_labelling_area_sequence_pair()
|
|
857
|
+
([1, 2, 4, 3], [0, 1, 2, 1])
|
|
858
|
+
"""
|
|
859
|
+
return (self.to_labelling_permutation(), self.to_area_sequence())
|
|
860
|
+
|
|
861
|
+
@combinatorial_map(name='to dyck word')
|
|
862
|
+
def to_dyck_word(self) -> DyckWord:
|
|
863
|
+
r"""
|
|
864
|
+
Return the support Dyck word of the parking function.
|
|
865
|
+
|
|
866
|
+
OUTPUT: the Dyck word of the corresponding parking function
|
|
867
|
+
|
|
868
|
+
.. SEEALSO:: :meth:`DyckWord`
|
|
869
|
+
|
|
870
|
+
EXAMPLES::
|
|
871
|
+
|
|
872
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
873
|
+
sage: PF.to_dyck_word()
|
|
874
|
+
[1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0]
|
|
875
|
+
|
|
876
|
+
::
|
|
877
|
+
|
|
878
|
+
sage: ParkingFunction([3,1,1,4]).to_dyck_word()
|
|
879
|
+
[1, 1, 0, 0, 1, 0, 1, 0]
|
|
880
|
+
sage: ParkingFunction([4,1,1,1]).to_dyck_word()
|
|
881
|
+
[1, 1, 1, 0, 0, 0, 1, 0]
|
|
882
|
+
sage: ParkingFunction([2,1,4,1]).to_dyck_word()
|
|
883
|
+
[1, 1, 0, 1, 0, 0, 1, 0]
|
|
884
|
+
"""
|
|
885
|
+
return DyckWord(area_sequence=self.to_area_sequence()) # type:ignore
|
|
886
|
+
|
|
887
|
+
def to_labelled_dyck_word(self):
|
|
888
|
+
r"""
|
|
889
|
+
Return the labelled Dyck word corresponding to the parking function.
|
|
890
|
+
|
|
891
|
+
This is a representation of the parking function as a list
|
|
892
|
+
where the entries of 1 in the Dyck word are replaced with the
|
|
893
|
+
corresponding label.
|
|
894
|
+
|
|
895
|
+
OUTPUT:
|
|
896
|
+
|
|
897
|
+
- the labelled Dyck word of the corresponding parking function
|
|
898
|
+
which is twice the size of parking function word
|
|
899
|
+
|
|
900
|
+
EXAMPLES::
|
|
901
|
+
|
|
902
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
903
|
+
sage: PF.to_labelled_dyck_word()
|
|
904
|
+
[2, 6, 0, 4, 5, 0, 0, 0, 3, 7, 0, 1, 0, 0]
|
|
905
|
+
|
|
906
|
+
::
|
|
907
|
+
|
|
908
|
+
sage: ParkingFunction([3,1,1,4]).to_labelled_dyck_word()
|
|
909
|
+
[2, 3, 0, 0, 1, 0, 4, 0]
|
|
910
|
+
sage: ParkingFunction([4,1,1,1]).to_labelled_dyck_word()
|
|
911
|
+
[2, 3, 4, 0, 0, 0, 1, 0]
|
|
912
|
+
sage: ParkingFunction([2,1,4,1]).to_labelled_dyck_word()
|
|
913
|
+
[2, 4, 0, 1, 0, 0, 3, 0]
|
|
914
|
+
"""
|
|
915
|
+
dw = self.to_dyck_word()
|
|
916
|
+
out = list(self.to_labelling_permutation())
|
|
917
|
+
for i in range(2 * len(out)):
|
|
918
|
+
if dw[i] == 0:
|
|
919
|
+
out.insert(i, 0)
|
|
920
|
+
return out
|
|
921
|
+
|
|
922
|
+
def to_labelling_dyck_word_pair(self) -> tuple[Permutation, DyckWord]:
|
|
923
|
+
r"""
|
|
924
|
+
Return the pair ``(L, D)`` where ``L`` is a labelling and
|
|
925
|
+
``D`` is the Dyck word of the parking function.
|
|
926
|
+
|
|
927
|
+
OUTPUT:
|
|
928
|
+
|
|
929
|
+
- the pair ``(L, D)``, where ``L`` is the labelling and ``D`` is
|
|
930
|
+
the Dyck word of the parking function
|
|
931
|
+
|
|
932
|
+
.. SEEALSO:: :meth:`DyckWord`
|
|
933
|
+
|
|
934
|
+
EXAMPLES::
|
|
935
|
+
|
|
936
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
937
|
+
sage: PF.to_labelling_dyck_word_pair()
|
|
938
|
+
([2, 6, 4, 5, 3, 7, 1], [1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0])
|
|
939
|
+
|
|
940
|
+
::
|
|
941
|
+
|
|
942
|
+
sage: ParkingFunction([3,1,1,4]).to_labelling_dyck_word_pair()
|
|
943
|
+
([2, 3, 1, 4], [1, 1, 0, 0, 1, 0, 1, 0])
|
|
944
|
+
sage: ParkingFunction([4,1,1,1]).to_labelling_dyck_word_pair()
|
|
945
|
+
([2, 3, 4, 1], [1, 1, 1, 0, 0, 0, 1, 0])
|
|
946
|
+
sage: ParkingFunction([2,1,4,1]).to_labelling_dyck_word_pair()
|
|
947
|
+
([2, 4, 1, 3], [1, 1, 0, 1, 0, 0, 1, 0])
|
|
948
|
+
"""
|
|
949
|
+
return (self.to_labelling_permutation(), self.to_dyck_word())
|
|
950
|
+
|
|
951
|
+
@combinatorial_map(name='to non-decreasing parking function')
|
|
952
|
+
def to_NonDecreasingParkingFunction(self) -> PF:
|
|
953
|
+
r"""
|
|
954
|
+
Return the non-decreasing parking function which underlies the
|
|
955
|
+
parking function.
|
|
956
|
+
|
|
957
|
+
OUTPUT: a sorted parking function
|
|
958
|
+
|
|
959
|
+
.. SEEALSO:: :meth:`NonDecreasingParkingFunction`
|
|
960
|
+
|
|
961
|
+
EXAMPLES::
|
|
962
|
+
|
|
963
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
964
|
+
sage: PF.to_NonDecreasingParkingFunction()
|
|
965
|
+
[1, 1, 2, 2, 5, 5, 6]
|
|
966
|
+
|
|
967
|
+
::
|
|
968
|
+
|
|
969
|
+
sage: ParkingFunction([3,1,1,4]).to_NonDecreasingParkingFunction()
|
|
970
|
+
[1, 1, 3, 4]
|
|
971
|
+
sage: ParkingFunction([4,1,1,1]).to_NonDecreasingParkingFunction()
|
|
972
|
+
[1, 1, 1, 4]
|
|
973
|
+
sage: ParkingFunction([2,1,4,1]).to_NonDecreasingParkingFunction()
|
|
974
|
+
[1, 1, 2, 4]
|
|
975
|
+
sage: ParkingFunction([4,1,2,1]).to_NonDecreasingParkingFunction()
|
|
976
|
+
[1, 1, 2, 4]
|
|
977
|
+
"""
|
|
978
|
+
return ParkingFunction(sorted(self)) # type:ignore
|
|
979
|
+
|
|
980
|
+
def characteristic_quasisymmetric_function(self, q=None,
|
|
981
|
+
R=QQ['q', 't'].fraction_field()):
|
|
982
|
+
r"""
|
|
983
|
+
Return the characteristic quasisymmetric function of ``self``.
|
|
984
|
+
|
|
985
|
+
The characteristic function of the Parking Function is the sum
|
|
986
|
+
over all permutation labellings of the Dyck path `q^{dinv(PF)}
|
|
987
|
+
F_{ides(PF)}` where `ides(PF)` (:meth:`ides_composition`) is
|
|
988
|
+
the descent composition of diagonal reading word of the
|
|
989
|
+
parking function.
|
|
990
|
+
|
|
991
|
+
INPUT:
|
|
992
|
+
|
|
993
|
+
- ``q`` -- (default: ``q = R('q')``) a parameter for the
|
|
994
|
+
generating function power
|
|
995
|
+
|
|
996
|
+
- ``R`` -- (default: ``R = QQ['q','t'].fraction_field()``) the
|
|
997
|
+
base ring to do the calculations over
|
|
998
|
+
|
|
999
|
+
OUTPUT: an element of the quasisymmetric functions over the ring ``R``
|
|
1000
|
+
|
|
1001
|
+
EXAMPLES::
|
|
1002
|
+
|
|
1003
|
+
sage: # needs sage.modules
|
|
1004
|
+
sage: R = QQ['q','t'].fraction_field()
|
|
1005
|
+
sage: (q,t) = R.gens()
|
|
1006
|
+
sage: cqf = sum(t**PF.area() * PF.characteristic_quasisymmetric_function()
|
|
1007
|
+
....: for PF in ParkingFunctions(3)); cqf
|
|
1008
|
+
(q^3+q^2*t+q*t^2+t^3+q*t)*F[1, 1, 1] + (q^2+q*t+t^2+q+t)*F[1, 2]
|
|
1009
|
+
+ (q^2+q*t+t^2+q+t)*F[2, 1] + F[3]
|
|
1010
|
+
sage: s = SymmetricFunctions(R).s()
|
|
1011
|
+
sage: s(cqf.to_symmetric_function())
|
|
1012
|
+
(q^3+q^2*t+q*t^2+t^3+q*t)*s[1, 1, 1] + (q^2+q*t+t^2+q+t)*s[2, 1] + s[3]
|
|
1013
|
+
sage: s(cqf.to_symmetric_function()).nabla(power=-1)
|
|
1014
|
+
s[1, 1, 1]
|
|
1015
|
+
|
|
1016
|
+
::
|
|
1017
|
+
|
|
1018
|
+
sage: p = ParkingFunction([3, 1, 2])
|
|
1019
|
+
sage: p.characteristic_quasisymmetric_function() # needs sage.modules
|
|
1020
|
+
q*F[2, 1]
|
|
1021
|
+
sage: pf = ParkingFunction([1,2,7,2,1,2,3,2,1])
|
|
1022
|
+
sage: pf.characteristic_quasisymmetric_function() # needs sage.modules
|
|
1023
|
+
q^2*F[1, 1, 1, 2, 1, 3]
|
|
1024
|
+
"""
|
|
1025
|
+
from sage.combinat.ncsf_qsym.qsym import QuasiSymmetricFunctions
|
|
1026
|
+
if q is None:
|
|
1027
|
+
q = R('q')
|
|
1028
|
+
else:
|
|
1029
|
+
if q not in R:
|
|
1030
|
+
raise ValueError("q=%s must be an element of the base ring %s" % (q, R))
|
|
1031
|
+
F = QuasiSymmetricFunctions(R).Fundamental()
|
|
1032
|
+
return q**self.dinv() * F(self.ides_composition())
|
|
1033
|
+
|
|
1034
|
+
def pretty_print(self, underpath=True):
|
|
1035
|
+
r"""
|
|
1036
|
+
Displays a parking function as a lattice path consisting of a
|
|
1037
|
+
Dyck path and a labelling with the labels displayed along the
|
|
1038
|
+
edges of the Dyck path.
|
|
1039
|
+
|
|
1040
|
+
INPUT:
|
|
1041
|
+
|
|
1042
|
+
- ``underpath`` -- if the length of the parking function is
|
|
1043
|
+
less than or equal to 9 then display the labels under the
|
|
1044
|
+
path if ``underpath`` is ``True`` otherwise display them to the
|
|
1045
|
+
right of the path (default: ``True``)
|
|
1046
|
+
|
|
1047
|
+
EXAMPLES::
|
|
1048
|
+
|
|
1049
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
1050
|
+
sage: PF.pretty_print()
|
|
1051
|
+
___
|
|
1052
|
+
_|1x
|
|
1053
|
+
|7x .
|
|
1054
|
+
_____|3 . .
|
|
1055
|
+
|5x x . . .
|
|
1056
|
+
_|4x . . . .
|
|
1057
|
+
|6x . . . . .
|
|
1058
|
+
|2 . . . . . .
|
|
1059
|
+
|
|
1060
|
+
sage: PF = ParkingFunction([6, 1, 5, 2, 2, 1, 5])
|
|
1061
|
+
sage: PF.pretty_print(underpath = false)
|
|
1062
|
+
___
|
|
1063
|
+
_| x 1
|
|
1064
|
+
| x . 7
|
|
1065
|
+
_____| . . 3
|
|
1066
|
+
| x x . . . 5
|
|
1067
|
+
_| x . . . . 4
|
|
1068
|
+
| x . . . . . 6
|
|
1069
|
+
| . . . . . . 2
|
|
1070
|
+
|
|
1071
|
+
::
|
|
1072
|
+
|
|
1073
|
+
sage: ParkingFunction([3, 1, 1, 4]).pretty_print()
|
|
1074
|
+
_
|
|
1075
|
+
_|4
|
|
1076
|
+
___|1 .
|
|
1077
|
+
|3x . .
|
|
1078
|
+
|2 . . .
|
|
1079
|
+
|
|
1080
|
+
sage: ParkingFunction([1,1,1]).pretty_print()
|
|
1081
|
+
_____
|
|
1082
|
+
|3x x
|
|
1083
|
+
|2x .
|
|
1084
|
+
|1 . .
|
|
1085
|
+
|
|
1086
|
+
sage: ParkingFunction([4,1,1,1]).pretty_print()
|
|
1087
|
+
_
|
|
1088
|
+
_____|1
|
|
1089
|
+
|4x x .
|
|
1090
|
+
|3x . .
|
|
1091
|
+
|2 . . .
|
|
1092
|
+
|
|
1093
|
+
sage: ParkingFunction([2,1,4,1]).pretty_print()
|
|
1094
|
+
_
|
|
1095
|
+
___|3
|
|
1096
|
+
_|1x .
|
|
1097
|
+
|4x . .
|
|
1098
|
+
|2 . . .
|
|
1099
|
+
|
|
1100
|
+
sage: ParkingFunction([2,1,4,1]).pretty_print(underpath = false)
|
|
1101
|
+
_
|
|
1102
|
+
___| 3
|
|
1103
|
+
_| x . 1
|
|
1104
|
+
| x . . 4
|
|
1105
|
+
| . . . 2
|
|
1106
|
+
|
|
1107
|
+
sage: pf = ParkingFunction([1,2,3,7,3,2,1,2,3,2,1])
|
|
1108
|
+
sage: pf.pretty_print()
|
|
1109
|
+
_________
|
|
1110
|
+
_______| x x x x 4
|
|
1111
|
+
| x x x x x x x . 9
|
|
1112
|
+
| x x x x x x . . 5
|
|
1113
|
+
_| x x x x x . . . 3
|
|
1114
|
+
| x x x x x . . . . 10
|
|
1115
|
+
| x x x x . . . . . 8
|
|
1116
|
+
| x x x . . . . . . 6
|
|
1117
|
+
_| x x . . . . . . . 2
|
|
1118
|
+
| x x . . . . . . . . 11
|
|
1119
|
+
| x . . . . . . . . . 7
|
|
1120
|
+
| . . . . . . . . . . 1
|
|
1121
|
+
"""
|
|
1122
|
+
L = self.to_labelling_permutation()
|
|
1123
|
+
dw = self.to_dyck_word()
|
|
1124
|
+
if len(L) <= 9:
|
|
1125
|
+
dw.pretty_print(labelling=L, underpath=underpath)
|
|
1126
|
+
else:
|
|
1127
|
+
dw.pretty_print(labelling=L, underpath=False)
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
PF = ParkingFunction
|
|
1131
|
+
|
|
1132
|
+
# *****************************************************************************
|
|
1133
|
+
# CONSTRUCTIONS
|
|
1134
|
+
# *****************************************************************************
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
def from_labelling_and_area_sequence(L, D) -> PF:
|
|
1138
|
+
r"""
|
|
1139
|
+
Return the parking function corresponding to the labelling area
|
|
1140
|
+
sequence pair.
|
|
1141
|
+
|
|
1142
|
+
INPUT:
|
|
1143
|
+
|
|
1144
|
+
- ``L`` -- a labelling permutation
|
|
1145
|
+
|
|
1146
|
+
- ``D`` -- an area sequence for a Dyck word
|
|
1147
|
+
|
|
1148
|
+
OUTPUT:
|
|
1149
|
+
|
|
1150
|
+
- the parking function corresponding the labelling permutation ``L``
|
|
1151
|
+
and ``D`` an area sequence of the corresponding Dyck path
|
|
1152
|
+
|
|
1153
|
+
EXAMPLES::
|
|
1154
|
+
|
|
1155
|
+
sage: from sage.combinat.parking_functions import from_labelling_and_area_sequence
|
|
1156
|
+
sage: from_labelling_and_area_sequence([2, 6, 4, 5, 3, 7, 1], [0, 1, 1, 2, 0, 1, 1])
|
|
1157
|
+
[6, 1, 5, 2, 2, 1, 5]
|
|
1158
|
+
|
|
1159
|
+
::
|
|
1160
|
+
|
|
1161
|
+
sage: from_labelling_and_area_sequence([1, 2, 3], [0, 1, 2])
|
|
1162
|
+
[1, 1, 1]
|
|
1163
|
+
sage: from_labelling_and_area_sequence([1, 2, 3], [0, 0, 0])
|
|
1164
|
+
[1, 2, 3]
|
|
1165
|
+
sage: from_labelling_and_area_sequence([1, 2, 3], [0, 1, 1])
|
|
1166
|
+
[1, 1, 2]
|
|
1167
|
+
sage: from_labelling_and_area_sequence([1, 2, 4, 3], [0, 1, 2, 1])
|
|
1168
|
+
[1, 1, 3, 1]
|
|
1169
|
+
|
|
1170
|
+
TESTS::
|
|
1171
|
+
|
|
1172
|
+
sage: PF = from_labelling_and_area_sequence([1, 2, 4, 3], [0, 1, 2, 1])
|
|
1173
|
+
sage: isinstance(PF, ParkingFunctions().element_class)
|
|
1174
|
+
True
|
|
1175
|
+
"""
|
|
1176
|
+
PF = ParkingFunctions_all()
|
|
1177
|
+
return PF.element_class(PF,
|
|
1178
|
+
[L.index(i) + 1 - D[L.index(i)]
|
|
1179
|
+
for i in range(1, len(L) + 1)])
|
|
1180
|
+
|
|
1181
|
+
|
|
1182
|
+
def from_labelled_dyck_word(LDW) -> PF:
|
|
1183
|
+
r"""
|
|
1184
|
+
Return the parking function corresponding to the labelled Dyck word.
|
|
1185
|
+
|
|
1186
|
+
INPUT:
|
|
1187
|
+
|
|
1188
|
+
- ``LDW`` -- labelled Dyck word
|
|
1189
|
+
|
|
1190
|
+
OUTPUT:
|
|
1191
|
+
|
|
1192
|
+
- the parking function corresponding to the labelled Dyck
|
|
1193
|
+
word that is half the size of ``LDW``
|
|
1194
|
+
|
|
1195
|
+
EXAMPLES::
|
|
1196
|
+
|
|
1197
|
+
sage: from sage.combinat.parking_functions import from_labelled_dyck_word
|
|
1198
|
+
sage: LDW = [2, 6, 0, 4, 5, 0, 0, 0, 3, 7, 0, 1, 0, 0]
|
|
1199
|
+
sage: from_labelled_dyck_word(LDW)
|
|
1200
|
+
[6, 1, 5, 2, 2, 1, 5]
|
|
1201
|
+
|
|
1202
|
+
::
|
|
1203
|
+
|
|
1204
|
+
sage: from_labelled_dyck_word([2, 3, 0, 0, 1, 0, 4, 0])
|
|
1205
|
+
[3, 1, 1, 4]
|
|
1206
|
+
sage: from_labelled_dyck_word([2, 3, 4, 0, 0, 0, 1, 0])
|
|
1207
|
+
[4, 1, 1, 1]
|
|
1208
|
+
sage: from_labelled_dyck_word([2, 4, 0, 1, 0, 0, 3, 0])
|
|
1209
|
+
[2, 1, 4, 1]
|
|
1210
|
+
"""
|
|
1211
|
+
L = [ell for ell in LDW if ell != 0]
|
|
1212
|
+
D = DyckWord([Integer(not x.is_zero()) for x in LDW]) # type:ignore
|
|
1213
|
+
return from_labelling_and_area_sequence(L, D.to_area_sequence())
|
|
1214
|
+
|
|
1215
|
+
|
|
1216
|
+
class ParkingFunctions(UniqueRepresentation, Parent):
|
|
1217
|
+
r"""
|
|
1218
|
+
Return the combinatorial class of Parking Functions.
|
|
1219
|
+
|
|
1220
|
+
A *parking function* of size `n` is a sequence `(a_1, \ldots,a_n)`
|
|
1221
|
+
of positive integers such that if `b_1 \leq b_2 \leq \cdots \leq b_n` is
|
|
1222
|
+
the increasing rearrangement of `a_1, \ldots, a_n`, then `b_i \leq i`.
|
|
1223
|
+
|
|
1224
|
+
A *parking function* of size `n` is a pair `(L, D)` of two sequences
|
|
1225
|
+
`L` and `D` where `L` is a permutation and `D` is an area sequence
|
|
1226
|
+
of a Dyck Path of size n such that `D[i] \geq 0`, `D[i+1] \leq D[i]+1`
|
|
1227
|
+
and if `D[i+1] = D[i]+1` then `L[i+1] > L[i]`.
|
|
1228
|
+
|
|
1229
|
+
The number of parking functions of size `n` is equal to the number
|
|
1230
|
+
of rooted forests on `n` vertices and is equal to `(n+1)^{n-1}`.
|
|
1231
|
+
|
|
1232
|
+
EXAMPLES:
|
|
1233
|
+
|
|
1234
|
+
Here are all parking functions of size 3::
|
|
1235
|
+
|
|
1236
|
+
sage: from sage.combinat.parking_functions import ParkingFunctions
|
|
1237
|
+
sage: ParkingFunctions(3).list()
|
|
1238
|
+
[[1, 1, 1], [1, 1, 2], [1, 2, 1], [2, 1, 1], [1, 1, 3], [1, 3, 1],
|
|
1239
|
+
[3, 1, 1], [1, 2, 2], [2, 1, 2], [2, 2, 1], [1, 2, 3], [1, 3, 2],
|
|
1240
|
+
[2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
|
|
1241
|
+
|
|
1242
|
+
If no size is specified, then ParkingFunctions returns the
|
|
1243
|
+
combinatorial class of all parking functions. ::
|
|
1244
|
+
|
|
1245
|
+
sage: PF = ParkingFunctions(); PF
|
|
1246
|
+
Parking functions
|
|
1247
|
+
sage: [] in PF
|
|
1248
|
+
True
|
|
1249
|
+
sage: [1] in PF
|
|
1250
|
+
True
|
|
1251
|
+
sage: [2] in PF
|
|
1252
|
+
False
|
|
1253
|
+
sage: [1,3,1] in PF
|
|
1254
|
+
True
|
|
1255
|
+
sage: [1,4,1] in PF
|
|
1256
|
+
False
|
|
1257
|
+
|
|
1258
|
+
If the size `n` is specified, then ParkingFunctions returns
|
|
1259
|
+
the combinatorial class of all parking functions of size `n`.
|
|
1260
|
+
|
|
1261
|
+
::
|
|
1262
|
+
|
|
1263
|
+
sage: PF = ParkingFunctions(0)
|
|
1264
|
+
sage: PF.list()
|
|
1265
|
+
[[]]
|
|
1266
|
+
sage: PF = ParkingFunctions(1)
|
|
1267
|
+
sage: PF.list()
|
|
1268
|
+
[[1]]
|
|
1269
|
+
sage: PF = ParkingFunctions(3)
|
|
1270
|
+
sage: PF.list()
|
|
1271
|
+
[[1, 1, 1], [1, 1, 2], [1, 2, 1], [2, 1, 1], [1, 1, 3],
|
|
1272
|
+
[1, 3, 1], [3, 1, 1], [1, 2, 2], [2, 1, 2], [2, 2, 1],
|
|
1273
|
+
[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
|
|
1274
|
+
|
|
1275
|
+
::
|
|
1276
|
+
|
|
1277
|
+
sage: PF3 = ParkingFunctions(3); PF3
|
|
1278
|
+
Parking functions of size 3
|
|
1279
|
+
sage: [] in PF3
|
|
1280
|
+
False
|
|
1281
|
+
sage: [1] in PF3
|
|
1282
|
+
False
|
|
1283
|
+
sage: [1,3,1] in PF3
|
|
1284
|
+
True
|
|
1285
|
+
sage: [1,4,1] in PF3
|
|
1286
|
+
False
|
|
1287
|
+
|
|
1288
|
+
TESTS::
|
|
1289
|
+
|
|
1290
|
+
sage: PF = ParkingFunctions(5)
|
|
1291
|
+
sage: TestSuite(PF).run()
|
|
1292
|
+
sage: len(PF.list()) == PF.cardinality()
|
|
1293
|
+
True
|
|
1294
|
+
"""
|
|
1295
|
+
@staticmethod
|
|
1296
|
+
def __classcall_private__(cls, n=None):
|
|
1297
|
+
"""
|
|
1298
|
+
Return the correct parent based on input.
|
|
1299
|
+
|
|
1300
|
+
TESTS::
|
|
1301
|
+
|
|
1302
|
+
sage: type(ParkingFunctions(5))
|
|
1303
|
+
<class 'sage.combinat.parking_functions.ParkingFunctions_n_with_category'>
|
|
1304
|
+
sage: type(ParkingFunctions())
|
|
1305
|
+
<class 'sage.combinat.parking_functions.ParkingFunctions_all_with_category'>
|
|
1306
|
+
"""
|
|
1307
|
+
if n is None:
|
|
1308
|
+
return ParkingFunctions_all()
|
|
1309
|
+
|
|
1310
|
+
if not isinstance(n, (Integer, int)) or n < 0:
|
|
1311
|
+
raise ValueError("%s is not a nonnegative integer" % n)
|
|
1312
|
+
return ParkingFunctions_n(n)
|
|
1313
|
+
|
|
1314
|
+
|
|
1315
|
+
class ParkingFunctions_all(ParkingFunctions):
|
|
1316
|
+
def __init__(self):
|
|
1317
|
+
"""
|
|
1318
|
+
TESTS::
|
|
1319
|
+
|
|
1320
|
+
sage: PF = ParkingFunctions()
|
|
1321
|
+
sage: TestSuite(PF).run()
|
|
1322
|
+
"""
|
|
1323
|
+
cat = InfiniteEnumeratedSets() & SetsWithGrading()
|
|
1324
|
+
Parent.__init__(self, category=cat)
|
|
1325
|
+
|
|
1326
|
+
Element = ParkingFunction
|
|
1327
|
+
|
|
1328
|
+
def _repr_(self) -> str:
|
|
1329
|
+
"""
|
|
1330
|
+
TESTS::
|
|
1331
|
+
|
|
1332
|
+
sage: repr(ParkingFunctions())
|
|
1333
|
+
'Parking functions'
|
|
1334
|
+
"""
|
|
1335
|
+
return "Parking functions"
|
|
1336
|
+
|
|
1337
|
+
def __contains__(self, x) -> bool:
|
|
1338
|
+
"""
|
|
1339
|
+
TESTS::
|
|
1340
|
+
|
|
1341
|
+
sage: [] in ParkingFunctions()
|
|
1342
|
+
True
|
|
1343
|
+
sage: [1] in ParkingFunctions()
|
|
1344
|
+
True
|
|
1345
|
+
sage: [2] in ParkingFunctions()
|
|
1346
|
+
False
|
|
1347
|
+
sage: [1,3,1] in ParkingFunctions()
|
|
1348
|
+
True
|
|
1349
|
+
sage: [1,4,1] in ParkingFunctions()
|
|
1350
|
+
False
|
|
1351
|
+
"""
|
|
1352
|
+
if isinstance(x, ParkingFunction):
|
|
1353
|
+
return True
|
|
1354
|
+
return is_a(x)
|
|
1355
|
+
|
|
1356
|
+
def graded_component(self, n):
|
|
1357
|
+
"""
|
|
1358
|
+
Return the graded component.
|
|
1359
|
+
|
|
1360
|
+
EXAMPLES::
|
|
1361
|
+
|
|
1362
|
+
sage: PF = ParkingFunctions()
|
|
1363
|
+
sage: PF.graded_component(4) == ParkingFunctions(4)
|
|
1364
|
+
True
|
|
1365
|
+
sage: it = iter(ParkingFunctions()) # indirect doctest
|
|
1366
|
+
sage: [next(it) for i in range(8)]
|
|
1367
|
+
[[], [1], [1, 1], [1, 2], [2, 1], [1, 1, 1], [1, 1, 2], [1, 2, 1]]
|
|
1368
|
+
"""
|
|
1369
|
+
return ParkingFunctions_n(n)
|
|
1370
|
+
|
|
1371
|
+
def __iter__(self) -> Iterator:
|
|
1372
|
+
"""
|
|
1373
|
+
Return an iterator.
|
|
1374
|
+
|
|
1375
|
+
TESTS::
|
|
1376
|
+
|
|
1377
|
+
sage: it = iter(ParkingFunctions()) # indirect doctest
|
|
1378
|
+
sage: [next(it) for i in range(8)]
|
|
1379
|
+
[[], [1], [1, 1], [1, 2], [2, 1], [1, 1, 1], [1, 1, 2], [1, 2, 1]]
|
|
1380
|
+
"""
|
|
1381
|
+
n = 0
|
|
1382
|
+
while True:
|
|
1383
|
+
for pf in ParkingFunctions_n(n):
|
|
1384
|
+
yield self.element_class(self, list(pf))
|
|
1385
|
+
n += 1
|
|
1386
|
+
|
|
1387
|
+
def _coerce_map_from_(self, S):
|
|
1388
|
+
"""
|
|
1389
|
+
Coercion from the homogeneous component to the graded set.
|
|
1390
|
+
|
|
1391
|
+
EXAMPLES::
|
|
1392
|
+
|
|
1393
|
+
sage: PF = ParkingFunctions()
|
|
1394
|
+
sage: PF3 = ParkingFunctions(3)
|
|
1395
|
+
sage: x = PF([1,3,2])
|
|
1396
|
+
sage: y = PF3([1,3,2])
|
|
1397
|
+
sage: PF(y).parent()
|
|
1398
|
+
Parking functions
|
|
1399
|
+
sage: x == y
|
|
1400
|
+
True
|
|
1401
|
+
"""
|
|
1402
|
+
if isinstance(S, ParkingFunctions_n):
|
|
1403
|
+
return True
|
|
1404
|
+
return False
|
|
1405
|
+
|
|
1406
|
+
|
|
1407
|
+
class ParkingFunctions_n(ParkingFunctions):
|
|
1408
|
+
r"""
|
|
1409
|
+
The combinatorial class of parking functions of size `n`.
|
|
1410
|
+
|
|
1411
|
+
A *parking function* of size `n` is a sequence `(a_1, \ldots,a_n)`
|
|
1412
|
+
of positive integers such that if `b_1 \leq b_2 \leq \cdots \leq b_n` is
|
|
1413
|
+
the increasing rearrangement of `a_1, \ldots, a_n`, then `b_i \leq i`.
|
|
1414
|
+
|
|
1415
|
+
A *parking function* of size `n` is a pair `(L, D)` of two sequences
|
|
1416
|
+
`L` and `D` where `L` is a permutation and `D` is an area sequence
|
|
1417
|
+
of a Dyck Path of size `n` such that `D[i] \geq 0`, `D[i+1] \leq D[i]+1`
|
|
1418
|
+
and if `D[i+1] = D[i]+1` then `L[i+1] > L[i]`.
|
|
1419
|
+
|
|
1420
|
+
The number of parking functions of size `n` is equal to the number
|
|
1421
|
+
of rooted forests on `n` vertices and is equal to `(n+1)^{n-1}`.
|
|
1422
|
+
|
|
1423
|
+
EXAMPLES::
|
|
1424
|
+
|
|
1425
|
+
sage: PF = ParkingFunctions(3)
|
|
1426
|
+
sage: PF.list()
|
|
1427
|
+
[[1, 1, 1], [1, 1, 2], [1, 2, 1], [2, 1, 1], [1, 1, 3],
|
|
1428
|
+
[1, 3, 1], [3, 1, 1], [1, 2, 2], [2, 1, 2], [2, 2, 1],
|
|
1429
|
+
[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
|
|
1430
|
+
|
|
1431
|
+
sage: [ParkingFunctions(i).cardinality() for i in range(6)]
|
|
1432
|
+
[1, 1, 3, 16, 125, 1296]
|
|
1433
|
+
|
|
1434
|
+
.. WARNING::
|
|
1435
|
+
|
|
1436
|
+
The precise order in which the parking function are generated or
|
|
1437
|
+
listed is not fixed, and may change in the future.
|
|
1438
|
+
|
|
1439
|
+
TESTS:
|
|
1440
|
+
|
|
1441
|
+
Check that :issue:`15216` is fixed::
|
|
1442
|
+
|
|
1443
|
+
sage: PF = ParkingFunctions()
|
|
1444
|
+
sage: PF3 = ParkingFunctions(3)
|
|
1445
|
+
sage: [1,1,1] in PF3
|
|
1446
|
+
True
|
|
1447
|
+
sage: PF3([1,1,1]) in PF3
|
|
1448
|
+
True
|
|
1449
|
+
sage: PF3([1,1,1]) in PF
|
|
1450
|
+
True
|
|
1451
|
+
sage: PF([1,1,1]) in PF
|
|
1452
|
+
True
|
|
1453
|
+
sage: PF3(PF3([1,1,1]))
|
|
1454
|
+
[1, 1, 1]
|
|
1455
|
+
"""
|
|
1456
|
+
|
|
1457
|
+
def __init__(self, n):
|
|
1458
|
+
"""
|
|
1459
|
+
TESTS::
|
|
1460
|
+
|
|
1461
|
+
sage: PF = ParkingFunctions(3)
|
|
1462
|
+
sage: TestSuite(PF).run()
|
|
1463
|
+
"""
|
|
1464
|
+
self.n = n
|
|
1465
|
+
Parent.__init__(self, category=FiniteEnumeratedSets())
|
|
1466
|
+
|
|
1467
|
+
Element = ParkingFunction
|
|
1468
|
+
|
|
1469
|
+
def _repr_(self) -> str:
|
|
1470
|
+
"""
|
|
1471
|
+
TESTS::
|
|
1472
|
+
|
|
1473
|
+
sage: repr(ParkingFunctions(3))
|
|
1474
|
+
'Parking functions of size 3'
|
|
1475
|
+
"""
|
|
1476
|
+
return "Parking functions of size %s" % self.n
|
|
1477
|
+
|
|
1478
|
+
def __contains__(self, x) -> bool:
|
|
1479
|
+
"""
|
|
1480
|
+
TESTS::
|
|
1481
|
+
|
|
1482
|
+
sage: PF3 = ParkingFunctions(3); PF3
|
|
1483
|
+
Parking functions of size 3
|
|
1484
|
+
sage: [] in PF3
|
|
1485
|
+
False
|
|
1486
|
+
sage: [1] in PF3
|
|
1487
|
+
False
|
|
1488
|
+
sage: [1,3,1] in PF3
|
|
1489
|
+
True
|
|
1490
|
+
sage: [1,1,1] in PF3
|
|
1491
|
+
True
|
|
1492
|
+
sage: [1,4,1] in PF3
|
|
1493
|
+
False
|
|
1494
|
+
sage: ParkingFunction([1,2]) in PF3
|
|
1495
|
+
False
|
|
1496
|
+
sage: all(p in PF3 for p in PF3)
|
|
1497
|
+
True
|
|
1498
|
+
"""
|
|
1499
|
+
if isinstance(x, ParkingFunction) and len(x) == self.n:
|
|
1500
|
+
return True
|
|
1501
|
+
return is_a(x, self.n)
|
|
1502
|
+
|
|
1503
|
+
def cardinality(self) -> Integer:
|
|
1504
|
+
r"""
|
|
1505
|
+
Return the number of parking functions of size ``n``.
|
|
1506
|
+
|
|
1507
|
+
The cardinality is equal to `(n+1)^{n-1}`.
|
|
1508
|
+
|
|
1509
|
+
EXAMPLES::
|
|
1510
|
+
|
|
1511
|
+
sage: [ParkingFunctions(i).cardinality() for i in range(6)]
|
|
1512
|
+
[1, 1, 3, 16, 125, 1296]
|
|
1513
|
+
"""
|
|
1514
|
+
return Integer((self.n + 1)**(self.n - 1))
|
|
1515
|
+
|
|
1516
|
+
def __iter__(self) -> Iterator:
|
|
1517
|
+
"""
|
|
1518
|
+
Return an iterator for parking functions of size `n`.
|
|
1519
|
+
|
|
1520
|
+
.. WARNING::
|
|
1521
|
+
|
|
1522
|
+
The precise order in which the parking function are
|
|
1523
|
+
generated is not fixed, and may change in the future.
|
|
1524
|
+
|
|
1525
|
+
EXAMPLES::
|
|
1526
|
+
|
|
1527
|
+
sage: PF = ParkingFunctions(0)
|
|
1528
|
+
sage: [e for e in PF] # indirect doctest
|
|
1529
|
+
[[]]
|
|
1530
|
+
sage: PF = ParkingFunctions(1)
|
|
1531
|
+
sage: [e for e in PF] # indirect doctest
|
|
1532
|
+
[[1]]
|
|
1533
|
+
sage: PF = ParkingFunctions(2)
|
|
1534
|
+
sage: [e for e in PF] # indirect doctest
|
|
1535
|
+
[[1, 1], [1, 2], [2, 1]]
|
|
1536
|
+
sage: PF = ParkingFunctions(3)
|
|
1537
|
+
sage: [e for e in PF] # indirect doctest
|
|
1538
|
+
[[1, 1, 1], [1, 1, 2], [1, 2, 1], [2, 1, 1], [1, 1, 3],
|
|
1539
|
+
[1, 3, 1], [3, 1, 1], [1, 2, 2], [2, 1, 2], [2, 2, 1],
|
|
1540
|
+
[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
|
|
1541
|
+
|
|
1542
|
+
TESTS::
|
|
1543
|
+
|
|
1544
|
+
sage: PF = ParkingFunctions(5)
|
|
1545
|
+
sage: [e for e in PF] == PF.list()
|
|
1546
|
+
True
|
|
1547
|
+
sage: PF = ParkingFunctions(6)
|
|
1548
|
+
sage: [e for e in PF] == PF.list()
|
|
1549
|
+
True
|
|
1550
|
+
"""
|
|
1551
|
+
def iterator_rec(n):
|
|
1552
|
+
"""
|
|
1553
|
+
TESTS::
|
|
1554
|
+
|
|
1555
|
+
sage: PF = ParkingFunctions(2)
|
|
1556
|
+
sage: [e for e in PF] # indirect doctest
|
|
1557
|
+
[[1, 1], [1, 2], [2, 1]]
|
|
1558
|
+
"""
|
|
1559
|
+
if n == 0:
|
|
1560
|
+
yield []
|
|
1561
|
+
return
|
|
1562
|
+
if n == 1:
|
|
1563
|
+
yield [1]
|
|
1564
|
+
return
|
|
1565
|
+
for res1 in iterator_rec(n - 1):
|
|
1566
|
+
for i in range(res1[-1], n + 1):
|
|
1567
|
+
yield res1 + [i]
|
|
1568
|
+
return
|
|
1569
|
+
for res in iterator_rec(self.n):
|
|
1570
|
+
for pi in Permutations(res):
|
|
1571
|
+
yield self.element_class(self, list(pi))
|
|
1572
|
+
return
|
|
1573
|
+
|
|
1574
|
+
def random_element(self) -> PF:
|
|
1575
|
+
r"""
|
|
1576
|
+
Return a random parking function of size `n`.
|
|
1577
|
+
|
|
1578
|
+
The algorithm uses a circular parking space with `n+1`
|
|
1579
|
+
spots. Then all `n` cars can park and there remains one empty
|
|
1580
|
+
spot. Spots are then renumbered so that the empty spot is `0`.
|
|
1581
|
+
|
|
1582
|
+
The probability distribution is uniform on the set of
|
|
1583
|
+
`(n+1)^{n-1}` parking functions of size `n`.
|
|
1584
|
+
|
|
1585
|
+
EXAMPLES::
|
|
1586
|
+
|
|
1587
|
+
sage: pf = ParkingFunctions(8)
|
|
1588
|
+
sage: a = pf.random_element(); a # random
|
|
1589
|
+
[5, 7, 2, 4, 2, 5, 1, 3]
|
|
1590
|
+
sage: a in pf
|
|
1591
|
+
True
|
|
1592
|
+
"""
|
|
1593
|
+
n = self.n
|
|
1594
|
+
Zm = Zmod(n + 1)
|
|
1595
|
+
fun = [Zm(randint(0, n)) for i in range(n)]
|
|
1596
|
+
free = [Zm(j) for j in range(n + 1)]
|
|
1597
|
+
for car in fun:
|
|
1598
|
+
position = car
|
|
1599
|
+
while position not in free:
|
|
1600
|
+
position += Zm.one()
|
|
1601
|
+
free.remove(position)
|
|
1602
|
+
return self.element_class(self, [(i - free[0]).lift() for i in fun])
|