passagemath-categories 10.6.32__cp314-cp314t-musllinux_1_2_aarch64.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_categories-10.6.32.dist-info/METADATA +156 -0
- passagemath_categories-10.6.32.dist-info/RECORD +719 -0
- passagemath_categories-10.6.32.dist-info/WHEEL +5 -0
- passagemath_categories-10.6.32.dist-info/top_level.txt +2 -0
- passagemath_categories.libs/libgcc_s-2d945d6c.so.1 +0 -0
- passagemath_categories.libs/libgmp-28992bcb.so.10.5.0 +0 -0
- passagemath_categories.libs/libstdc++-85f2cd6d.so.6.0.33 +0 -0
- sage/all__sagemath_categories.py +28 -0
- sage/arith/all.py +38 -0
- sage/arith/constants.pxd +27 -0
- sage/arith/functions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/functions.pxd +4 -0
- sage/arith/functions.pyx +221 -0
- sage/arith/misc.py +6552 -0
- sage/arith/multi_modular.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/multi_modular.pxd +39 -0
- sage/arith/multi_modular.pyx +994 -0
- sage/arith/rational_reconstruction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/rational_reconstruction.pxd +4 -0
- sage/arith/rational_reconstruction.pyx +115 -0
- sage/arith/srange.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/arith/srange.pyx +571 -0
- sage/calculus/all__sagemath_categories.py +2 -0
- sage/calculus/functional.py +481 -0
- sage/calculus/functions.py +151 -0
- sage/categories/additive_groups.py +73 -0
- sage/categories/additive_magmas.py +1044 -0
- sage/categories/additive_monoids.py +114 -0
- sage/categories/additive_semigroups.py +184 -0
- sage/categories/affine_weyl_groups.py +238 -0
- sage/categories/algebra_ideals.py +95 -0
- sage/categories/algebra_modules.py +96 -0
- sage/categories/algebras.py +349 -0
- sage/categories/algebras_with_basis.py +377 -0
- sage/categories/all.py +160 -0
- sage/categories/aperiodic_semigroups.py +29 -0
- sage/categories/associative_algebras.py +47 -0
- sage/categories/bialgebras.py +101 -0
- sage/categories/bialgebras_with_basis.py +414 -0
- sage/categories/bimodules.py +206 -0
- sage/categories/chain_complexes.py +268 -0
- sage/categories/classical_crystals.py +480 -0
- sage/categories/coalgebras.py +405 -0
- sage/categories/coalgebras_with_basis.py +232 -0
- sage/categories/coercion_methods.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/coercion_methods.pyx +52 -0
- sage/categories/commutative_additive_groups.py +104 -0
- sage/categories/commutative_additive_monoids.py +45 -0
- sage/categories/commutative_additive_semigroups.py +48 -0
- sage/categories/commutative_algebra_ideals.py +87 -0
- sage/categories/commutative_algebras.py +94 -0
- sage/categories/commutative_ring_ideals.py +58 -0
- sage/categories/commutative_rings.py +736 -0
- sage/categories/complete_discrete_valuation.py +293 -0
- sage/categories/complex_reflection_groups.py +145 -0
- sage/categories/complex_reflection_or_generalized_coxeter_groups.py +1249 -0
- sage/categories/coxeter_group_algebras.py +186 -0
- sage/categories/coxeter_groups.py +3402 -0
- sage/categories/crystals.py +2628 -0
- sage/categories/cw_complexes.py +216 -0
- sage/categories/dedekind_domains.py +137 -0
- sage/categories/discrete_valuation.py +325 -0
- sage/categories/distributive_magmas_and_additive_magmas.py +100 -0
- sage/categories/division_rings.py +114 -0
- sage/categories/domains.py +95 -0
- sage/categories/drinfeld_modules.py +789 -0
- sage/categories/dual.py +42 -0
- sage/categories/enumerated_sets.py +1146 -0
- sage/categories/euclidean_domains.py +271 -0
- sage/categories/examples/algebras_with_basis.py +102 -0
- sage/categories/examples/all.py +1 -0
- sage/categories/examples/commutative_additive_monoids.py +130 -0
- sage/categories/examples/commutative_additive_semigroups.py +199 -0
- sage/categories/examples/coxeter_groups.py +8 -0
- sage/categories/examples/crystals.py +236 -0
- sage/categories/examples/cw_complexes.py +163 -0
- sage/categories/examples/facade_sets.py +187 -0
- sage/categories/examples/filtered_algebras_with_basis.py +204 -0
- sage/categories/examples/filtered_modules_with_basis.py +154 -0
- sage/categories/examples/finite_coxeter_groups.py +252 -0
- sage/categories/examples/finite_dimensional_algebras_with_basis.py +148 -0
- sage/categories/examples/finite_dimensional_lie_algebras_with_basis.py +495 -0
- sage/categories/examples/finite_enumerated_sets.py +208 -0
- sage/categories/examples/finite_monoids.py +150 -0
- sage/categories/examples/finite_semigroups.py +190 -0
- sage/categories/examples/finite_weyl_groups.py +191 -0
- sage/categories/examples/graded_connected_hopf_algebras_with_basis.py +152 -0
- sage/categories/examples/graded_modules_with_basis.py +168 -0
- sage/categories/examples/graphs.py +122 -0
- sage/categories/examples/hopf_algebras_with_basis.py +145 -0
- sage/categories/examples/infinite_enumerated_sets.py +190 -0
- sage/categories/examples/lie_algebras.py +352 -0
- sage/categories/examples/lie_algebras_with_basis.py +196 -0
- sage/categories/examples/magmas.py +162 -0
- sage/categories/examples/manifolds.py +94 -0
- sage/categories/examples/monoids.py +144 -0
- sage/categories/examples/posets.py +178 -0
- sage/categories/examples/semigroups.py +580 -0
- sage/categories/examples/semigroups_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/categories/examples/semigroups_cython.pyx +221 -0
- sage/categories/examples/semirings.py +249 -0
- sage/categories/examples/sets_cat.py +706 -0
- sage/categories/examples/sets_with_grading.py +101 -0
- sage/categories/examples/with_realizations.py +542 -0
- sage/categories/fields.py +991 -0
- sage/categories/filtered_algebras.py +63 -0
- sage/categories/filtered_algebras_with_basis.py +548 -0
- sage/categories/filtered_hopf_algebras_with_basis.py +138 -0
- sage/categories/filtered_modules.py +210 -0
- sage/categories/filtered_modules_with_basis.py +1209 -0
- sage/categories/finite_complex_reflection_groups.py +1506 -0
- sage/categories/finite_coxeter_groups.py +1138 -0
- sage/categories/finite_crystals.py +103 -0
- sage/categories/finite_dimensional_algebras_with_basis.py +1860 -0
- sage/categories/finite_dimensional_bialgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_coalgebras_with_basis.py +33 -0
- sage/categories/finite_dimensional_graded_lie_algebras_with_basis.py +231 -0
- sage/categories/finite_dimensional_hopf_algebras_with_basis.py +38 -0
- sage/categories/finite_dimensional_lie_algebras_with_basis.py +2774 -0
- sage/categories/finite_dimensional_modules_with_basis.py +1407 -0
- sage/categories/finite_dimensional_nilpotent_lie_algebras_with_basis.py +167 -0
- sage/categories/finite_dimensional_semisimple_algebras_with_basis.py +270 -0
- sage/categories/finite_enumerated_sets.py +769 -0
- sage/categories/finite_fields.py +252 -0
- sage/categories/finite_groups.py +256 -0
- sage/categories/finite_lattice_posets.py +242 -0
- sage/categories/finite_monoids.py +316 -0
- sage/categories/finite_permutation_groups.py +339 -0
- sage/categories/finite_posets.py +1994 -0
- sage/categories/finite_semigroups.py +136 -0
- sage/categories/finite_sets.py +93 -0
- sage/categories/finite_weyl_groups.py +39 -0
- sage/categories/finitely_generated_lambda_bracket_algebras.py +112 -0
- sage/categories/finitely_generated_lie_conformal_algebras.py +114 -0
- sage/categories/finitely_generated_magmas.py +57 -0
- sage/categories/finitely_generated_semigroups.py +214 -0
- sage/categories/function_fields.py +76 -0
- sage/categories/g_sets.py +77 -0
- sage/categories/gcd_domains.py +65 -0
- sage/categories/generalized_coxeter_groups.py +94 -0
- sage/categories/graded_algebras.py +85 -0
- sage/categories/graded_algebras_with_basis.py +258 -0
- sage/categories/graded_bialgebras.py +32 -0
- sage/categories/graded_bialgebras_with_basis.py +32 -0
- sage/categories/graded_coalgebras.py +65 -0
- sage/categories/graded_coalgebras_with_basis.py +51 -0
- sage/categories/graded_hopf_algebras.py +41 -0
- sage/categories/graded_hopf_algebras_with_basis.py +169 -0
- sage/categories/graded_lie_algebras.py +91 -0
- sage/categories/graded_lie_algebras_with_basis.py +44 -0
- sage/categories/graded_lie_conformal_algebras.py +74 -0
- sage/categories/graded_modules.py +133 -0
- sage/categories/graded_modules_with_basis.py +329 -0
- sage/categories/graphs.py +138 -0
- sage/categories/group_algebras.py +430 -0
- sage/categories/groupoid.py +94 -0
- sage/categories/groups.py +667 -0
- sage/categories/h_trivial_semigroups.py +64 -0
- sage/categories/hecke_modules.py +185 -0
- sage/categories/highest_weight_crystals.py +980 -0
- sage/categories/hopf_algebras.py +219 -0
- sage/categories/hopf_algebras_with_basis.py +309 -0
- sage/categories/infinite_enumerated_sets.py +115 -0
- sage/categories/integral_domains.py +203 -0
- sage/categories/j_trivial_semigroups.py +29 -0
- sage/categories/kac_moody_algebras.py +82 -0
- sage/categories/kahler_algebras.py +203 -0
- sage/categories/l_trivial_semigroups.py +63 -0
- sage/categories/lambda_bracket_algebras.py +280 -0
- sage/categories/lambda_bracket_algebras_with_basis.py +107 -0
- sage/categories/lattice_posets.py +89 -0
- sage/categories/left_modules.py +49 -0
- sage/categories/lie_algebras.py +1070 -0
- sage/categories/lie_algebras_with_basis.py +261 -0
- sage/categories/lie_conformal_algebras.py +350 -0
- sage/categories/lie_conformal_algebras_with_basis.py +147 -0
- sage/categories/lie_groups.py +73 -0
- sage/categories/loop_crystals.py +1290 -0
- sage/categories/magmas.py +1189 -0
- sage/categories/magmas_and_additive_magmas.py +149 -0
- sage/categories/magmatic_algebras.py +365 -0
- sage/categories/manifolds.py +352 -0
- sage/categories/matrix_algebras.py +40 -0
- sage/categories/metric_spaces.py +387 -0
- sage/categories/modular_abelian_varieties.py +78 -0
- sage/categories/modules.py +989 -0
- sage/categories/modules_with_basis.py +2794 -0
- sage/categories/monoid_algebras.py +38 -0
- sage/categories/monoids.py +739 -0
- sage/categories/noetherian_rings.py +87 -0
- sage/categories/number_fields.py +242 -0
- sage/categories/ore_modules.py +189 -0
- sage/categories/partially_ordered_monoids.py +49 -0
- sage/categories/permutation_groups.py +63 -0
- sage/categories/pointed_sets.py +42 -0
- sage/categories/polyhedra.py +74 -0
- sage/categories/poor_man_map.py +270 -0
- sage/categories/posets.py +722 -0
- sage/categories/principal_ideal_domains.py +270 -0
- sage/categories/quantum_group_representations.py +543 -0
- sage/categories/quotient_fields.py +728 -0
- sage/categories/r_trivial_semigroups.py +45 -0
- sage/categories/regular_crystals.py +898 -0
- sage/categories/regular_supercrystals.py +170 -0
- sage/categories/right_modules.py +49 -0
- sage/categories/ring_ideals.py +74 -0
- sage/categories/rings.py +1904 -0
- sage/categories/rngs.py +175 -0
- sage/categories/schemes.py +393 -0
- sage/categories/semigroups.py +1060 -0
- sage/categories/semirings.py +71 -0
- sage/categories/semisimple_algebras.py +114 -0
- sage/categories/sets_with_grading.py +235 -0
- sage/categories/shephard_groups.py +43 -0
- sage/categories/signed_tensor.py +120 -0
- sage/categories/simplicial_complexes.py +134 -0
- sage/categories/simplicial_sets.py +1206 -0
- sage/categories/super_algebras.py +149 -0
- sage/categories/super_algebras_with_basis.py +144 -0
- sage/categories/super_hopf_algebras_with_basis.py +126 -0
- sage/categories/super_lie_conformal_algebras.py +193 -0
- sage/categories/super_modules.py +229 -0
- sage/categories/super_modules_with_basis.py +193 -0
- sage/categories/supercommutative_algebras.py +99 -0
- sage/categories/supercrystals.py +406 -0
- sage/categories/tensor.py +110 -0
- sage/categories/topological_spaces.py +170 -0
- sage/categories/triangular_kac_moody_algebras.py +439 -0
- sage/categories/tutorial.py +58 -0
- sage/categories/unique_factorization_domains.py +318 -0
- sage/categories/unital_algebras.py +426 -0
- sage/categories/vector_bundles.py +159 -0
- sage/categories/vector_spaces.py +357 -0
- sage/categories/weyl_groups.py +853 -0
- sage/combinat/all__sagemath_categories.py +34 -0
- sage/combinat/backtrack.py +180 -0
- sage/combinat/combinat.py +2269 -0
- sage/combinat/combinat_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/combinat_cython.pxd +6 -0
- sage/combinat/combinat_cython.pyx +390 -0
- sage/combinat/combination.py +796 -0
- sage/combinat/combinatorial_map.py +416 -0
- sage/combinat/composition.py +2192 -0
- sage/combinat/dlx.py +510 -0
- sage/combinat/integer_lists/__init__.py +7 -0
- sage/combinat/integer_lists/base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/base.pxd +16 -0
- sage/combinat/integer_lists/base.pyx +713 -0
- sage/combinat/integer_lists/invlex.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/integer_lists/invlex.pxd +4 -0
- sage/combinat/integer_lists/invlex.pyx +1650 -0
- sage/combinat/integer_lists/lists.py +328 -0
- sage/combinat/integer_lists/nn.py +48 -0
- sage/combinat/integer_vector.py +1818 -0
- sage/combinat/integer_vector_weighted.py +413 -0
- sage/combinat/matrices/all__sagemath_categories.py +5 -0
- sage/combinat/matrices/dancing_links.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/matrices/dancing_links.pyx +1159 -0
- sage/combinat/matrices/dancing_links_c.h +380 -0
- sage/combinat/matrices/dlxcpp.py +136 -0
- sage/combinat/partition.py +10070 -0
- sage/combinat/partitions.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/partitions.pyx +743 -0
- sage/combinat/permutation.py +10168 -0
- sage/combinat/permutation_cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/combinat/permutation_cython.pxd +11 -0
- sage/combinat/permutation_cython.pyx +407 -0
- sage/combinat/q_analogues.py +1090 -0
- sage/combinat/ranker.py +268 -0
- sage/combinat/subset.py +1561 -0
- sage/combinat/subsets_hereditary.py +202 -0
- sage/combinat/subsets_pairwise.py +184 -0
- sage/combinat/tools.py +63 -0
- sage/combinat/tuple.py +348 -0
- sage/data_structures/all.py +2 -0
- sage/data_structures/all__sagemath_categories.py +2 -0
- sage/data_structures/binary_matrix.pxd +138 -0
- sage/data_structures/binary_search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/binary_search.pxd +3 -0
- sage/data_structures/binary_search.pyx +66 -0
- sage/data_structures/bitset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset.pxd +40 -0
- sage/data_structures/bitset.pyx +2385 -0
- sage/data_structures/bitset_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/bitset_base.pxd +926 -0
- sage/data_structures/bitset_base.pyx +117 -0
- sage/data_structures/bitset_intrinsics.h +487 -0
- sage/data_structures/blas_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/blas_dict.pxd +12 -0
- sage/data_structures/blas_dict.pyx +469 -0
- sage/data_structures/list_of_pairs.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/list_of_pairs.pxd +16 -0
- sage/data_structures/list_of_pairs.pyx +122 -0
- sage/data_structures/mutable_poset.py +3312 -0
- sage/data_structures/pairing_heap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/data_structures/pairing_heap.h +346 -0
- sage/data_structures/pairing_heap.pxd +88 -0
- sage/data_structures/pairing_heap.pyx +1464 -0
- sage/data_structures/sparse_bitset.pxd +62 -0
- sage/data_structures/stream.py +5070 -0
- sage/databases/all__sagemath_categories.py +7 -0
- sage/databases/sql_db.py +2236 -0
- sage/ext/all__sagemath_categories.py +3 -0
- sage/ext/fast_callable.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_callable.pxd +4 -0
- sage/ext/fast_callable.pyx +2746 -0
- sage/ext/fast_eval.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/fast_eval.pxd +1 -0
- sage/ext/fast_eval.pyx +102 -0
- sage/ext/interpreters/__init__.py +1 -0
- sage/ext/interpreters/all__sagemath_categories.py +2 -0
- sage/ext/interpreters/wrapper_el.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_el.pxd +18 -0
- sage/ext/interpreters/wrapper_el.pyx +148 -0
- sage/ext/interpreters/wrapper_py.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/ext/interpreters/wrapper_py.pxd +17 -0
- sage/ext/interpreters/wrapper_py.pyx +133 -0
- sage/functions/airy.py +937 -0
- sage/functions/all.py +97 -0
- sage/functions/bessel.py +2102 -0
- sage/functions/error.py +784 -0
- sage/functions/exp_integral.py +1529 -0
- sage/functions/gamma.py +1087 -0
- sage/functions/generalized.py +672 -0
- sage/functions/hyperbolic.py +747 -0
- sage/functions/hypergeometric.py +1156 -0
- sage/functions/jacobi.py +1705 -0
- sage/functions/log.py +1402 -0
- sage/functions/min_max.py +338 -0
- sage/functions/orthogonal_polys.py +3106 -0
- sage/functions/other.py +2303 -0
- sage/functions/piecewise.py +1505 -0
- sage/functions/prime_pi.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/functions/prime_pi.pyx +262 -0
- sage/functions/special.py +1212 -0
- sage/functions/spike_function.py +278 -0
- sage/functions/transcendental.py +690 -0
- sage/functions/trig.py +1062 -0
- sage/functions/wigner.py +726 -0
- sage/geometry/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/geometry/abc.pyx +82 -0
- sage/geometry/all__sagemath_categories.py +1 -0
- sage/groups/all__sagemath_categories.py +11 -0
- sage/groups/generic.py +1733 -0
- sage/groups/groups_catalog.py +113 -0
- sage/groups/perm_gps/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/all.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_categories.py +1 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pxd +52 -0
- sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx +906 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd +85 -0
- sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx +534 -0
- sage/groups/perm_gps/partn_ref/data_structures.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/data_structures.pxd +576 -0
- sage/groups/perm_gps/partn_ref/data_structures.pyx +1792 -0
- sage/groups/perm_gps/partn_ref/double_coset.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/double_coset.pxd +45 -0
- sage/groups/perm_gps/partn_ref/double_coset.pyx +739 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pxd +18 -0
- sage/groups/perm_gps/partn_ref/refinement_lists.pyx +82 -0
- sage/groups/perm_gps/partn_ref/refinement_python.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pxd +16 -0
- sage/groups/perm_gps/partn_ref/refinement_python.pyx +564 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pxd +60 -0
- sage/groups/perm_gps/partn_ref/refinement_sets.pyx +858 -0
- sage/interfaces/abc.py +140 -0
- sage/interfaces/all.py +58 -0
- sage/interfaces/all__sagemath_categories.py +1 -0
- sage/interfaces/expect.py +1643 -0
- sage/interfaces/interface.py +1682 -0
- sage/interfaces/process.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/process.pxd +5 -0
- sage/interfaces/process.pyx +288 -0
- sage/interfaces/quit.py +167 -0
- sage/interfaces/sage0.py +604 -0
- sage/interfaces/sagespawn.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/interfaces/sagespawn.pyx +308 -0
- sage/interfaces/tab_completion.py +101 -0
- sage/misc/all__sagemath_categories.py +78 -0
- sage/misc/allocator.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/allocator.pxd +6 -0
- sage/misc/allocator.pyx +47 -0
- sage/misc/binary_tree.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/binary_tree.pxd +29 -0
- sage/misc/binary_tree.pyx +537 -0
- sage/misc/callable_dict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/callable_dict.pyx +89 -0
- sage/misc/citation.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/citation.pyx +159 -0
- sage/misc/converting_dict.py +293 -0
- sage/misc/defaults.py +129 -0
- sage/misc/derivative.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/derivative.pyx +223 -0
- sage/misc/functional.py +2005 -0
- sage/misc/html.py +589 -0
- sage/misc/latex.py +2673 -0
- sage/misc/latex_macros.py +236 -0
- sage/misc/latex_standalone.py +1833 -0
- sage/misc/map_threaded.py +38 -0
- sage/misc/mathml.py +76 -0
- sage/misc/method_decorator.py +88 -0
- sage/misc/mrange.py +755 -0
- sage/misc/multireplace.py +41 -0
- sage/misc/object_multiplexer.py +92 -0
- sage/misc/parser.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/parser.pyx +1107 -0
- sage/misc/random_testing.py +264 -0
- sage/misc/rest_index_of_methods.py +377 -0
- sage/misc/search.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/search.pxd +2 -0
- sage/misc/search.pyx +68 -0
- sage/misc/stopgap.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/misc/stopgap.pyx +95 -0
- sage/misc/table.py +853 -0
- sage/monoids/all__sagemath_categories.py +1 -0
- sage/monoids/indexed_free_monoid.py +1071 -0
- sage/monoids/monoid.py +82 -0
- sage/numerical/all__sagemath_categories.py +1 -0
- sage/numerical/backends/all__sagemath_categories.py +1 -0
- sage/numerical/backends/generic_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_backend.pxd +61 -0
- sage/numerical/backends/generic_backend.pyx +1893 -0
- sage/numerical/backends/generic_sdp_backend.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/numerical/backends/generic_sdp_backend.pxd +38 -0
- sage/numerical/backends/generic_sdp_backend.pyx +755 -0
- sage/parallel/all.py +6 -0
- sage/parallel/decorate.py +575 -0
- sage/parallel/map_reduce.py +1997 -0
- sage/parallel/multiprocessing_sage.py +76 -0
- sage/parallel/ncpus.py +35 -0
- sage/parallel/parallelism.py +364 -0
- sage/parallel/reference.py +47 -0
- sage/parallel/use_fork.py +333 -0
- sage/rings/abc.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/abc.pxd +31 -0
- sage/rings/abc.pyx +526 -0
- sage/rings/algebraic_closure_finite_field.py +1154 -0
- sage/rings/all__sagemath_categories.py +91 -0
- sage/rings/big_oh.py +227 -0
- sage/rings/continued_fraction.py +2754 -0
- sage/rings/continued_fraction_gosper.py +220 -0
- sage/rings/factorint.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/factorint.pyx +295 -0
- sage/rings/fast_arith.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fast_arith.pxd +21 -0
- sage/rings/fast_arith.pyx +535 -0
- sage/rings/finite_rings/all__sagemath_categories.py +9 -0
- sage/rings/finite_rings/conway_polynomials.py +542 -0
- sage/rings/finite_rings/element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/element_base.pxd +12 -0
- sage/rings/finite_rings/element_base.pyx +1176 -0
- sage/rings/finite_rings/finite_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/finite_field_base.pxd +7 -0
- sage/rings/finite_rings/finite_field_base.pyx +2171 -0
- sage/rings/finite_rings/finite_field_constructor.py +827 -0
- sage/rings/finite_rings/finite_field_prime_modn.py +372 -0
- sage/rings/finite_rings/galois_group.py +154 -0
- sage/rings/finite_rings/hom_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_finite_field.pxd +23 -0
- sage/rings/finite_rings/hom_finite_field.pyx +856 -0
- sage/rings/finite_rings/hom_prime_finite_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/hom_prime_finite_field.pxd +15 -0
- sage/rings/finite_rings/hom_prime_finite_field.pyx +164 -0
- sage/rings/finite_rings/homset.py +357 -0
- sage/rings/finite_rings/integer_mod.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/integer_mod.pxd +56 -0
- sage/rings/finite_rings/integer_mod.pyx +4586 -0
- sage/rings/finite_rings/integer_mod_limits.h +11 -0
- sage/rings/finite_rings/integer_mod_ring.py +2044 -0
- sage/rings/finite_rings/residue_field.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/finite_rings/residue_field.pxd +30 -0
- sage/rings/finite_rings/residue_field.pyx +1811 -0
- sage/rings/finite_rings/stdint.pxd +19 -0
- sage/rings/fraction_field.py +1452 -0
- sage/rings/fraction_field_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/fraction_field_element.pyx +1357 -0
- sage/rings/function_field/all.py +7 -0
- sage/rings/function_field/all__sagemath_categories.py +2 -0
- sage/rings/function_field/constructor.py +218 -0
- sage/rings/function_field/element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element.pxd +11 -0
- sage/rings/function_field/element.pyx +1008 -0
- sage/rings/function_field/element_rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/function_field/element_rational.pyx +513 -0
- sage/rings/function_field/extensions.py +230 -0
- sage/rings/function_field/function_field.py +1468 -0
- sage/rings/function_field/function_field_rational.py +1005 -0
- sage/rings/function_field/ideal.py +1155 -0
- sage/rings/function_field/ideal_rational.py +629 -0
- sage/rings/function_field/jacobian_base.py +826 -0
- sage/rings/function_field/jacobian_hess.py +1053 -0
- sage/rings/function_field/jacobian_khuri_makdisi.py +1027 -0
- sage/rings/function_field/maps.py +1039 -0
- sage/rings/function_field/order.py +281 -0
- sage/rings/function_field/order_basis.py +586 -0
- sage/rings/function_field/order_rational.py +576 -0
- sage/rings/function_field/place.py +426 -0
- sage/rings/function_field/place_rational.py +181 -0
- sage/rings/generic.py +320 -0
- sage/rings/homset.py +332 -0
- sage/rings/ideal.py +1885 -0
- sage/rings/ideal_monoid.py +215 -0
- sage/rings/infinity.py +1890 -0
- sage/rings/integer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer.pxd +45 -0
- sage/rings/integer.pyx +7874 -0
- sage/rings/integer_ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/integer_ring.pxd +8 -0
- sage/rings/integer_ring.pyx +1693 -0
- sage/rings/laurent_series_ring.py +931 -0
- sage/rings/laurent_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/laurent_series_ring_element.pxd +11 -0
- sage/rings/laurent_series_ring_element.pyx +1927 -0
- sage/rings/lazy_series.py +7815 -0
- sage/rings/lazy_series_ring.py +4356 -0
- sage/rings/localization.py +1043 -0
- sage/rings/morphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/morphism.pxd +39 -0
- sage/rings/morphism.pyx +3299 -0
- sage/rings/multi_power_series_ring.py +1145 -0
- sage/rings/multi_power_series_ring_element.py +2184 -0
- sage/rings/noncommutative_ideals.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/noncommutative_ideals.pyx +423 -0
- sage/rings/number_field/all__sagemath_categories.py +1 -0
- sage/rings/number_field/number_field_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_base.pxd +8 -0
- sage/rings/number_field/number_field_base.pyx +507 -0
- sage/rings/number_field/number_field_element_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/number_field/number_field_element_base.pxd +6 -0
- sage/rings/number_field/number_field_element_base.pyx +36 -0
- sage/rings/number_field/number_field_ideal.py +3550 -0
- sage/rings/padics/all__sagemath_categories.py +4 -0
- sage/rings/padics/local_generic.py +1670 -0
- sage/rings/padics/local_generic_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/local_generic_element.pxd +5 -0
- sage/rings/padics/local_generic_element.pyx +1017 -0
- sage/rings/padics/misc.py +256 -0
- sage/rings/padics/padic_generic.py +1911 -0
- sage/rings/padics/pow_computer.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/padics/pow_computer.pxd +38 -0
- sage/rings/padics/pow_computer.pyx +671 -0
- sage/rings/padics/precision_error.py +24 -0
- sage/rings/polynomial/all__sagemath_categories.py +25 -0
- sage/rings/polynomial/commutative_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/commutative_polynomial.pxd +6 -0
- sage/rings/polynomial/commutative_polynomial.pyx +24 -0
- sage/rings/polynomial/cyclotomic.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/cyclotomic.pyx +404 -0
- sage/rings/polynomial/flatten.py +711 -0
- sage/rings/polynomial/ideal.py +102 -0
- sage/rings/polynomial/infinite_polynomial_element.py +1768 -0
- sage/rings/polynomial/infinite_polynomial_ring.py +1653 -0
- sage/rings/polynomial/laurent_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/laurent_polynomial.pxd +18 -0
- sage/rings/polynomial/laurent_polynomial.pyx +2190 -0
- sage/rings/polynomial/laurent_polynomial_ideal.py +590 -0
- sage/rings/polynomial/laurent_polynomial_ring.py +832 -0
- sage/rings/polynomial/laurent_polynomial_ring_base.py +708 -0
- sage/rings/polynomial/multi_polynomial.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial.pxd +12 -0
- sage/rings/polynomial/multi_polynomial.pyx +3082 -0
- sage/rings/polynomial/multi_polynomial_element.py +2570 -0
- sage/rings/polynomial/multi_polynomial_ideal.py +5771 -0
- sage/rings/polynomial/multi_polynomial_ring.py +947 -0
- sage/rings/polynomial/multi_polynomial_ring_base.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pxd +15 -0
- sage/rings/polynomial/multi_polynomial_ring_base.pyx +1855 -0
- sage/rings/polynomial/multi_polynomial_sequence.py +2204 -0
- sage/rings/polynomial/polydict.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polydict.pxd +45 -0
- sage/rings/polynomial/polydict.pyx +2701 -0
- sage/rings/polynomial/polynomial_compiled.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_compiled.pxd +59 -0
- sage/rings/polynomial/polynomial_compiled.pyx +509 -0
- sage/rings/polynomial/polynomial_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_element.pxd +64 -0
- sage/rings/polynomial/polynomial_element.pyx +13255 -0
- sage/rings/polynomial/polynomial_element_generic.py +1637 -0
- sage/rings/polynomial/polynomial_fateman.py +97 -0
- sage/rings/polynomial/polynomial_quotient_ring.py +2465 -0
- sage/rings/polynomial/polynomial_quotient_ring_element.py +779 -0
- sage/rings/polynomial/polynomial_ring.py +3784 -0
- sage/rings/polynomial/polynomial_ring_constructor.py +1051 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pxd +5 -0
- sage/rings/polynomial/polynomial_ring_homomorphism.pyx +121 -0
- sage/rings/polynomial/polynomial_singular_interface.py +549 -0
- sage/rings/polynomial/symmetric_ideal.py +989 -0
- sage/rings/polynomial/symmetric_reduction.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/symmetric_reduction.pxd +8 -0
- sage/rings/polynomial/symmetric_reduction.pyx +669 -0
- sage/rings/polynomial/term_order.py +2279 -0
- sage/rings/polynomial/toy_buchberger.py +449 -0
- sage/rings/polynomial/toy_d_basis.py +387 -0
- sage/rings/polynomial/toy_variety.py +362 -0
- sage/rings/power_series_mpoly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_mpoly.pxd +9 -0
- sage/rings/power_series_mpoly.pyx +161 -0
- sage/rings/power_series_poly.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_poly.pxd +10 -0
- sage/rings/power_series_poly.pyx +1317 -0
- sage/rings/power_series_ring.py +1441 -0
- sage/rings/power_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/power_series_ring_element.pxd +12 -0
- sage/rings/power_series_ring_element.pyx +3028 -0
- sage/rings/puiseux_series_ring.py +487 -0
- sage/rings/puiseux_series_ring_element.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/puiseux_series_ring_element.pxd +7 -0
- sage/rings/puiseux_series_ring_element.pyx +1055 -0
- sage/rings/qqbar_decorators.py +167 -0
- sage/rings/quotient_ring.py +1598 -0
- sage/rings/quotient_ring_element.py +979 -0
- sage/rings/rational.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/rational.pxd +20 -0
- sage/rings/rational.pyx +4284 -0
- sage/rings/rational_field.py +1730 -0
- sage/rings/real_double.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_double.pxd +16 -0
- sage/rings/real_double.pyx +2218 -0
- sage/rings/real_lazy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/real_lazy.pxd +30 -0
- sage/rings/real_lazy.pyx +1773 -0
- sage/rings/ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/ring.pxd +30 -0
- sage/rings/ring.pyx +850 -0
- sage/rings/semirings/all.py +3 -0
- sage/rings/semirings/non_negative_integer_semiring.py +107 -0
- sage/rings/semirings/tropical_mpolynomial.py +972 -0
- sage/rings/semirings/tropical_polynomial.py +997 -0
- sage/rings/semirings/tropical_semiring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/semirings/tropical_semiring.pyx +676 -0
- sage/rings/semirings/tropical_variety.py +1701 -0
- sage/rings/sum_of_squares.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/rings/sum_of_squares.pxd +3 -0
- sage/rings/sum_of_squares.pyx +336 -0
- sage/rings/tests.py +504 -0
- sage/schemes/affine/affine_homset.py +508 -0
- sage/schemes/affine/affine_morphism.py +1574 -0
- sage/schemes/affine/affine_point.py +460 -0
- sage/schemes/affine/affine_rational_point.py +308 -0
- sage/schemes/affine/affine_space.py +1264 -0
- sage/schemes/affine/affine_subscheme.py +592 -0
- sage/schemes/affine/all.py +25 -0
- sage/schemes/all__sagemath_categories.py +5 -0
- sage/schemes/generic/algebraic_scheme.py +2092 -0
- sage/schemes/generic/all.py +5 -0
- sage/schemes/generic/ambient_space.py +400 -0
- sage/schemes/generic/divisor.py +465 -0
- sage/schemes/generic/divisor_group.py +313 -0
- sage/schemes/generic/glue.py +84 -0
- sage/schemes/generic/homset.py +820 -0
- sage/schemes/generic/hypersurface.py +234 -0
- sage/schemes/generic/morphism.py +2107 -0
- sage/schemes/generic/point.py +237 -0
- sage/schemes/generic/scheme.py +1190 -0
- sage/schemes/generic/spec.py +199 -0
- sage/schemes/product_projective/all.py +6 -0
- sage/schemes/product_projective/homset.py +236 -0
- sage/schemes/product_projective/morphism.py +517 -0
- sage/schemes/product_projective/point.py +568 -0
- sage/schemes/product_projective/rational_point.py +550 -0
- sage/schemes/product_projective/space.py +1301 -0
- sage/schemes/product_projective/subscheme.py +466 -0
- sage/schemes/projective/all.py +24 -0
- sage/schemes/projective/proj_bdd_height.py +453 -0
- sage/schemes/projective/projective_homset.py +718 -0
- sage/schemes/projective/projective_morphism.py +2792 -0
- sage/schemes/projective/projective_point.py +1484 -0
- sage/schemes/projective/projective_rational_point.py +569 -0
- sage/schemes/projective/projective_space.py +2571 -0
- sage/schemes/projective/projective_subscheme.py +1574 -0
- sage/sets/all.py +17 -0
- sage/sets/cartesian_product.py +376 -0
- sage/sets/condition_set.py +525 -0
- sage/sets/disjoint_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/disjoint_set.pxd +36 -0
- sage/sets/disjoint_set.pyx +998 -0
- sage/sets/disjoint_union_enumerated_sets.py +625 -0
- sage/sets/family.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/family.pxd +12 -0
- sage/sets/family.pyx +1556 -0
- sage/sets/finite_enumerated_set.py +406 -0
- sage/sets/finite_set_map_cy.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/finite_set_map_cy.pxd +34 -0
- sage/sets/finite_set_map_cy.pyx +708 -0
- sage/sets/finite_set_maps.py +591 -0
- sage/sets/image_set.py +448 -0
- sage/sets/integer_range.py +829 -0
- sage/sets/non_negative_integers.py +241 -0
- sage/sets/positive_integers.py +93 -0
- sage/sets/primes.py +188 -0
- sage/sets/real_set.py +2760 -0
- sage/sets/recursively_enumerated_set.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/sets/recursively_enumerated_set.pxd +31 -0
- sage/sets/recursively_enumerated_set.pyx +2082 -0
- sage/sets/set.py +2083 -0
- sage/sets/set_from_iterator.py +1021 -0
- sage/sets/totally_ordered_finite_set.py +329 -0
- sage/symbolic/all__sagemath_categories.py +1 -0
- sage/symbolic/function.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/symbolic/function.pxd +29 -0
- sage/symbolic/function.pyx +1488 -0
- sage/symbolic/symbols.py +56 -0
- sage/tests/all__sagemath_categories.py +1 -0
- sage/tests/cython.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/cython.pyx +37 -0
- sage/tests/stl_vector.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/tests/stl_vector.pyx +171 -0
- sage/typeset/all.py +6 -0
- sage/typeset/ascii_art.py +295 -0
- sage/typeset/character_art.py +789 -0
- sage/typeset/character_art_factory.py +572 -0
- sage/typeset/symbols.py +334 -0
- sage/typeset/unicode_art.py +183 -0
- sage/typeset/unicode_characters.py +101 -0
|
@@ -0,0 +1,2192 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
r"""
|
|
3
|
+
Integer compositions
|
|
4
|
+
|
|
5
|
+
A composition `c` of a nonnegative integer `n` is a list of positive integers
|
|
6
|
+
(the *parts* of the composition) with total sum `n`.
|
|
7
|
+
|
|
8
|
+
This module provides tools for manipulating compositions and enumerated
|
|
9
|
+
sets of compositions.
|
|
10
|
+
|
|
11
|
+
EXAMPLES::
|
|
12
|
+
|
|
13
|
+
sage: Composition([5, 3, 1, 3])
|
|
14
|
+
[5, 3, 1, 3]
|
|
15
|
+
sage: list(Compositions(4))
|
|
16
|
+
[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]
|
|
17
|
+
|
|
18
|
+
AUTHORS:
|
|
19
|
+
|
|
20
|
+
- Mike Hansen, Nicolas M. Thiéry
|
|
21
|
+
- MuPAD-Combinat developers (algorithms and design inspiration)
|
|
22
|
+
- Travis Scrimshaw (2013-02-03): Removed ``CombinatorialClass``
|
|
23
|
+
"""
|
|
24
|
+
# ****************************************************************************
|
|
25
|
+
# Copyright (C) 2007 Mike Hansen <mhansen@gmail.com>
|
|
26
|
+
# 2009 Nicolas M. Thiery <nthiery at users.sf.net>
|
|
27
|
+
#
|
|
28
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
29
|
+
# https://www.gnu.org/licenses/
|
|
30
|
+
# ****************************************************************************
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
from itertools import accumulate
|
|
33
|
+
from collections.abc import Sequence
|
|
34
|
+
|
|
35
|
+
from sage.categories.enumerated_sets import EnumeratedSets
|
|
36
|
+
from sage.categories.additive_monoids import AdditiveMonoids
|
|
37
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
38
|
+
from sage.structure.parent import Parent
|
|
39
|
+
from sage.sets.finite_enumerated_set import FiniteEnumeratedSet
|
|
40
|
+
from sage.rings.integer_ring import ZZ
|
|
41
|
+
from .combinat import CombinatorialElement
|
|
42
|
+
from sage.categories.cartesian_product import cartesian_product
|
|
43
|
+
|
|
44
|
+
from .integer_lists import IntegerListsLex
|
|
45
|
+
from sage.rings.integer import Integer
|
|
46
|
+
from sage.combinat.combinatorial_map import combinatorial_map
|
|
47
|
+
from sage.misc.persist import register_unpickle_override
|
|
48
|
+
|
|
49
|
+
from sage.misc.lazy_import import lazy_import
|
|
50
|
+
lazy_import("sage.combinat.partition", "Partition")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Composition(CombinatorialElement):
|
|
54
|
+
r"""
|
|
55
|
+
Integer compositions.
|
|
56
|
+
|
|
57
|
+
A composition of a nonnegative integer `n` is a list
|
|
58
|
+
`(i_1, \ldots, i_k)` of positive integers with total sum `n`.
|
|
59
|
+
|
|
60
|
+
EXAMPLES:
|
|
61
|
+
|
|
62
|
+
The simplest way to create a composition is by specifying its
|
|
63
|
+
entries as a list, tuple (or other iterable)::
|
|
64
|
+
|
|
65
|
+
sage: Composition([3,1,2])
|
|
66
|
+
[3, 1, 2]
|
|
67
|
+
sage: Composition((3,1,2))
|
|
68
|
+
[3, 1, 2]
|
|
69
|
+
sage: Composition(i for i in range(2,5))
|
|
70
|
+
[2, 3, 4]
|
|
71
|
+
|
|
72
|
+
You can also create a composition from its code. The *code* of
|
|
73
|
+
a composition `(i_1, i_2, \ldots, i_k)` of `n` is a list of length `n`
|
|
74
|
+
that consists of a `1` followed by `i_1-1` zeros, then a `1` followed
|
|
75
|
+
by `i_2-1` zeros, and so on.
|
|
76
|
+
|
|
77
|
+
::
|
|
78
|
+
|
|
79
|
+
sage: Composition([4,1,2,3,5]).to_code()
|
|
80
|
+
[1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0]
|
|
81
|
+
sage: Composition(code=_)
|
|
82
|
+
[4, 1, 2, 3, 5]
|
|
83
|
+
sage: Composition([3,1,2,3,5]).to_code()
|
|
84
|
+
[1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0]
|
|
85
|
+
sage: Composition(code=_)
|
|
86
|
+
[3, 1, 2, 3, 5]
|
|
87
|
+
|
|
88
|
+
You can also create the composition of `n` corresponding to a subset of
|
|
89
|
+
`\{1, 2, \ldots, n-1\}` under the bijection that maps the composition
|
|
90
|
+
`(i_1, i_2, \ldots, i_k)` of `n` to the subset
|
|
91
|
+
`\{i_1, i_1 + i_2, i_1 + i_2 + i_3, \ldots, i_1 + \cdots + i_{k-1}\}`
|
|
92
|
+
(see :meth:`to_subset`)::
|
|
93
|
+
|
|
94
|
+
sage: Composition(from_subset=({1, 2, 4}, 5))
|
|
95
|
+
[1, 1, 2, 1]
|
|
96
|
+
sage: Composition([1, 1, 2, 1]).to_subset()
|
|
97
|
+
{1, 2, 4}
|
|
98
|
+
|
|
99
|
+
The following notation equivalently specifies the composition from the
|
|
100
|
+
set `\{i_1 - 1, i_1 + i_2 - 1, i_1 + i_2 + i_3 - 1, \dots, i_1 + \cdots
|
|
101
|
+
+ i_{k-1} - 1, n-1\}` or `\{i_1 - 1, i_1 + i_2 - 1, i_1 + i_2 + i_3
|
|
102
|
+
- 1, \dots, i_1 + \cdots + i_{k-1} - 1\}` and `n`. This provides
|
|
103
|
+
compatibility with Python's `0`-indexing.
|
|
104
|
+
|
|
105
|
+
::
|
|
106
|
+
|
|
107
|
+
sage: Composition(descents=[1,0,4,8,11])
|
|
108
|
+
[1, 1, 3, 4, 3]
|
|
109
|
+
sage: Composition(descents=[0,1,3,4])
|
|
110
|
+
[1, 1, 2, 1]
|
|
111
|
+
sage: Composition(descents=([0,1,3],5))
|
|
112
|
+
[1, 1, 2, 1]
|
|
113
|
+
sage: Composition(descents=({0,1,3},5))
|
|
114
|
+
[1, 1, 2, 1]
|
|
115
|
+
|
|
116
|
+
An integer composition may be regarded as a sequence. Thus it is an
|
|
117
|
+
instance of the Python abstract base class ``Sequence`` allows us to check if objects
|
|
118
|
+
behave "like" sequences based on implemented methods. Note that
|
|
119
|
+
``collections.abc.Sequence`` is not the same as
|
|
120
|
+
:class:`sage.structure.sequence.Sequence`::
|
|
121
|
+
|
|
122
|
+
sage: import collections.abc
|
|
123
|
+
sage: C = Composition([3,2,3])
|
|
124
|
+
sage: isinstance(C, collections.abc.Sequence)
|
|
125
|
+
True
|
|
126
|
+
sage: issubclass(C.__class__, collections.abc.Sequence)
|
|
127
|
+
True
|
|
128
|
+
|
|
129
|
+
Typically, instances of ``collections.abc.Sequence`` have a ``.count`` method.
|
|
130
|
+
``Composition.count`` counts the number of parts of a specified size::
|
|
131
|
+
|
|
132
|
+
sage: C.count(3)
|
|
133
|
+
2
|
|
134
|
+
|
|
135
|
+
EXAMPLES::
|
|
136
|
+
|
|
137
|
+
sage: C = Composition([3,1,2])
|
|
138
|
+
sage: TestSuite(C).run()
|
|
139
|
+
"""
|
|
140
|
+
@staticmethod
|
|
141
|
+
def __classcall_private__(cls, co=None, descents=None, code=None, from_subset=None):
|
|
142
|
+
"""
|
|
143
|
+
This constructs a list from optional arguments and delegates the
|
|
144
|
+
construction of a :class:`Composition` to the ``element_class()`` call
|
|
145
|
+
of the appropriate parent.
|
|
146
|
+
|
|
147
|
+
EXAMPLES::
|
|
148
|
+
|
|
149
|
+
sage: Composition([3,2,1])
|
|
150
|
+
[3, 2, 1]
|
|
151
|
+
sage: Composition(from_subset=({1, 2, 4}, 5))
|
|
152
|
+
[1, 1, 2, 1]
|
|
153
|
+
sage: Composition(descents=[1,0,4,8,11])
|
|
154
|
+
[1, 1, 3, 4, 3]
|
|
155
|
+
sage: Composition([4,1,2,3,5]).to_code()
|
|
156
|
+
[1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0]
|
|
157
|
+
sage: Composition(code=_)
|
|
158
|
+
[4, 1, 2, 3, 5]
|
|
159
|
+
|
|
160
|
+
TESTS:
|
|
161
|
+
|
|
162
|
+
Let us check that :issue:`14862` is solved::
|
|
163
|
+
|
|
164
|
+
sage: C = Compositions()
|
|
165
|
+
sage: C([3,-1,1])
|
|
166
|
+
Traceback (most recent call last):
|
|
167
|
+
...
|
|
168
|
+
ValueError: not a composition
|
|
169
|
+
sage: C("strawberry")
|
|
170
|
+
Traceback (most recent call last):
|
|
171
|
+
...
|
|
172
|
+
ValueError: not a composition
|
|
173
|
+
"""
|
|
174
|
+
if descents is not None:
|
|
175
|
+
if isinstance(descents, tuple):
|
|
176
|
+
return Compositions().from_descents(descents[0],
|
|
177
|
+
nps=descents[1])
|
|
178
|
+
else:
|
|
179
|
+
return Compositions().from_descents(descents)
|
|
180
|
+
elif code is not None:
|
|
181
|
+
return Compositions().from_code(code)
|
|
182
|
+
elif from_subset is not None:
|
|
183
|
+
return Compositions().from_subset(*from_subset)
|
|
184
|
+
elif isinstance(co, Composition):
|
|
185
|
+
return co
|
|
186
|
+
|
|
187
|
+
return Compositions()(co)
|
|
188
|
+
|
|
189
|
+
def __init__(self, parent, lst):
|
|
190
|
+
"""
|
|
191
|
+
Initialize ``self``.
|
|
192
|
+
|
|
193
|
+
EXAMPLES::
|
|
194
|
+
|
|
195
|
+
sage: C = Composition([3,1,2])
|
|
196
|
+
sage: TestSuite(C).run()
|
|
197
|
+
"""
|
|
198
|
+
lst = [Integer(u) for u in lst]
|
|
199
|
+
if not all(u >= 0 for u in lst):
|
|
200
|
+
raise ValueError("elements must be nonnegative integers")
|
|
201
|
+
CombinatorialElement.__init__(self, parent, lst)
|
|
202
|
+
|
|
203
|
+
def _ascii_art_(self):
|
|
204
|
+
"""
|
|
205
|
+
TESTS::
|
|
206
|
+
|
|
207
|
+
sage: # needs sage.combinat
|
|
208
|
+
sage: ascii_art(Compositions(4).list())
|
|
209
|
+
[ * ]
|
|
210
|
+
[ * ** * * ]
|
|
211
|
+
[ * * ** *** * ** * ]
|
|
212
|
+
[ *, * , * , * , **, ** , ***, **** ]
|
|
213
|
+
sage: Partitions.options(diagram_str='#', convention='French')
|
|
214
|
+
sage: ascii_art(Compositions(4).list())
|
|
215
|
+
[ # ]
|
|
216
|
+
[ # # # ## ]
|
|
217
|
+
[ # # ## # # ## ### ]
|
|
218
|
+
[ #, ##, #, ###, #, ##, #, #### ]
|
|
219
|
+
sage: Partitions.options._reset()
|
|
220
|
+
"""
|
|
221
|
+
from sage.typeset.ascii_art import ascii_art
|
|
222
|
+
return ascii_art(self.to_skew_partition())
|
|
223
|
+
|
|
224
|
+
def _unicode_art_(self):
|
|
225
|
+
"""
|
|
226
|
+
TESTS::
|
|
227
|
+
|
|
228
|
+
sage: # needs sage.combinat
|
|
229
|
+
sage: unicode_art(Compositions(4).list())
|
|
230
|
+
⎡ ┌┐ ⎤
|
|
231
|
+
⎢ ├┤ ┌┬┐ ┌┐ ┌┐ ⎥
|
|
232
|
+
⎢ ├┤ ├┼┘ ┌┼┤ ┌┬┬┐ ├┤ ┌┬┐ ┌┐ ⎥
|
|
233
|
+
⎢ ├┤ ├┤ ├┼┘ ├┼┴┘ ┌┼┤ ┌┼┼┘ ┌┬┼┤ ┌┬┬┬┐ ⎥
|
|
234
|
+
⎣ └┘, └┘ , └┘ , └┘ , └┴┘, └┴┘ , └┴┴┘, └┴┴┴┘ ⎦
|
|
235
|
+
sage: Partitions.options(diagram_str='#', convention='French')
|
|
236
|
+
sage: unicode_art(Compositions(4).list())
|
|
237
|
+
⎡ ┌┐ ⎤
|
|
238
|
+
⎢ ├┤ ┌┐ ┌┐ ┌┬┐ ⎥
|
|
239
|
+
⎢ ├┤ ├┤ ├┼┐ ┌┐ └┼┤ ┌┬┐ ┌┬┬┐ ⎥
|
|
240
|
+
⎢ ├┤ ├┼┐ └┼┤ ├┼┬┐ ├┤ └┼┼┐ └┴┼┤ ┌┬┬┬┐ ⎥
|
|
241
|
+
⎣ └┘, └┴┘, └┘, └┴┴┘, └┘, └┴┘, └┘, └┴┴┴┘ ⎦
|
|
242
|
+
sage: Partitions.options._reset()
|
|
243
|
+
"""
|
|
244
|
+
from sage.typeset.unicode_art import unicode_art
|
|
245
|
+
return unicode_art(self.to_skew_partition())
|
|
246
|
+
|
|
247
|
+
def __setstate__(self, state):
|
|
248
|
+
r"""
|
|
249
|
+
In order to maintain backwards compatibility and be able to unpickle a
|
|
250
|
+
old pickle from ``Composition_class`` we have to override the default
|
|
251
|
+
``__setstate__``.
|
|
252
|
+
|
|
253
|
+
EXAMPLES::
|
|
254
|
+
|
|
255
|
+
sage: loads(b"x\x9ck`J.NLO\xd5K\xce\xcfM\xca\xccK,\x011\n\xf2\x8b3K2\xf3\xf3\xb8\x9c\x11\xec\xf8\xe4\x9c\xc4\xe2b\xaeBF\xcd\xc6B\xa6\xdaBf\x8dP\xd6\xf8\x8c\xc4\xe2\x8cB\x16? +'\xb3\xb8\xa4\x905\xb6\x90M\x03bZQf^z\xb1^f^Ijzj\x11Wnbvj<\x8cS\xc8\x1e\xcah\xd8\x1aT\xc8\x91\x01d\x18\x01\x19\x9c\x19P\x11\xae\xd4\xd2$=\x00eW0g")
|
|
256
|
+
[1, 2, 1]
|
|
257
|
+
sage: loads(dumps( Composition([1,2,1]) )) # indirect doctest
|
|
258
|
+
[1, 2, 1]
|
|
259
|
+
"""
|
|
260
|
+
if isinstance(state, dict): # for old pickles from Composition_class
|
|
261
|
+
self._set_parent(Compositions())
|
|
262
|
+
self.__dict__ = state
|
|
263
|
+
else:
|
|
264
|
+
self._set_parent(state[0])
|
|
265
|
+
self.__dict__ = state[1]
|
|
266
|
+
|
|
267
|
+
@combinatorial_map(order=2, name='conjugate')
|
|
268
|
+
def conjugate(self) -> Composition:
|
|
269
|
+
r"""
|
|
270
|
+
Return the conjugate of the composition ``self``.
|
|
271
|
+
|
|
272
|
+
The conjugate of a composition `I` is defined as the
|
|
273
|
+
complement (see :meth:`complement`) of the reverse composition
|
|
274
|
+
(see :meth:`reversed`) of `I`.
|
|
275
|
+
|
|
276
|
+
An equivalent definition of the conjugate goes by saying that
|
|
277
|
+
the ribbon shape of the conjugate of a composition `I` is the
|
|
278
|
+
conjugate of the ribbon shape of `I`. (The ribbon shape of a
|
|
279
|
+
composition is returned by :meth:`to_skew_partition`.)
|
|
280
|
+
|
|
281
|
+
This implementation uses the algorithm from mupad-combinat.
|
|
282
|
+
|
|
283
|
+
EXAMPLES::
|
|
284
|
+
|
|
285
|
+
sage: Composition([1, 1, 3, 1, 2, 1, 3]).conjugate()
|
|
286
|
+
[1, 1, 3, 3, 1, 3]
|
|
287
|
+
|
|
288
|
+
The ribbon shape of the conjugate of `I` is the conjugate of
|
|
289
|
+
the ribbon shape of `I`::
|
|
290
|
+
|
|
291
|
+
sage: all( I.conjugate().to_skew_partition() # needs sage.combinat
|
|
292
|
+
....: == I.to_skew_partition().conjugate()
|
|
293
|
+
....: for I in Compositions(4) )
|
|
294
|
+
True
|
|
295
|
+
|
|
296
|
+
TESTS::
|
|
297
|
+
|
|
298
|
+
sage: parent(list(Compositions(1))[0].conjugate())
|
|
299
|
+
Compositions of 1
|
|
300
|
+
sage: parent(list(Compositions(0))[0].conjugate())
|
|
301
|
+
Compositions of 0
|
|
302
|
+
"""
|
|
303
|
+
comp = self
|
|
304
|
+
if not comp:
|
|
305
|
+
return self
|
|
306
|
+
n = len(comp)
|
|
307
|
+
coofcp = [sigmaj - j for j, sigmaj in enumerate(accumulate(comp))]
|
|
308
|
+
|
|
309
|
+
cocjg = []
|
|
310
|
+
for i in range(n - 1):
|
|
311
|
+
ni = n - i
|
|
312
|
+
cocjg += [i + 1 for _ in range(coofcp[ni - 1] - coofcp[ni - 2])]
|
|
313
|
+
cocjg += [n for j in range(coofcp[0])]
|
|
314
|
+
|
|
315
|
+
return self.parent()([cocjg[0]] + [cocjg[i] - cocjg[i - 1] + 1
|
|
316
|
+
for i in range(1, len(cocjg))])
|
|
317
|
+
|
|
318
|
+
@combinatorial_map(order=2, name='reversed')
|
|
319
|
+
def reversed(self) -> Composition:
|
|
320
|
+
r"""
|
|
321
|
+
Return the reverse composition of ``self``.
|
|
322
|
+
|
|
323
|
+
The reverse composition of a composition `(i_1, i_2, \ldots, i_k)`
|
|
324
|
+
is defined as the composition `(i_k, i_{k-1}, \ldots, i_1)`.
|
|
325
|
+
|
|
326
|
+
EXAMPLES::
|
|
327
|
+
|
|
328
|
+
sage: Composition([1, 1, 3, 1, 2, 1, 3]).reversed()
|
|
329
|
+
[3, 1, 2, 1, 3, 1, 1]
|
|
330
|
+
"""
|
|
331
|
+
return self.parent()(reversed(self))
|
|
332
|
+
|
|
333
|
+
@combinatorial_map(order=2, name='complement')
|
|
334
|
+
def complement(self) -> Composition:
|
|
335
|
+
r"""
|
|
336
|
+
Return the complement of the composition ``self``.
|
|
337
|
+
|
|
338
|
+
The complement of a composition `I` is defined as follows:
|
|
339
|
+
|
|
340
|
+
If `I` is the empty composition, then the complement is the empty
|
|
341
|
+
composition as well. Otherwise, let `S` be the descent set of `I`
|
|
342
|
+
(that is, the subset
|
|
343
|
+
`\{ i_1, i_1 + i_2, \ldots, i_1 + i_2 + \cdots + i_{k-1} \}`
|
|
344
|
+
of `\{ 1, 2, \ldots, |I|-1 \}`, where `I` is written as
|
|
345
|
+
`(i_1, i_2, \ldots, i_k)`). Then, the complement of `I` is
|
|
346
|
+
defined as the composition of size `|I|` whose descent set is
|
|
347
|
+
`\{ 1, 2, \ldots, |I|-1 \} \setminus S`.
|
|
348
|
+
|
|
349
|
+
The complement of a composition `I` also is the reverse
|
|
350
|
+
composition (:meth:`reversed`) of the conjugate
|
|
351
|
+
(:meth:`conjugate`) of `I`.
|
|
352
|
+
|
|
353
|
+
EXAMPLES::
|
|
354
|
+
|
|
355
|
+
sage: Composition([1, 1, 3, 1, 2, 1, 3]).conjugate()
|
|
356
|
+
[1, 1, 3, 3, 1, 3]
|
|
357
|
+
sage: Composition([1, 1, 3, 1, 2, 1, 3]).complement()
|
|
358
|
+
[3, 1, 3, 3, 1, 1]
|
|
359
|
+
"""
|
|
360
|
+
return self.conjugate().reversed()
|
|
361
|
+
|
|
362
|
+
def __add__(self, other) -> Composition:
|
|
363
|
+
"""
|
|
364
|
+
Return the concatenation of two compositions.
|
|
365
|
+
|
|
366
|
+
EXAMPLES::
|
|
367
|
+
|
|
368
|
+
sage: Composition([1, 1, 3]) + Composition([4, 1, 2])
|
|
369
|
+
[1, 1, 3, 4, 1, 2]
|
|
370
|
+
|
|
371
|
+
TESTS::
|
|
372
|
+
|
|
373
|
+
sage: Composition([]) + Composition([]) == Composition([])
|
|
374
|
+
True
|
|
375
|
+
"""
|
|
376
|
+
return Compositions()(list(self) + list(other))
|
|
377
|
+
|
|
378
|
+
def size(self) -> int:
|
|
379
|
+
"""
|
|
380
|
+
Return the size of ``self``, that is the sum of its parts.
|
|
381
|
+
|
|
382
|
+
EXAMPLES::
|
|
383
|
+
|
|
384
|
+
sage: Composition([7,1,3]).size()
|
|
385
|
+
11
|
|
386
|
+
"""
|
|
387
|
+
return sum(self)
|
|
388
|
+
|
|
389
|
+
@staticmethod
|
|
390
|
+
def sum(compositions) -> Composition:
|
|
391
|
+
"""
|
|
392
|
+
Return the concatenation of the given compositions.
|
|
393
|
+
|
|
394
|
+
INPUT:
|
|
395
|
+
|
|
396
|
+
- ``compositions`` -- list (or iterable) of compositions
|
|
397
|
+
|
|
398
|
+
EXAMPLES::
|
|
399
|
+
|
|
400
|
+
sage: Composition.sum([Composition([1, 1, 3]), Composition([4, 1, 2]), Composition([3,1])])
|
|
401
|
+
[1, 1, 3, 4, 1, 2, 3, 1]
|
|
402
|
+
|
|
403
|
+
Any iterable can be provided as input::
|
|
404
|
+
|
|
405
|
+
sage: Composition.sum([Composition([i,i]) for i in [4,1,3]])
|
|
406
|
+
[4, 4, 1, 1, 3, 3]
|
|
407
|
+
|
|
408
|
+
Empty inputs are handled gracefully::
|
|
409
|
+
|
|
410
|
+
sage: Composition.sum([]) == Composition([])
|
|
411
|
+
True
|
|
412
|
+
"""
|
|
413
|
+
return sum(compositions, Compositions()([]))
|
|
414
|
+
|
|
415
|
+
def near_concatenation(self, other):
|
|
416
|
+
r"""
|
|
417
|
+
Return the near-concatenation of two nonempty compositions
|
|
418
|
+
``self`` and ``other``.
|
|
419
|
+
|
|
420
|
+
The near-concatenation `I \odot J` of two nonempty compositions
|
|
421
|
+
`I` and `J` is defined as the composition
|
|
422
|
+
`(i_1, i_2, \ldots , i_{n-1}, i_n + j_1, j_2, j_3, \ldots , j_m)`,
|
|
423
|
+
where `(i_1, i_2, \ldots , i_n) = I` and
|
|
424
|
+
`(j_1, j_2, \ldots , j_m) = J`.
|
|
425
|
+
|
|
426
|
+
This method returns ``None`` if one of the two input
|
|
427
|
+
compositions is empty.
|
|
428
|
+
|
|
429
|
+
EXAMPLES::
|
|
430
|
+
|
|
431
|
+
sage: Composition([1, 1, 3]).near_concatenation(Composition([4, 1, 2]))
|
|
432
|
+
[1, 1, 7, 1, 2]
|
|
433
|
+
sage: Composition([6]).near_concatenation(Composition([1, 5]))
|
|
434
|
+
[7, 5]
|
|
435
|
+
sage: Composition([1, 5]).near_concatenation(Composition([6]))
|
|
436
|
+
[1, 11]
|
|
437
|
+
|
|
438
|
+
TESTS::
|
|
439
|
+
|
|
440
|
+
sage: Composition([]).near_concatenation(Composition([]))
|
|
441
|
+
<BLANKLINE>
|
|
442
|
+
sage: Composition([]).near_concatenation(Composition([2, 1]))
|
|
443
|
+
<BLANKLINE>
|
|
444
|
+
sage: Composition([3, 2]).near_concatenation(Composition([]))
|
|
445
|
+
<BLANKLINE>
|
|
446
|
+
"""
|
|
447
|
+
if not self or not other:
|
|
448
|
+
return None
|
|
449
|
+
return Compositions()(list(self)[:-1] + [self[-1] + other[0]] + list(other)[1:])
|
|
450
|
+
|
|
451
|
+
def ribbon_decomposition(self, other, check=True):
|
|
452
|
+
r"""
|
|
453
|
+
Return a pair describing the ribbon decomposition of a composition
|
|
454
|
+
``self`` with respect to a composition ``other`` of the same size.
|
|
455
|
+
|
|
456
|
+
If `I` and `J` are two compositions of the same nonzero size, then
|
|
457
|
+
the ribbon decomposition of `I` with respect to `J` is defined as
|
|
458
|
+
follows: Write `I` and `J` as `I = (i_1, i_2, \ldots , i_n)` and
|
|
459
|
+
`J = (j_1, j_2, \ldots , j_m)`. Then, the equality
|
|
460
|
+
`I = I_1 \bullet I_2 \bullet \ldots \bullet I_m` holds for a
|
|
461
|
+
unique `m`-tuple `(I_1, I_2, \ldots , I_m)` of compositions such
|
|
462
|
+
that each `I_k` has size `j_k` and for a unique choice of `m-1`
|
|
463
|
+
signs `\bullet` each of which is either the concatenation sign
|
|
464
|
+
`\cdot` or the near-concatenation sign `\odot` (see
|
|
465
|
+
:meth:`__add__` and :meth:`near_concatenation` for the definitions
|
|
466
|
+
of these two signs). This `m`-tuple and this choice of signs
|
|
467
|
+
together are said to form the ribbon decomposition of `I` with
|
|
468
|
+
respect to `J`. If `I` and `J` are empty, then the same definition
|
|
469
|
+
applies, except that there are `0` rather than `m-1` signs.
|
|
470
|
+
|
|
471
|
+
See Section 4.8 of [NCSF1]_.
|
|
472
|
+
|
|
473
|
+
INPUT:
|
|
474
|
+
|
|
475
|
+
- ``other`` -- composition of same size as ``self``
|
|
476
|
+
|
|
477
|
+
- ``check`` -- boolean (default: ``True``); whether to check the input
|
|
478
|
+
compositions for having the same size
|
|
479
|
+
|
|
480
|
+
OUTPUT:
|
|
481
|
+
|
|
482
|
+
- a pair ``(u, v)``, where ``u`` is a tuple of compositions
|
|
483
|
+
(corresponding to the `m`-tuple `(I_1, I_2, \ldots , I_m)` in
|
|
484
|
+
the above definition), and ``v`` is a tuple of `0`s and `1`s
|
|
485
|
+
(encoding the choice of signs `\bullet` in the above definition,
|
|
486
|
+
with a `0` standing for `\cdot` and a `1` standing for `\odot`).
|
|
487
|
+
|
|
488
|
+
EXAMPLES::
|
|
489
|
+
|
|
490
|
+
sage: Composition([3, 1, 1, 3, 1]).ribbon_decomposition([4, 3, 2])
|
|
491
|
+
(([3, 1], [1, 2], [1, 1]), (0, 1))
|
|
492
|
+
sage: Composition([9, 6]).ribbon_decomposition([1, 3, 6, 3, 2])
|
|
493
|
+
(([1], [3], [5, 1], [3], [2]), (1, 1, 1, 1))
|
|
494
|
+
sage: Composition([9, 6]).ribbon_decomposition([1, 3, 5, 1, 3, 2])
|
|
495
|
+
(([1], [3], [5], [1], [3], [2]), (1, 1, 0, 1, 1))
|
|
496
|
+
sage: Composition([1, 1, 1, 1, 1]).ribbon_decomposition([3, 2])
|
|
497
|
+
(([1, 1, 1], [1, 1]), (0,))
|
|
498
|
+
sage: Composition([4, 2]).ribbon_decomposition([6])
|
|
499
|
+
(([4, 2],), ())
|
|
500
|
+
sage: Composition([]).ribbon_decomposition([])
|
|
501
|
+
((), ())
|
|
502
|
+
|
|
503
|
+
Let us check that the defining property
|
|
504
|
+
`I = I_1 \bullet I_2 \bullet \ldots \bullet I_m` is satisfied::
|
|
505
|
+
|
|
506
|
+
sage: def compose_back(u, v):
|
|
507
|
+
....: comp = u[0]
|
|
508
|
+
....: r = len(v)
|
|
509
|
+
....: if len(u) != r + 1:
|
|
510
|
+
....: raise ValueError("something is wrong")
|
|
511
|
+
....: for i in range(r):
|
|
512
|
+
....: if v[i] == 0:
|
|
513
|
+
....: comp += u[i + 1]
|
|
514
|
+
....: else:
|
|
515
|
+
....: comp = comp.near_concatenation(u[i + 1])
|
|
516
|
+
....: return comp
|
|
517
|
+
sage: all( all( all( compose_back(*(I.ribbon_decomposition(J))) == I
|
|
518
|
+
....: for J in Compositions(n) )
|
|
519
|
+
....: for I in Compositions(n) )
|
|
520
|
+
....: for n in range(1, 5) )
|
|
521
|
+
True
|
|
522
|
+
|
|
523
|
+
TESTS::
|
|
524
|
+
|
|
525
|
+
sage: Composition([3, 1, 1, 3, 1]).ribbon_decomposition([4, 3, 1])
|
|
526
|
+
Traceback (most recent call last):
|
|
527
|
+
...
|
|
528
|
+
ValueError: [3, 1, 1, 3, 1] is not the same size as [4, 3, 1]
|
|
529
|
+
|
|
530
|
+
AUTHORS:
|
|
531
|
+
|
|
532
|
+
- Darij Grinberg (2013-08-29)
|
|
533
|
+
"""
|
|
534
|
+
# Speaking in terms of the definition in the docstring, we have
|
|
535
|
+
# I = self and J = other.
|
|
536
|
+
|
|
537
|
+
if check and (sum(self) != sum(other)):
|
|
538
|
+
raise ValueError("{} is not the same size as {}".format(self, other))
|
|
539
|
+
|
|
540
|
+
factors = []
|
|
541
|
+
signs = []
|
|
542
|
+
|
|
543
|
+
I_iter = iter(self)
|
|
544
|
+
i = 0
|
|
545
|
+
for j in other:
|
|
546
|
+
current_factor = []
|
|
547
|
+
current_factor_size = 0
|
|
548
|
+
while True:
|
|
549
|
+
if i == 0:
|
|
550
|
+
try:
|
|
551
|
+
i = next(I_iter)
|
|
552
|
+
except StopIteration:
|
|
553
|
+
factors.append(Compositions()(current_factor))
|
|
554
|
+
return (tuple(factors), tuple(signs))
|
|
555
|
+
if current_factor_size + i <= j:
|
|
556
|
+
current_factor.append(i)
|
|
557
|
+
current_factor_size += i
|
|
558
|
+
i = 0
|
|
559
|
+
else:
|
|
560
|
+
if j == current_factor_size:
|
|
561
|
+
signs.append(0)
|
|
562
|
+
else:
|
|
563
|
+
current_factor.append(j - current_factor_size)
|
|
564
|
+
i -= j - current_factor_size
|
|
565
|
+
signs.append(1)
|
|
566
|
+
factors.append(Compositions()(current_factor))
|
|
567
|
+
break
|
|
568
|
+
|
|
569
|
+
return (tuple(factors), tuple(signs))
|
|
570
|
+
|
|
571
|
+
def join(self, other, check=True) -> Composition:
|
|
572
|
+
r"""
|
|
573
|
+
Return the join of ``self`` with a composition ``other`` of the
|
|
574
|
+
same size.
|
|
575
|
+
|
|
576
|
+
The join of two compositions `I` and `J` of size `n` is the
|
|
577
|
+
coarsest composition of `n` which refines each of `I` and `J`. It
|
|
578
|
+
can be described as the composition whose descent set is the
|
|
579
|
+
union of the descent sets of `I` and `J`. It is also the
|
|
580
|
+
concatenation of `I_1, I_2, \cdots , I_m`, where
|
|
581
|
+
`I = I_1 \bullet I_2 \bullet \ldots \bullet I_m` is the ribbon
|
|
582
|
+
decomposition of `I` with respect to `J` (see
|
|
583
|
+
:meth:`ribbon_decomposition`).
|
|
584
|
+
|
|
585
|
+
INPUT:
|
|
586
|
+
|
|
587
|
+
- ``other`` -- composition of same size as ``self``
|
|
588
|
+
|
|
589
|
+
- ``check`` -- boolean (default: ``True``); whether to check the input
|
|
590
|
+
compositions for having the same size
|
|
591
|
+
|
|
592
|
+
OUTPUT: the join of the compositions ``self`` and ``other``
|
|
593
|
+
|
|
594
|
+
EXAMPLES::
|
|
595
|
+
|
|
596
|
+
sage: Composition([3, 1, 1, 3, 1]).join([4, 3, 2])
|
|
597
|
+
[3, 1, 1, 2, 1, 1]
|
|
598
|
+
sage: Composition([9, 6]).join([1, 3, 6, 3, 2])
|
|
599
|
+
[1, 3, 5, 1, 3, 2]
|
|
600
|
+
sage: Composition([9, 6]).join([1, 3, 5, 1, 3, 2])
|
|
601
|
+
[1, 3, 5, 1, 3, 2]
|
|
602
|
+
sage: Composition([1, 1, 1, 1, 1]).join([3, 2])
|
|
603
|
+
[1, 1, 1, 1, 1]
|
|
604
|
+
sage: Composition([4, 2]).join([3, 3])
|
|
605
|
+
[3, 1, 2]
|
|
606
|
+
sage: Composition([]).join([])
|
|
607
|
+
[]
|
|
608
|
+
|
|
609
|
+
Let us verify on small examples that the join
|
|
610
|
+
of `I` and `J` refines both of `I` and `J`::
|
|
611
|
+
|
|
612
|
+
sage: all( all( I.join(J).is_finer(I) and
|
|
613
|
+
....: I.join(J).is_finer(J)
|
|
614
|
+
....: for J in Compositions(4) )
|
|
615
|
+
....: for I in Compositions(4) )
|
|
616
|
+
True
|
|
617
|
+
|
|
618
|
+
and is the coarsest composition to do so::
|
|
619
|
+
|
|
620
|
+
sage: all( all( all( K.is_finer(I.join(J))
|
|
621
|
+
....: for K in I.finer()
|
|
622
|
+
....: if K.is_finer(J) )
|
|
623
|
+
....: for J in Compositions(3) )
|
|
624
|
+
....: for I in Compositions(3) )
|
|
625
|
+
True
|
|
626
|
+
|
|
627
|
+
Let us check that the join of `I` and `J` is indeed the
|
|
628
|
+
concatenation of `I_1, I_2, \cdots , I_m`, where
|
|
629
|
+
`I = I_1 \bullet I_2 \bullet \ldots \bullet I_m` is the ribbon
|
|
630
|
+
decomposition of `I` with respect to `J`::
|
|
631
|
+
|
|
632
|
+
sage: all( all( Composition.sum(I.ribbon_decomposition(J)[0])
|
|
633
|
+
....: == I.join(J) for J in Compositions(4) )
|
|
634
|
+
....: for I in Compositions(4) )
|
|
635
|
+
True
|
|
636
|
+
|
|
637
|
+
Also, the descent set of the join of `I` and `J` is the
|
|
638
|
+
union of the descent sets of `I` and `J`::
|
|
639
|
+
|
|
640
|
+
sage: all( all( I.to_subset().union(J.to_subset())
|
|
641
|
+
....: == I.join(J).to_subset()
|
|
642
|
+
....: for J in Compositions(4) )
|
|
643
|
+
....: for I in Compositions(4) )
|
|
644
|
+
True
|
|
645
|
+
|
|
646
|
+
TESTS::
|
|
647
|
+
|
|
648
|
+
sage: Composition([3, 1, 1, 3, 1]).join([4, 3, 1])
|
|
649
|
+
Traceback (most recent call last):
|
|
650
|
+
...
|
|
651
|
+
ValueError: [3, 1, 1, 3, 1] is not the same size as [4, 3, 1]
|
|
652
|
+
|
|
653
|
+
.. SEEALSO::
|
|
654
|
+
|
|
655
|
+
:meth:`meet`, :meth:`ribbon_decomposition`
|
|
656
|
+
|
|
657
|
+
AUTHORS:
|
|
658
|
+
|
|
659
|
+
- Darij Grinberg (2013-09-05)
|
|
660
|
+
"""
|
|
661
|
+
# The following code is a slimmed down version of the
|
|
662
|
+
# ribbon_decomposition method. It is a lot faster than
|
|
663
|
+
# using to_subset() and from_subset, and also a lot
|
|
664
|
+
# faster than ribbon_decomposition.
|
|
665
|
+
|
|
666
|
+
# Speaking in terms of the definition in the docstring, we have
|
|
667
|
+
# I = self and J = other.
|
|
668
|
+
|
|
669
|
+
if check and (sum(self) != sum(other)):
|
|
670
|
+
raise ValueError("{} is not the same size as {}".format(self, other))
|
|
671
|
+
|
|
672
|
+
factors: list[int] = []
|
|
673
|
+
|
|
674
|
+
I_iter = iter(self)
|
|
675
|
+
i = 0
|
|
676
|
+
for j in other:
|
|
677
|
+
current_factor_size = 0
|
|
678
|
+
while True:
|
|
679
|
+
if i == 0:
|
|
680
|
+
try:
|
|
681
|
+
i = next(I_iter)
|
|
682
|
+
except StopIteration:
|
|
683
|
+
return Compositions()(factors)
|
|
684
|
+
if current_factor_size + i <= j:
|
|
685
|
+
factors.append(i)
|
|
686
|
+
current_factor_size += i
|
|
687
|
+
i = 0
|
|
688
|
+
else:
|
|
689
|
+
if not j == current_factor_size:
|
|
690
|
+
factors.append(j - current_factor_size)
|
|
691
|
+
i -= j - current_factor_size
|
|
692
|
+
break
|
|
693
|
+
|
|
694
|
+
return self.parent()(factors)
|
|
695
|
+
|
|
696
|
+
sup = join
|
|
697
|
+
|
|
698
|
+
def meet(self, other, check=True) -> Composition:
|
|
699
|
+
r"""
|
|
700
|
+
Return the meet of ``self`` with a composition ``other`` of the
|
|
701
|
+
same size.
|
|
702
|
+
|
|
703
|
+
The meet of two compositions `I` and `J` of size `n` is the
|
|
704
|
+
finest composition of `n` which is coarser than each of `I` and
|
|
705
|
+
`J`. It can be described as the composition whose descent set is
|
|
706
|
+
the intersection of the descent sets of `I` and `J`.
|
|
707
|
+
|
|
708
|
+
INPUT:
|
|
709
|
+
|
|
710
|
+
- ``other`` -- composition of same size as ``self``
|
|
711
|
+
|
|
712
|
+
- ``check`` -- boolean (default: ``True``); whether to check the input
|
|
713
|
+
compositions for having the same size
|
|
714
|
+
|
|
715
|
+
OUTPUT: the meet of the compositions ``self`` and ``other``
|
|
716
|
+
|
|
717
|
+
EXAMPLES::
|
|
718
|
+
|
|
719
|
+
sage: Composition([3, 1, 1, 3, 1]).meet([4, 3, 2])
|
|
720
|
+
[4, 5]
|
|
721
|
+
sage: Composition([9, 6]).meet([1, 3, 6, 3, 2])
|
|
722
|
+
[15]
|
|
723
|
+
sage: Composition([9, 6]).meet([1, 3, 5, 1, 3, 2])
|
|
724
|
+
[9, 6]
|
|
725
|
+
sage: Composition([1, 1, 1, 1, 1]).meet([3, 2])
|
|
726
|
+
[3, 2]
|
|
727
|
+
sage: Composition([4, 2]).meet([3, 3])
|
|
728
|
+
[6]
|
|
729
|
+
sage: Composition([]).meet([])
|
|
730
|
+
[]
|
|
731
|
+
sage: Composition([1]).meet([1])
|
|
732
|
+
[1]
|
|
733
|
+
|
|
734
|
+
Let us verify on small examples that the meet
|
|
735
|
+
of `I` and `J` is coarser than both of `I` and `J`::
|
|
736
|
+
|
|
737
|
+
sage: all( all( I.is_finer(I.meet(J)) and
|
|
738
|
+
....: J.is_finer(I.meet(J))
|
|
739
|
+
....: for J in Compositions(4) )
|
|
740
|
+
....: for I in Compositions(4) )
|
|
741
|
+
True
|
|
742
|
+
|
|
743
|
+
and is the finest composition to do so::
|
|
744
|
+
|
|
745
|
+
sage: all( all( all( I.meet(J).is_finer(K)
|
|
746
|
+
....: for K in I.fatter()
|
|
747
|
+
....: if J.is_finer(K) )
|
|
748
|
+
....: for J in Compositions(3) )
|
|
749
|
+
....: for I in Compositions(3) )
|
|
750
|
+
True
|
|
751
|
+
|
|
752
|
+
The descent set of the meet of `I` and `J` is the
|
|
753
|
+
intersection of the descent sets of `I` and `J`::
|
|
754
|
+
|
|
755
|
+
sage: def test_meet(n):
|
|
756
|
+
....: return all( all( I.to_subset().intersection(J.to_subset())
|
|
757
|
+
....: == I.meet(J).to_subset()
|
|
758
|
+
....: for J in Compositions(n) )
|
|
759
|
+
....: for I in Compositions(n) )
|
|
760
|
+
sage: all( test_meet(n) for n in range(1, 5) )
|
|
761
|
+
True
|
|
762
|
+
|
|
763
|
+
TESTS::
|
|
764
|
+
|
|
765
|
+
sage: Composition([3, 1, 1, 3, 1]).meet([4, 3, 1])
|
|
766
|
+
Traceback (most recent call last):
|
|
767
|
+
...
|
|
768
|
+
ValueError: [3, 1, 1, 3, 1] is not the same size as [4, 3, 1]
|
|
769
|
+
|
|
770
|
+
.. SEEALSO::
|
|
771
|
+
|
|
772
|
+
:meth:`join`
|
|
773
|
+
|
|
774
|
+
AUTHORS:
|
|
775
|
+
|
|
776
|
+
- Darij Grinberg (2013-09-05)
|
|
777
|
+
"""
|
|
778
|
+
# The following code is much faster than using to_subset()
|
|
779
|
+
# and from_subset.
|
|
780
|
+
|
|
781
|
+
# Speaking in terms of the definition in the docstring, we have
|
|
782
|
+
# I = self and J = other.
|
|
783
|
+
|
|
784
|
+
if check and (sum(self) != sum(other)):
|
|
785
|
+
raise ValueError("{} is not the same size as {}".format(self, other))
|
|
786
|
+
|
|
787
|
+
factors = []
|
|
788
|
+
current_part = 0
|
|
789
|
+
|
|
790
|
+
I_iter = iter(self)
|
|
791
|
+
i = 0
|
|
792
|
+
for j in other:
|
|
793
|
+
current_factor_size = 0
|
|
794
|
+
while True:
|
|
795
|
+
if i == 0:
|
|
796
|
+
try:
|
|
797
|
+
i = next(I_iter)
|
|
798
|
+
except StopIteration:
|
|
799
|
+
factors.append(current_part)
|
|
800
|
+
return Compositions()(factors)
|
|
801
|
+
if current_factor_size + i <= j:
|
|
802
|
+
current_part += i
|
|
803
|
+
current_factor_size += i
|
|
804
|
+
i = 0
|
|
805
|
+
else:
|
|
806
|
+
if j == current_factor_size:
|
|
807
|
+
factors.append(current_part)
|
|
808
|
+
current_part = 0
|
|
809
|
+
else:
|
|
810
|
+
i -= j - current_factor_size
|
|
811
|
+
current_part += j - current_factor_size
|
|
812
|
+
break
|
|
813
|
+
|
|
814
|
+
return self.parent()(factors)
|
|
815
|
+
|
|
816
|
+
inf = meet
|
|
817
|
+
|
|
818
|
+
def finer(self):
|
|
819
|
+
"""
|
|
820
|
+
Return the set of compositions which are finer than ``self``.
|
|
821
|
+
|
|
822
|
+
EXAMPLES::
|
|
823
|
+
|
|
824
|
+
sage: C = Composition([3,2]).finer()
|
|
825
|
+
sage: C.cardinality()
|
|
826
|
+
8
|
|
827
|
+
sage: C.list()
|
|
828
|
+
[[1, 1, 1, 1, 1], [1, 1, 1, 2], [1, 2, 1, 1], [1, 2, 2], [2, 1, 1, 1], [2, 1, 2], [3, 1, 1], [3, 2]]
|
|
829
|
+
|
|
830
|
+
sage: Composition([]).finer()
|
|
831
|
+
{[]}
|
|
832
|
+
"""
|
|
833
|
+
if not self:
|
|
834
|
+
return FiniteEnumeratedSet([self])
|
|
835
|
+
else:
|
|
836
|
+
return cartesian_product([Compositions(i) for i in self]).map(Composition.sum)
|
|
837
|
+
|
|
838
|
+
def is_finer(self, co2) -> bool:
|
|
839
|
+
"""
|
|
840
|
+
Return ``True`` if the composition ``self`` is finer than the
|
|
841
|
+
composition ``co2``; otherwise, return ``False``.
|
|
842
|
+
|
|
843
|
+
EXAMPLES::
|
|
844
|
+
|
|
845
|
+
sage: Composition([4,1,2]).is_finer([3,1,3])
|
|
846
|
+
False
|
|
847
|
+
sage: Composition([3,1,3]).is_finer([4,1,2])
|
|
848
|
+
False
|
|
849
|
+
sage: Composition([1,2,2,1,1,2]).is_finer([5,1,3])
|
|
850
|
+
True
|
|
851
|
+
sage: Composition([2,2,2]).is_finer([4,2])
|
|
852
|
+
True
|
|
853
|
+
"""
|
|
854
|
+
co1 = self
|
|
855
|
+
if sum(co1) != sum(co2):
|
|
856
|
+
raise ValueError("compositions self (= %s) and co2 (= %s) must be of the same size" % (self, co2))
|
|
857
|
+
|
|
858
|
+
sum1 = 0
|
|
859
|
+
sum2 = 0
|
|
860
|
+
i1 = 0
|
|
861
|
+
for j2 in co2:
|
|
862
|
+
sum2 += j2
|
|
863
|
+
while sum1 < sum2:
|
|
864
|
+
sum1 += co1[i1]
|
|
865
|
+
i1 += 1
|
|
866
|
+
if sum1 > sum2:
|
|
867
|
+
return False
|
|
868
|
+
|
|
869
|
+
return True
|
|
870
|
+
|
|
871
|
+
def fatten(self, grouping) -> Composition:
|
|
872
|
+
r"""
|
|
873
|
+
Return the composition fatter than ``self``, obtained by grouping
|
|
874
|
+
together consecutive parts according to ``grouping``.
|
|
875
|
+
|
|
876
|
+
INPUT:
|
|
877
|
+
|
|
878
|
+
- ``grouping`` -- a composition whose sum is the length of ``self``
|
|
879
|
+
|
|
880
|
+
EXAMPLES:
|
|
881
|
+
|
|
882
|
+
Let us start with the composition::
|
|
883
|
+
|
|
884
|
+
sage: c = Composition([4,5,2,7,1])
|
|
885
|
+
|
|
886
|
+
With ``grouping`` equal to `(1, \ldots, 1)`, `c` is left unchanged::
|
|
887
|
+
|
|
888
|
+
sage: c.fatten(Composition([1,1,1,1,1]))
|
|
889
|
+
[4, 5, 2, 7, 1]
|
|
890
|
+
|
|
891
|
+
With ``grouping`` equal to `(\ell)` where `\ell` is the length of
|
|
892
|
+
`c`, this yields the coarsest composition above `c`::
|
|
893
|
+
|
|
894
|
+
sage: c.fatten(Composition([5]))
|
|
895
|
+
[19]
|
|
896
|
+
|
|
897
|
+
Other values for ``grouping`` yield (all the) other compositions
|
|
898
|
+
coarser than `c`::
|
|
899
|
+
|
|
900
|
+
sage: c.fatten(Composition([2,1,2]))
|
|
901
|
+
[9, 2, 8]
|
|
902
|
+
sage: c.fatten(Composition([3,1,1]))
|
|
903
|
+
[11, 7, 1]
|
|
904
|
+
|
|
905
|
+
TESTS::
|
|
906
|
+
|
|
907
|
+
sage: Composition([]).fatten(Composition([]))
|
|
908
|
+
[]
|
|
909
|
+
sage: c.fatten(Composition([3,1,1])).__class__ == c.__class__
|
|
910
|
+
True
|
|
911
|
+
"""
|
|
912
|
+
parent = self.parent()
|
|
913
|
+
result = [0] * len(grouping)
|
|
914
|
+
j = 0
|
|
915
|
+
for i, gi in enumerate(grouping):
|
|
916
|
+
result[i] = sum(self[j:j + gi])
|
|
917
|
+
j += gi
|
|
918
|
+
return parent(result)
|
|
919
|
+
|
|
920
|
+
def fatter(self):
|
|
921
|
+
"""
|
|
922
|
+
Return the set of compositions which are fatter than ``self``.
|
|
923
|
+
|
|
924
|
+
Complexity for generation: `O(|c|)` memory, `O(|r|)` time where `|c|`
|
|
925
|
+
is the size of ``self`` and `r` is the result.
|
|
926
|
+
|
|
927
|
+
EXAMPLES::
|
|
928
|
+
|
|
929
|
+
sage: C = Composition([4,5,2]).fatter()
|
|
930
|
+
sage: C.cardinality()
|
|
931
|
+
4
|
|
932
|
+
sage: list(C)
|
|
933
|
+
[[4, 5, 2], [4, 7], [9, 2], [11]]
|
|
934
|
+
|
|
935
|
+
Some extreme cases::
|
|
936
|
+
|
|
937
|
+
sage: list(Composition([5]).fatter())
|
|
938
|
+
[[5]]
|
|
939
|
+
sage: list(Composition([]).fatter())
|
|
940
|
+
[[]]
|
|
941
|
+
sage: list(Composition([1,1,1,1]).fatter()) == list(Compositions(4))
|
|
942
|
+
True
|
|
943
|
+
"""
|
|
944
|
+
return Compositions(len(self)).map(self.fatten)
|
|
945
|
+
|
|
946
|
+
def refinement_splitting(self, J) -> list[Composition]:
|
|
947
|
+
r"""
|
|
948
|
+
Return the refinement splitting of ``self`` according to ``J``.
|
|
949
|
+
|
|
950
|
+
INPUT:
|
|
951
|
+
|
|
952
|
+
- ``J`` -- a composition such that ``self`` is finer than ``J``
|
|
953
|
+
|
|
954
|
+
OUTPUT:
|
|
955
|
+
|
|
956
|
+
- the unique list of compositions `(I^{(p)})_{p=1, \ldots , m}`,
|
|
957
|
+
obtained by splitting `I`, such that
|
|
958
|
+
`|I^{(p)}| = J_p` for all `p = 1, \ldots, m`.
|
|
959
|
+
|
|
960
|
+
.. SEEALSO::
|
|
961
|
+
|
|
962
|
+
:meth:`refinement_splitting_lengths`
|
|
963
|
+
|
|
964
|
+
EXAMPLES::
|
|
965
|
+
|
|
966
|
+
sage: Composition([1,2,2,1,1,2]).refinement_splitting([5,1,3])
|
|
967
|
+
[[1, 2, 2], [1], [1, 2]]
|
|
968
|
+
sage: Composition([]).refinement_splitting([])
|
|
969
|
+
[]
|
|
970
|
+
sage: Composition([3]).refinement_splitting([2])
|
|
971
|
+
Traceback (most recent call last):
|
|
972
|
+
...
|
|
973
|
+
ValueError: compositions self (= [3]) and J (= [2]) must be of the same size
|
|
974
|
+
sage: Composition([2,1]).refinement_splitting([1,2])
|
|
975
|
+
Traceback (most recent call last):
|
|
976
|
+
...
|
|
977
|
+
ValueError: composition J (= [2, 1]) does not refine self (= [1, 2])
|
|
978
|
+
"""
|
|
979
|
+
I = self
|
|
980
|
+
if sum(I) != sum(J):
|
|
981
|
+
# Error: compositions are not of the same size
|
|
982
|
+
raise ValueError("compositions self (= %s) and J (= %s) must be of the same size" % (I, J))
|
|
983
|
+
sum1 = 0
|
|
984
|
+
sum2 = 0
|
|
985
|
+
i1 = -1
|
|
986
|
+
decomp = []
|
|
987
|
+
for j2 in J:
|
|
988
|
+
new_comp = []
|
|
989
|
+
sum2 += j2
|
|
990
|
+
while sum1 < sum2:
|
|
991
|
+
i1 += 1
|
|
992
|
+
new_comp.append(I[i1])
|
|
993
|
+
sum1 += new_comp[-1]
|
|
994
|
+
if sum1 > sum2:
|
|
995
|
+
raise ValueError("composition J (= %s) does not refine self (= %s)" % (I, J))
|
|
996
|
+
decomp.append(Compositions()(new_comp))
|
|
997
|
+
return decomp
|
|
998
|
+
|
|
999
|
+
def refinement_splitting_lengths(self, J):
|
|
1000
|
+
"""
|
|
1001
|
+
Return the lengths of the compositions in the refinement splitting of
|
|
1002
|
+
``self`` according to ``J``.
|
|
1003
|
+
|
|
1004
|
+
.. SEEALSO::
|
|
1005
|
+
|
|
1006
|
+
:meth:`refinement_splitting` for the definition of refinement splitting
|
|
1007
|
+
|
|
1008
|
+
EXAMPLES::
|
|
1009
|
+
|
|
1010
|
+
sage: Composition([1,2,2,1,1,2]).refinement_splitting_lengths([5,1,3])
|
|
1011
|
+
[3, 1, 2]
|
|
1012
|
+
sage: Composition([]).refinement_splitting_lengths([])
|
|
1013
|
+
[]
|
|
1014
|
+
sage: Composition([3]).refinement_splitting_lengths([2])
|
|
1015
|
+
Traceback (most recent call last):
|
|
1016
|
+
...
|
|
1017
|
+
ValueError: compositions self (= [3]) and J (= [2]) must be of the same size
|
|
1018
|
+
sage: Composition([2,1]).refinement_splitting_lengths([1,2])
|
|
1019
|
+
Traceback (most recent call last):
|
|
1020
|
+
...
|
|
1021
|
+
ValueError: composition J (= [2, 1]) does not refine self (= [1, 2])
|
|
1022
|
+
"""
|
|
1023
|
+
return Compositions()([len(p) for p in self.refinement_splitting(J)])
|
|
1024
|
+
|
|
1025
|
+
def major_index(self) -> int:
|
|
1026
|
+
"""
|
|
1027
|
+
Return the major index of ``self``. The major index is
|
|
1028
|
+
defined as the sum of the descents.
|
|
1029
|
+
|
|
1030
|
+
EXAMPLES::
|
|
1031
|
+
|
|
1032
|
+
sage: Composition([1, 1, 3, 1, 2, 1, 3]).major_index()
|
|
1033
|
+
31
|
|
1034
|
+
"""
|
|
1035
|
+
lv = len(self)
|
|
1036
|
+
if lv == 1:
|
|
1037
|
+
return 0
|
|
1038
|
+
return sum([(lv - (i + 1)) * ci
|
|
1039
|
+
for i, ci in enumerate(self)])
|
|
1040
|
+
|
|
1041
|
+
def to_code(self) -> list:
|
|
1042
|
+
r"""
|
|
1043
|
+
Return the code of the composition ``self``.
|
|
1044
|
+
|
|
1045
|
+
The code of a composition `I` is a list of length
|
|
1046
|
+
`\mathrm{size}(I)` of 1s and 0s such that there is a 1
|
|
1047
|
+
wherever a new part starts. (Exceptional case: When the
|
|
1048
|
+
composition is empty, the code is ``[0]``.)
|
|
1049
|
+
|
|
1050
|
+
EXAMPLES::
|
|
1051
|
+
|
|
1052
|
+
sage: Composition([4,1,2,3,5]).to_code()
|
|
1053
|
+
[1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0]
|
|
1054
|
+
|
|
1055
|
+
TESTS::
|
|
1056
|
+
|
|
1057
|
+
sage: Composition([]).to_code()
|
|
1058
|
+
[0]
|
|
1059
|
+
"""
|
|
1060
|
+
if not self:
|
|
1061
|
+
return [0]
|
|
1062
|
+
|
|
1063
|
+
code = []
|
|
1064
|
+
for i in self:
|
|
1065
|
+
code += [1] + [0] * (i - 1)
|
|
1066
|
+
|
|
1067
|
+
return code
|
|
1068
|
+
|
|
1069
|
+
def partial_sums(self, final=True) -> list:
|
|
1070
|
+
r"""
|
|
1071
|
+
The partial sums of the sequence defined by the entries of the
|
|
1072
|
+
composition.
|
|
1073
|
+
|
|
1074
|
+
If `I = (i_1, \ldots, i_m)` is a composition, then the partial sums of
|
|
1075
|
+
the entries of the composition are
|
|
1076
|
+
`[i_1, i_1 + i_2, \ldots, i_1 + i_2 + \cdots + i_m]`.
|
|
1077
|
+
|
|
1078
|
+
INPUT:
|
|
1079
|
+
|
|
1080
|
+
- ``final`` -- boolean (default: ``True``); whether or not to include
|
|
1081
|
+
the final partial sum, which is always the size of the composition
|
|
1082
|
+
|
|
1083
|
+
.. SEEALSO::
|
|
1084
|
+
|
|
1085
|
+
:meth:`to_subset`
|
|
1086
|
+
|
|
1087
|
+
EXAMPLES::
|
|
1088
|
+
|
|
1089
|
+
sage: Composition([1,1,3,1,2,1,3]).partial_sums()
|
|
1090
|
+
[1, 2, 5, 6, 8, 9, 12]
|
|
1091
|
+
|
|
1092
|
+
With ``final = False``, the last partial sum is not included::
|
|
1093
|
+
|
|
1094
|
+
sage: Composition([1,1,3,1,2,1,3]).partial_sums(final=False)
|
|
1095
|
+
[1, 2, 5, 6, 8, 9]
|
|
1096
|
+
"""
|
|
1097
|
+
s = 0
|
|
1098
|
+
partial_sums = []
|
|
1099
|
+
for i in self:
|
|
1100
|
+
s += i
|
|
1101
|
+
partial_sums.append(s)
|
|
1102
|
+
if final is False:
|
|
1103
|
+
partial_sums.pop()
|
|
1104
|
+
return partial_sums
|
|
1105
|
+
|
|
1106
|
+
def to_subset(self, final=False):
|
|
1107
|
+
r"""
|
|
1108
|
+
The subset corresponding to ``self`` under the bijection (see below)
|
|
1109
|
+
between compositions of `n` and subsets of `\{1, 2, \ldots, n-1\}`.
|
|
1110
|
+
|
|
1111
|
+
The bijection maps a composition `(i_1, \ldots, i_k)` of `n` to
|
|
1112
|
+
`\{i_1, i_1 + i_2, i_1 + i_2 + i_3, \ldots, i_1 + \cdots + i_{k-1}\}`.
|
|
1113
|
+
|
|
1114
|
+
INPUT:
|
|
1115
|
+
|
|
1116
|
+
- ``final`` -- boolean (default: ``False``); whether or not to include
|
|
1117
|
+
the final partial sum, which is always the size of the composition
|
|
1118
|
+
|
|
1119
|
+
.. SEEALSO::
|
|
1120
|
+
|
|
1121
|
+
:meth:`partial_sums`
|
|
1122
|
+
|
|
1123
|
+
EXAMPLES::
|
|
1124
|
+
|
|
1125
|
+
sage: Composition([1,1,3,1,2,1,3]).to_subset()
|
|
1126
|
+
{1, 2, 5, 6, 8, 9}
|
|
1127
|
+
sage: for I in Compositions(3): print(I.to_subset())
|
|
1128
|
+
{1, 2}
|
|
1129
|
+
{1}
|
|
1130
|
+
{2}
|
|
1131
|
+
{}
|
|
1132
|
+
|
|
1133
|
+
With ``final=True``, the sum of all the elements of the composition is
|
|
1134
|
+
included in the subset::
|
|
1135
|
+
|
|
1136
|
+
sage: Composition([1,1,3,1,2,1,3]).to_subset(final=True)
|
|
1137
|
+
{1, 2, 5, 6, 8, 9, 12}
|
|
1138
|
+
|
|
1139
|
+
TESTS:
|
|
1140
|
+
|
|
1141
|
+
We verify that ``to_subset`` is indeed a bijection for compositions of
|
|
1142
|
+
size `n = 8`::
|
|
1143
|
+
|
|
1144
|
+
sage: n = 8
|
|
1145
|
+
sage: all(Composition(from_subset=(S, n)).to_subset() == S
|
|
1146
|
+
....: for S in Subsets(n-1))
|
|
1147
|
+
True
|
|
1148
|
+
sage: all(Composition(from_subset=(I.to_subset(), n)) == I
|
|
1149
|
+
....: for I in Compositions(n))
|
|
1150
|
+
True
|
|
1151
|
+
"""
|
|
1152
|
+
from sage.sets.set import Set
|
|
1153
|
+
return Set(self.partial_sums(final=final))
|
|
1154
|
+
|
|
1155
|
+
def descents(self, final_descent=False) -> list:
|
|
1156
|
+
r"""
|
|
1157
|
+
This gives one fewer than the partial sums of the composition.
|
|
1158
|
+
|
|
1159
|
+
This is here to maintain some sort of backward compatibility, even
|
|
1160
|
+
through the original implementation was broken (it gave the wrong
|
|
1161
|
+
answer). The same information can be found in :meth:`partial_sums`.
|
|
1162
|
+
|
|
1163
|
+
.. SEEALSO::
|
|
1164
|
+
|
|
1165
|
+
:meth:`partial_sums`
|
|
1166
|
+
|
|
1167
|
+
INPUT:
|
|
1168
|
+
|
|
1169
|
+
- ``final_descent`` -- boolean (default: ``False``)
|
|
1170
|
+
|
|
1171
|
+
OUTPUT:
|
|
1172
|
+
|
|
1173
|
+
- the list of partial sums of ``self`` with each part
|
|
1174
|
+
decremented by `1`. This includes the sum of all entries when
|
|
1175
|
+
``final_descent`` is ``True``.
|
|
1176
|
+
|
|
1177
|
+
EXAMPLES::
|
|
1178
|
+
|
|
1179
|
+
sage: c = Composition([2,1,3,2])
|
|
1180
|
+
sage: c.descents()
|
|
1181
|
+
[1, 2, 5]
|
|
1182
|
+
sage: c.descents(final_descent=True)
|
|
1183
|
+
[1, 2, 5, 7]
|
|
1184
|
+
"""
|
|
1185
|
+
return [i - 1 for i in self.partial_sums(final=final_descent)]
|
|
1186
|
+
|
|
1187
|
+
def peaks(self) -> list:
|
|
1188
|
+
"""
|
|
1189
|
+
Return a list of the peaks of the composition ``self``.
|
|
1190
|
+
|
|
1191
|
+
The peaks of a composition are the descents which do not
|
|
1192
|
+
immediately follow another descent.
|
|
1193
|
+
|
|
1194
|
+
EXAMPLES::
|
|
1195
|
+
|
|
1196
|
+
sage: Composition([1, 1, 3, 1, 2, 1, 3]).peaks()
|
|
1197
|
+
[4, 7]
|
|
1198
|
+
"""
|
|
1199
|
+
descents = set(d - 1 for d in self.to_subset(final=True))
|
|
1200
|
+
return [i + 1 for i in range(len(self))
|
|
1201
|
+
if i not in descents and i + 1 in descents]
|
|
1202
|
+
|
|
1203
|
+
@combinatorial_map(name='to partition')
|
|
1204
|
+
def to_partition(self):
|
|
1205
|
+
"""
|
|
1206
|
+
Return the partition obtained by sorting ``self`` into decreasing
|
|
1207
|
+
order.
|
|
1208
|
+
|
|
1209
|
+
EXAMPLES::
|
|
1210
|
+
|
|
1211
|
+
sage: Composition([2,1,3]).to_partition() # needs sage.combinat
|
|
1212
|
+
[3, 2, 1]
|
|
1213
|
+
sage: Composition([4,2,2]).to_partition() # needs sage.combinat
|
|
1214
|
+
[4, 2, 2]
|
|
1215
|
+
sage: Composition([]).to_partition() # needs sage.combinat
|
|
1216
|
+
[]
|
|
1217
|
+
"""
|
|
1218
|
+
return Partition(sorted(self, reverse=True))
|
|
1219
|
+
|
|
1220
|
+
def to_skew_partition(self, overlap=1):
|
|
1221
|
+
"""
|
|
1222
|
+
Return the skew partition obtained from ``self``.
|
|
1223
|
+
|
|
1224
|
+
This is a skew partition whose rows have the entries of
|
|
1225
|
+
``self`` as their length, taken in reverse order (so the first
|
|
1226
|
+
entry of ``self`` is the length of the lowermost row,
|
|
1227
|
+
etc.). The parameter ``overlap`` indicates the number of cells
|
|
1228
|
+
on each row that are directly below cells of the previous
|
|
1229
|
+
row. When it is set to `1` (its default value), the result is
|
|
1230
|
+
the ribbon shape of ``self``.
|
|
1231
|
+
|
|
1232
|
+
EXAMPLES::
|
|
1233
|
+
|
|
1234
|
+
sage: # needs sage.combinat
|
|
1235
|
+
sage: Composition([3,4,1]).to_skew_partition()
|
|
1236
|
+
[6, 6, 3] / [5, 2]
|
|
1237
|
+
sage: Composition([3,4,1]).to_skew_partition(overlap=0)
|
|
1238
|
+
[8, 7, 3] / [7, 3]
|
|
1239
|
+
sage: Composition([]).to_skew_partition()
|
|
1240
|
+
[] / []
|
|
1241
|
+
sage: Composition([1,2]).to_skew_partition()
|
|
1242
|
+
[2, 1] / []
|
|
1243
|
+
sage: Composition([2,1]).to_skew_partition()
|
|
1244
|
+
[2, 2] / [1]
|
|
1245
|
+
"""
|
|
1246
|
+
from sage.combinat.skew_partition import SkewPartition
|
|
1247
|
+
outer = []
|
|
1248
|
+
inner = []
|
|
1249
|
+
sum_outer = -overlap
|
|
1250
|
+
|
|
1251
|
+
for k in self[:-1]:
|
|
1252
|
+
outer.append(k + sum_outer + overlap)
|
|
1253
|
+
sum_outer += k - overlap
|
|
1254
|
+
inner.append(sum_outer + overlap)
|
|
1255
|
+
|
|
1256
|
+
if self:
|
|
1257
|
+
outer.append(self[-1] + sum_outer + overlap)
|
|
1258
|
+
else:
|
|
1259
|
+
return SkewPartition([[], []])
|
|
1260
|
+
|
|
1261
|
+
return SkewPartition(
|
|
1262
|
+
[[x for x in reversed(outer) if x != 0],
|
|
1263
|
+
[x for x in reversed(inner) if x != 0]])
|
|
1264
|
+
|
|
1265
|
+
def shuffle_product(self, other, overlap=False):
|
|
1266
|
+
r"""
|
|
1267
|
+
The (overlapping) shuffles of ``self`` and ``other``.
|
|
1268
|
+
|
|
1269
|
+
Suppose `I = (i_1, \ldots, i_k)` and `J = (j_1, \ldots, j_l)` are two
|
|
1270
|
+
compositions. A *shuffle* of `I` and `J` is a composition of length
|
|
1271
|
+
`k + l` that contains both `I` and `J` as subsequences.
|
|
1272
|
+
|
|
1273
|
+
More generally, an *overlapping shuffle* of `I` and `J` is obtained by
|
|
1274
|
+
distributing the elements of `I` and `J` (preserving the relative
|
|
1275
|
+
ordering of these elements) among the positions of an empty list; an
|
|
1276
|
+
element of `I` and an element of `J` are permitted to share the same
|
|
1277
|
+
position, in which case they are replaced by their sum. In particular,
|
|
1278
|
+
a shuffle of `I` and `J` is an overlapping shuffle of `I` and `J`.
|
|
1279
|
+
|
|
1280
|
+
INPUT:
|
|
1281
|
+
|
|
1282
|
+
- ``other`` -- composition
|
|
1283
|
+
|
|
1284
|
+
- ``overlap`` -- boolean (default: ``False``); if ``True``, the
|
|
1285
|
+
overlapping shuffle product is returned
|
|
1286
|
+
|
|
1287
|
+
OUTPUT:
|
|
1288
|
+
|
|
1289
|
+
An enumerated set (allowing for multiplicities)
|
|
1290
|
+
|
|
1291
|
+
EXAMPLES:
|
|
1292
|
+
|
|
1293
|
+
The shuffle product of `[2,2]` and `[1,1,3]`::
|
|
1294
|
+
|
|
1295
|
+
sage: alph = Composition([2,2])
|
|
1296
|
+
sage: beta = Composition([1,1,3])
|
|
1297
|
+
sage: S = alph.shuffle_product(beta); S # needs sage.combinat
|
|
1298
|
+
Shuffle product of [2, 2] and [1, 1, 3]
|
|
1299
|
+
sage: S.list() # needs sage.combinat
|
|
1300
|
+
[[2, 2, 1, 1, 3], [2, 1, 2, 1, 3], [2, 1, 1, 2, 3], [2, 1, 1, 3, 2],
|
|
1301
|
+
[1, 2, 2, 1, 3], [1, 2, 1, 2, 3], [1, 2, 1, 3, 2], [1, 1, 2, 2, 3],
|
|
1302
|
+
[1, 1, 2, 3, 2], [1, 1, 3, 2, 2]]
|
|
1303
|
+
|
|
1304
|
+
The *overlapping* shuffle product of `[2,2]` and `[1,1,3]`::
|
|
1305
|
+
|
|
1306
|
+
sage: alph = Composition([2,2])
|
|
1307
|
+
sage: beta = Composition([1,1,3])
|
|
1308
|
+
sage: O = alph.shuffle_product(beta, overlap=True); O # needs sage.combinat
|
|
1309
|
+
Overlapping shuffle product of [2, 2] and [1, 1, 3]
|
|
1310
|
+
sage: O.list() # needs sage.combinat
|
|
1311
|
+
[[2, 2, 1, 1, 3], [2, 1, 2, 1, 3], [2, 1, 1, 2, 3], [2, 1, 1, 3, 2],
|
|
1312
|
+
[1, 2, 2, 1, 3], [1, 2, 1, 2, 3], [1, 2, 1, 3, 2], [1, 1, 2, 2, 3],
|
|
1313
|
+
[1, 1, 2, 3, 2], [1, 1, 3, 2, 2],
|
|
1314
|
+
[3, 2, 1, 3], [2, 3, 1, 3], [3, 1, 2, 3], [2, 1, 3, 3], [3, 1, 3, 2],
|
|
1315
|
+
[2, 1, 1, 5], [1, 3, 2, 3], [1, 2, 3, 3], [1, 3, 3, 2], [1, 2, 1, 5],
|
|
1316
|
+
[1, 1, 5, 2], [1, 1, 2, 5],
|
|
1317
|
+
[3, 3, 3], [3, 1, 5], [1, 3, 5]]
|
|
1318
|
+
|
|
1319
|
+
Note that the shuffle product of two compositions can include the same
|
|
1320
|
+
composition more than once since a composition can be a shuffle of two
|
|
1321
|
+
compositions in several ways. For example::
|
|
1322
|
+
|
|
1323
|
+
sage: # needs sage.combinat
|
|
1324
|
+
sage: w1 = Composition([1])
|
|
1325
|
+
sage: S = w1.shuffle_product(w1); S
|
|
1326
|
+
Shuffle product of [1] and [1]
|
|
1327
|
+
sage: S.list()
|
|
1328
|
+
[[1, 1], [1, 1]]
|
|
1329
|
+
sage: O = w1.shuffle_product(w1, overlap=True); O
|
|
1330
|
+
Overlapping shuffle product of [1] and [1]
|
|
1331
|
+
sage: O.list()
|
|
1332
|
+
[[1, 1], [1, 1], [2]]
|
|
1333
|
+
|
|
1334
|
+
TESTS::
|
|
1335
|
+
|
|
1336
|
+
sage: empty = Composition([])
|
|
1337
|
+
sage: empty.shuffle_product(empty).list() # needs sage.combinat
|
|
1338
|
+
[[]]
|
|
1339
|
+
"""
|
|
1340
|
+
if overlap:
|
|
1341
|
+
from sage.combinat.shuffle import ShuffleProduct_overlapping
|
|
1342
|
+
return ShuffleProduct_overlapping(self, other,
|
|
1343
|
+
Compositions())
|
|
1344
|
+
else:
|
|
1345
|
+
from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2
|
|
1346
|
+
return ShuffleProduct_w1w2(self, other)
|
|
1347
|
+
|
|
1348
|
+
def wll_gt(self, co2) -> bool:
|
|
1349
|
+
"""
|
|
1350
|
+
Return ``True`` if the composition ``self`` is greater than the
|
|
1351
|
+
composition ``co2`` with respect to the wll-ordering; otherwise,
|
|
1352
|
+
return ``False``.
|
|
1353
|
+
|
|
1354
|
+
The wll-ordering is a total order on the set of all compositions
|
|
1355
|
+
defined as follows: A composition `I` is greater than a
|
|
1356
|
+
composition `J` if and only if one of the following conditions
|
|
1357
|
+
holds:
|
|
1358
|
+
|
|
1359
|
+
- The size of `I` is greater than the size of `J`.
|
|
1360
|
+
|
|
1361
|
+
- The size of `I` equals the size of `J`, but the length of `I`
|
|
1362
|
+
is greater than the length of `J`.
|
|
1363
|
+
|
|
1364
|
+
- The size of `I` equals the size of `J`, and the length of `I`
|
|
1365
|
+
equals the length of `J`, but `I` is lexicographically
|
|
1366
|
+
greater than `J`.
|
|
1367
|
+
|
|
1368
|
+
("wll-ordering" is short for "weight, length, lexicographic
|
|
1369
|
+
ordering".)
|
|
1370
|
+
|
|
1371
|
+
EXAMPLES::
|
|
1372
|
+
|
|
1373
|
+
sage: Composition([4,1,2]).wll_gt([3,1,3])
|
|
1374
|
+
True
|
|
1375
|
+
sage: Composition([7]).wll_gt([4,1,2])
|
|
1376
|
+
False
|
|
1377
|
+
sage: Composition([8]).wll_gt([4,1,2])
|
|
1378
|
+
True
|
|
1379
|
+
sage: Composition([3,2,2,2]).wll_gt([5,2])
|
|
1380
|
+
True
|
|
1381
|
+
sage: Composition([]).wll_gt([3])
|
|
1382
|
+
False
|
|
1383
|
+
sage: Composition([2,1]).wll_gt([2,1])
|
|
1384
|
+
False
|
|
1385
|
+
sage: Composition([2,2,2]).wll_gt([4,2])
|
|
1386
|
+
True
|
|
1387
|
+
sage: Composition([4,2]).wll_gt([2,2,2])
|
|
1388
|
+
False
|
|
1389
|
+
sage: Composition([1,1,2]).wll_gt([2,2])
|
|
1390
|
+
True
|
|
1391
|
+
sage: Composition([2,2]).wll_gt([1,3])
|
|
1392
|
+
True
|
|
1393
|
+
sage: Composition([2,1,2]).wll_gt([])
|
|
1394
|
+
True
|
|
1395
|
+
"""
|
|
1396
|
+
co1 = self
|
|
1397
|
+
if sum(co1) > sum(co2):
|
|
1398
|
+
return True
|
|
1399
|
+
elif sum(co1) < sum(co2):
|
|
1400
|
+
return False
|
|
1401
|
+
if len(co1) > len(co2):
|
|
1402
|
+
return True
|
|
1403
|
+
if len(co1) < len(co2):
|
|
1404
|
+
return False
|
|
1405
|
+
for i in range(len(co1)):
|
|
1406
|
+
if co1[i] > co2[i]:
|
|
1407
|
+
return True
|
|
1408
|
+
elif co1[i] < co2[i]:
|
|
1409
|
+
return False
|
|
1410
|
+
return False
|
|
1411
|
+
|
|
1412
|
+
def count(self, n):
|
|
1413
|
+
r"""
|
|
1414
|
+
Return the number of parts of size ``n``.
|
|
1415
|
+
|
|
1416
|
+
EXAMPLES::
|
|
1417
|
+
|
|
1418
|
+
sage: C = Composition([3,2,3])
|
|
1419
|
+
sage: C.count(3)
|
|
1420
|
+
2
|
|
1421
|
+
sage: C.count(2)
|
|
1422
|
+
1
|
|
1423
|
+
sage: C.count(1)
|
|
1424
|
+
0
|
|
1425
|
+
"""
|
|
1426
|
+
return sum(i == n for i in self)
|
|
1427
|
+
|
|
1428
|
+
def specht_module(self, base_ring=None):
|
|
1429
|
+
r"""
|
|
1430
|
+
Return the Specht module corresponding to ``self``.
|
|
1431
|
+
|
|
1432
|
+
EXAMPLES::
|
|
1433
|
+
|
|
1434
|
+
sage: SM = Composition([1,2,2]).specht_module(QQ); SM # needs sage.combinat sage.modules
|
|
1435
|
+
Specht module of [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)] over Rational Field
|
|
1436
|
+
sage: s = SymmetricFunctions(QQ).s() # needs sage.combinat sage.modules
|
|
1437
|
+
sage: s(SM.frobenius_image()) # needs sage.combinat sage.libs.flint sage.modules
|
|
1438
|
+
s[2, 2, 1]
|
|
1439
|
+
"""
|
|
1440
|
+
from sage.combinat.specht_module import SpechtModule
|
|
1441
|
+
from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra
|
|
1442
|
+
if base_ring is None:
|
|
1443
|
+
from sage.rings.rational_field import QQ
|
|
1444
|
+
base_ring = QQ
|
|
1445
|
+
R = SymmetricGroupAlgebra(base_ring, sum(self))
|
|
1446
|
+
cells = [(i, j) for i, row in enumerate(self) for j in range(row)]
|
|
1447
|
+
return SpechtModule(R, cells)
|
|
1448
|
+
|
|
1449
|
+
def specht_module_dimension(self, base_ring=None):
|
|
1450
|
+
r"""
|
|
1451
|
+
Return the dimension of the Specht module corresponding to ``self``.
|
|
1452
|
+
|
|
1453
|
+
INPUT:
|
|
1454
|
+
|
|
1455
|
+
- ``base_ring`` -- (default: `\QQ`) the base ring
|
|
1456
|
+
|
|
1457
|
+
EXAMPLES::
|
|
1458
|
+
|
|
1459
|
+
sage: Composition([1,2,2]).specht_module_dimension() # needs sage.combinat sage.modules
|
|
1460
|
+
5
|
|
1461
|
+
sage: Composition([1,2,2]).specht_module_dimension(GF(2)) # needs sage.combinat sage.modules sage.rings.finite_rings
|
|
1462
|
+
5
|
|
1463
|
+
"""
|
|
1464
|
+
from sage.combinat.specht_module import specht_module_rank
|
|
1465
|
+
return specht_module_rank(self, base_ring)
|
|
1466
|
+
|
|
1467
|
+
|
|
1468
|
+
Sequence.register(Composition)
|
|
1469
|
+
##############################################################
|
|
1470
|
+
|
|
1471
|
+
|
|
1472
|
+
class Compositions(UniqueRepresentation, Parent):
|
|
1473
|
+
r"""
|
|
1474
|
+
Set of integer compositions.
|
|
1475
|
+
|
|
1476
|
+
A composition `c` of a nonnegative integer `n` is a list of
|
|
1477
|
+
positive integers with total sum `n`.
|
|
1478
|
+
|
|
1479
|
+
.. SEEALSO::
|
|
1480
|
+
|
|
1481
|
+
- :class:`Composition`
|
|
1482
|
+
- :class:`Partitions`
|
|
1483
|
+
- :class:`IntegerVectors`
|
|
1484
|
+
|
|
1485
|
+
EXAMPLES:
|
|
1486
|
+
|
|
1487
|
+
There are 8 compositions of 4::
|
|
1488
|
+
|
|
1489
|
+
sage: Compositions(4).cardinality()
|
|
1490
|
+
8
|
|
1491
|
+
|
|
1492
|
+
Here is the list of them::
|
|
1493
|
+
|
|
1494
|
+
sage: Compositions(4).list()
|
|
1495
|
+
[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]
|
|
1496
|
+
|
|
1497
|
+
You can use the ``.first()`` method to get the 'first' composition of
|
|
1498
|
+
a number::
|
|
1499
|
+
|
|
1500
|
+
sage: Compositions(4).first()
|
|
1501
|
+
[1, 1, 1, 1]
|
|
1502
|
+
|
|
1503
|
+
You can also calculate the 'next' composition given the current
|
|
1504
|
+
one::
|
|
1505
|
+
|
|
1506
|
+
sage: Compositions(4).next([1,1,2])
|
|
1507
|
+
[1, 2, 1]
|
|
1508
|
+
|
|
1509
|
+
If `n` is not specified, this returns the combinatorial class of
|
|
1510
|
+
all (nonnegative) integer compositions::
|
|
1511
|
+
|
|
1512
|
+
sage: Compositions()
|
|
1513
|
+
Compositions of nonnegative integers
|
|
1514
|
+
sage: [] in Compositions()
|
|
1515
|
+
True
|
|
1516
|
+
sage: [2,3,1] in Compositions()
|
|
1517
|
+
True
|
|
1518
|
+
sage: [-2,3,1] in Compositions()
|
|
1519
|
+
False
|
|
1520
|
+
|
|
1521
|
+
If `n` is specified, it returns the class of compositions of `n`::
|
|
1522
|
+
|
|
1523
|
+
sage: Compositions(3)
|
|
1524
|
+
Compositions of 3
|
|
1525
|
+
sage: list(Compositions(3))
|
|
1526
|
+
[[1, 1, 1], [1, 2], [2, 1], [3]]
|
|
1527
|
+
sage: Compositions(3).cardinality()
|
|
1528
|
+
4
|
|
1529
|
+
|
|
1530
|
+
The following examples show how to test whether or not an object
|
|
1531
|
+
is a composition::
|
|
1532
|
+
|
|
1533
|
+
sage: [3,4] in Compositions()
|
|
1534
|
+
True
|
|
1535
|
+
sage: [3,4] in Compositions(7)
|
|
1536
|
+
True
|
|
1537
|
+
sage: [3,4] in Compositions(5)
|
|
1538
|
+
False
|
|
1539
|
+
|
|
1540
|
+
Similarly, one can check whether or not an object is a composition
|
|
1541
|
+
which satisfies further constraints::
|
|
1542
|
+
|
|
1543
|
+
sage: [4,2] in Compositions(6, inner=[2,2])
|
|
1544
|
+
True
|
|
1545
|
+
sage: [4,2] in Compositions(6, inner=[2,3])
|
|
1546
|
+
False
|
|
1547
|
+
sage: [4,1] in Compositions(5, inner=[2,1], max_slope = 0)
|
|
1548
|
+
True
|
|
1549
|
+
|
|
1550
|
+
An example with incompatible constraints::
|
|
1551
|
+
|
|
1552
|
+
sage: [4,2] in Compositions(6, inner=[2,2], min_part=3)
|
|
1553
|
+
False
|
|
1554
|
+
|
|
1555
|
+
The options ``length``, ``min_length``, and ``max_length`` can be used
|
|
1556
|
+
to set length constraints on the compositions. For example, the
|
|
1557
|
+
compositions of 4 of length equal to, at least, and at most 2 are
|
|
1558
|
+
given by::
|
|
1559
|
+
|
|
1560
|
+
sage: Compositions(4, length=2).list()
|
|
1561
|
+
[[3, 1], [2, 2], [1, 3]]
|
|
1562
|
+
sage: Compositions(4, min_length=2).list()
|
|
1563
|
+
[[3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
|
|
1564
|
+
sage: Compositions(4, max_length=2).list()
|
|
1565
|
+
[[4], [3, 1], [2, 2], [1, 3]]
|
|
1566
|
+
|
|
1567
|
+
Setting both ``min_length`` and ``max_length`` to the same value is
|
|
1568
|
+
equivalent to setting ``length`` to this value::
|
|
1569
|
+
|
|
1570
|
+
sage: Compositions(4, min_length=2, max_length=2).list()
|
|
1571
|
+
[[3, 1], [2, 2], [1, 3]]
|
|
1572
|
+
|
|
1573
|
+
The options ``inner`` and ``outer`` can be used to set part-by-part
|
|
1574
|
+
containment constraints. The list of compositions of 4 bounded
|
|
1575
|
+
above by ``[3,1,2]`` is given by::
|
|
1576
|
+
|
|
1577
|
+
sage: list(Compositions(4, outer=[3,1,2]))
|
|
1578
|
+
[[3, 1], [2, 1, 1], [1, 1, 2]]
|
|
1579
|
+
|
|
1580
|
+
``outer`` sets ``max_length`` to the length of its argument. Moreover, the
|
|
1581
|
+
parts of ``outer`` may be infinite to clear the constraint on specific
|
|
1582
|
+
parts. This is the list of compositions of 4 of length at most 3
|
|
1583
|
+
such that the first and third parts are at most 1::
|
|
1584
|
+
|
|
1585
|
+
sage: Compositions(4, outer=[1,oo,1]).list()
|
|
1586
|
+
[[1, 3], [1, 2, 1]]
|
|
1587
|
+
|
|
1588
|
+
This is the list of compositions of 4 bounded below by ``[1,1,1]``::
|
|
1589
|
+
|
|
1590
|
+
sage: Compositions(4, inner=[1,1,1]).list()
|
|
1591
|
+
[[2, 1, 1], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
|
|
1592
|
+
|
|
1593
|
+
The options ``min_slope`` and ``max_slope`` can be used to set constraints
|
|
1594
|
+
on the slope, that is the difference ``p[i+1]-p[i]`` of two
|
|
1595
|
+
consecutive parts. The following is the list of weakly increasing
|
|
1596
|
+
compositions of 4::
|
|
1597
|
+
|
|
1598
|
+
sage: Compositions(4, min_slope=0).list()
|
|
1599
|
+
[[4], [2, 2], [1, 3], [1, 1, 2], [1, 1, 1, 1]]
|
|
1600
|
+
|
|
1601
|
+
Here are the weakly decreasing ones::
|
|
1602
|
+
|
|
1603
|
+
sage: Compositions(4, max_slope=0).list()
|
|
1604
|
+
[[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]]
|
|
1605
|
+
|
|
1606
|
+
The following is the list of compositions of 4 such that two
|
|
1607
|
+
consecutive parts differ by at most one::
|
|
1608
|
+
|
|
1609
|
+
sage: Compositions(4, min_slope=-1, max_slope=1).list()
|
|
1610
|
+
[[4], [2, 2], [2, 1, 1], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
|
|
1611
|
+
|
|
1612
|
+
The constraints can be combined together in all reasonable ways.
|
|
1613
|
+
This is the list of compositions of 5 of length between 2 and 4
|
|
1614
|
+
such that the difference between consecutive parts is between -2
|
|
1615
|
+
and 1::
|
|
1616
|
+
|
|
1617
|
+
sage: Compositions(5, max_slope=1, min_slope=-2, min_length=2, max_length=4).list()
|
|
1618
|
+
[[3, 2], [3, 1, 1], [2, 3], [2, 2, 1], [2, 1, 2], [2, 1, 1, 1], [1, 2, 2], [1, 2, 1, 1], [1, 1, 2, 1], [1, 1, 1, 2]]
|
|
1619
|
+
|
|
1620
|
+
We can do the same thing with an outer constraint::
|
|
1621
|
+
|
|
1622
|
+
sage: Compositions(5, max_slope=1, min_slope=-2, min_length=2, max_length=4, outer=[2,5,2]).list()
|
|
1623
|
+
[[2, 3], [2, 2, 1], [2, 1, 2], [1, 2, 2]]
|
|
1624
|
+
|
|
1625
|
+
However, providing incoherent constraints may yield strange
|
|
1626
|
+
results. It is up to the user to ensure that the inner and outer
|
|
1627
|
+
compositions themselves satisfy the parts and slope constraints.
|
|
1628
|
+
|
|
1629
|
+
Note that setting ``min_part=0`` is not allowed::
|
|
1630
|
+
|
|
1631
|
+
sage: Compositions(2, length=3, min_part=0)
|
|
1632
|
+
Traceback (most recent call last):
|
|
1633
|
+
...
|
|
1634
|
+
ValueError: setting min_part=0 is not allowed for Compositions
|
|
1635
|
+
|
|
1636
|
+
Instead you must use ``IntegerVectors``::
|
|
1637
|
+
|
|
1638
|
+
sage: list(IntegerVectors(2, 3))
|
|
1639
|
+
[[2, 0, 0], [1, 1, 0], [1, 0, 1], [0, 2, 0], [0, 1, 1], [0, 0, 2]]
|
|
1640
|
+
|
|
1641
|
+
The generation algorithm is constant amortized time, and handled
|
|
1642
|
+
by the generic tool :class:`IntegerListsLex`.
|
|
1643
|
+
|
|
1644
|
+
TESTS::
|
|
1645
|
+
|
|
1646
|
+
sage: C = Compositions(4, length=2)
|
|
1647
|
+
sage: C == loads(dumps(C))
|
|
1648
|
+
True
|
|
1649
|
+
|
|
1650
|
+
sage: Compositions(6, min_part=2, length=3)
|
|
1651
|
+
Compositions of the integer 6 satisfying constraints length=3, min_part=2
|
|
1652
|
+
|
|
1653
|
+
sage: [2, 1] in Compositions(3, length=2)
|
|
1654
|
+
True
|
|
1655
|
+
sage: [2,1,2] in Compositions(5, min_part=1)
|
|
1656
|
+
True
|
|
1657
|
+
sage: [2,1,2] in Compositions(5, min_part=2)
|
|
1658
|
+
False
|
|
1659
|
+
|
|
1660
|
+
sage: Compositions(4, length=2).cardinality()
|
|
1661
|
+
3
|
|
1662
|
+
sage: Compositions(4, min_length=2).cardinality()
|
|
1663
|
+
7
|
|
1664
|
+
sage: Compositions(4, max_length=2).cardinality()
|
|
1665
|
+
4
|
|
1666
|
+
sage: Compositions(4, max_part=2).cardinality()
|
|
1667
|
+
5
|
|
1668
|
+
sage: Compositions(4, min_part=2).cardinality()
|
|
1669
|
+
2
|
|
1670
|
+
sage: Compositions(4, outer=[3,1,2]).cardinality()
|
|
1671
|
+
3
|
|
1672
|
+
|
|
1673
|
+
sage: Compositions(4, length=2).list()
|
|
1674
|
+
[[3, 1], [2, 2], [1, 3]]
|
|
1675
|
+
sage: Compositions(4, min_length=2).list()
|
|
1676
|
+
[[3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
|
|
1677
|
+
sage: Compositions(4, max_length=2).list()
|
|
1678
|
+
[[4], [3, 1], [2, 2], [1, 3]]
|
|
1679
|
+
sage: Compositions(4, max_part=2).list()
|
|
1680
|
+
[[2, 2], [2, 1, 1], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
|
|
1681
|
+
sage: Compositions(4, min_part=2).list()
|
|
1682
|
+
[[4], [2, 2]]
|
|
1683
|
+
sage: Compositions(4, outer=[3,1,2]).list()
|
|
1684
|
+
[[3, 1], [2, 1, 1], [1, 1, 2]]
|
|
1685
|
+
sage: Compositions(3, outer = Composition([3,2])).list()
|
|
1686
|
+
[[3], [2, 1], [1, 2]]
|
|
1687
|
+
sage: Compositions(4, outer=[1,oo,1]).list()
|
|
1688
|
+
[[1, 3], [1, 2, 1]]
|
|
1689
|
+
sage: Compositions(4, inner=[1,1,1]).list()
|
|
1690
|
+
[[2, 1, 1], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
|
|
1691
|
+
sage: Compositions(4, inner=Composition([1,2])).list()
|
|
1692
|
+
[[2, 2], [1, 3], [1, 2, 1]]
|
|
1693
|
+
sage: Compositions(4, min_slope=0).list()
|
|
1694
|
+
[[4], [2, 2], [1, 3], [1, 1, 2], [1, 1, 1, 1]]
|
|
1695
|
+
sage: Compositions(4, min_slope=-1, max_slope=1).list()
|
|
1696
|
+
[[4], [2, 2], [2, 1, 1], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
|
|
1697
|
+
sage: Compositions(5, max_slope=1, min_slope=-2, min_length=2, max_length=4).list()
|
|
1698
|
+
[[3, 2], [3, 1, 1], [2, 3], [2, 2, 1], [2, 1, 2], [2, 1, 1, 1], [1, 2, 2], [1, 2, 1, 1], [1, 1, 2, 1], [1, 1, 1, 2]]
|
|
1699
|
+
sage: Compositions(5, max_slope=1, min_slope=-2, min_length=2, max_length=4, outer=[2,5,2]).list()
|
|
1700
|
+
[[2, 3], [2, 2, 1], [2, 1, 2], [1, 2, 2]]
|
|
1701
|
+
"""
|
|
1702
|
+
@staticmethod
|
|
1703
|
+
def __classcall_private__(self, n=None, **kwargs):
|
|
1704
|
+
"""
|
|
1705
|
+
Return the correct parent based upon the input.
|
|
1706
|
+
|
|
1707
|
+
EXAMPLES::
|
|
1708
|
+
|
|
1709
|
+
sage: C = Compositions(3)
|
|
1710
|
+
sage: C2 = Compositions(int(3))
|
|
1711
|
+
sage: C is C2
|
|
1712
|
+
True
|
|
1713
|
+
"""
|
|
1714
|
+
if n is None:
|
|
1715
|
+
if kwargs:
|
|
1716
|
+
raise ValueError("incorrect number of arguments")
|
|
1717
|
+
return Compositions_all()
|
|
1718
|
+
else:
|
|
1719
|
+
if not kwargs:
|
|
1720
|
+
if isinstance(n, (int, Integer)):
|
|
1721
|
+
return Compositions_n(n)
|
|
1722
|
+
else:
|
|
1723
|
+
raise ValueError("n must be an integer")
|
|
1724
|
+
else:
|
|
1725
|
+
# FIXME: should inherit from IntegerListLex, and implement repr, or _name as a lazy attribute
|
|
1726
|
+
txt = "Compositions of the integer %s satisfying constraints %s"
|
|
1727
|
+
kwargs['name'] = txt % (n, ", ".join(f"{key}={kwargs[key]}"
|
|
1728
|
+
for key in sorted(kwargs)))
|
|
1729
|
+
kwargs['element_class'] = Composition
|
|
1730
|
+
if 'min_part' not in kwargs:
|
|
1731
|
+
kwargs['min_part'] = 1
|
|
1732
|
+
elif kwargs['min_part'] == 0:
|
|
1733
|
+
raise ValueError("setting min_part=0 is not allowed for Compositions")
|
|
1734
|
+
|
|
1735
|
+
if 'outer' in kwargs:
|
|
1736
|
+
kwargs['ceiling'] = list(kwargs['outer'])
|
|
1737
|
+
if 'max_length' in kwargs:
|
|
1738
|
+
kwargs['max_length'] = min(len(kwargs['outer']), kwargs['max_length'])
|
|
1739
|
+
else:
|
|
1740
|
+
kwargs['max_length'] = len(kwargs['outer'])
|
|
1741
|
+
del kwargs['outer']
|
|
1742
|
+
|
|
1743
|
+
if 'inner' in kwargs:
|
|
1744
|
+
inner = list(kwargs['inner'])
|
|
1745
|
+
kwargs['floor'] = inner
|
|
1746
|
+
del kwargs['inner']
|
|
1747
|
+
# Should this be handled by integer lists lex?
|
|
1748
|
+
if 'min_length' in kwargs:
|
|
1749
|
+
kwargs['min_length'] = max(len(inner), kwargs['min_length'])
|
|
1750
|
+
else:
|
|
1751
|
+
kwargs['min_length'] = len(inner)
|
|
1752
|
+
return IntegerListsLex(n, **kwargs)
|
|
1753
|
+
|
|
1754
|
+
def __init__(self, is_infinite=False, category=None):
|
|
1755
|
+
"""
|
|
1756
|
+
Initialize ``self``.
|
|
1757
|
+
|
|
1758
|
+
EXAMPLES::
|
|
1759
|
+
|
|
1760
|
+
sage: C = Compositions()
|
|
1761
|
+
sage: TestSuite(C).run()
|
|
1762
|
+
"""
|
|
1763
|
+
if category is None:
|
|
1764
|
+
category = EnumeratedSets()
|
|
1765
|
+
if is_infinite:
|
|
1766
|
+
Parent.__init__(self, category=category.Infinite())
|
|
1767
|
+
else:
|
|
1768
|
+
Parent.__init__(self, category=category.Finite())
|
|
1769
|
+
|
|
1770
|
+
Element = Composition
|
|
1771
|
+
|
|
1772
|
+
def _element_constructor_(self, lst) -> Composition:
|
|
1773
|
+
"""
|
|
1774
|
+
Construct an element with ``self`` as parent.
|
|
1775
|
+
|
|
1776
|
+
EXAMPLES::
|
|
1777
|
+
|
|
1778
|
+
sage: P = Compositions()
|
|
1779
|
+
sage: P([3,3,1]) # indirect doctest
|
|
1780
|
+
[3, 3, 1]
|
|
1781
|
+
sage: P(Partition([5,2,1])) # needs sage.combinat
|
|
1782
|
+
[5, 2, 1]
|
|
1783
|
+
"""
|
|
1784
|
+
# input can be an iterator, and one has to use it twice
|
|
1785
|
+
lst = list(lst)
|
|
1786
|
+
if any(not isinstance(x, (int, Integer)) or x < 0 for x in lst):
|
|
1787
|
+
raise ValueError('not a composition')
|
|
1788
|
+
elt = self.element_class(self, lst)
|
|
1789
|
+
if elt not in self:
|
|
1790
|
+
raise ValueError("%s not in %s" % (elt, self))
|
|
1791
|
+
return elt
|
|
1792
|
+
|
|
1793
|
+
def __contains__(self, x) -> bool:
|
|
1794
|
+
"""
|
|
1795
|
+
TESTS::
|
|
1796
|
+
|
|
1797
|
+
sage: [2,1,3] in Compositions()
|
|
1798
|
+
True
|
|
1799
|
+
sage: [] in Compositions()
|
|
1800
|
+
True
|
|
1801
|
+
sage: [-2,-1] in Compositions()
|
|
1802
|
+
False
|
|
1803
|
+
sage: [0,0] in Compositions()
|
|
1804
|
+
True
|
|
1805
|
+
"""
|
|
1806
|
+
if isinstance(x, (Composition, Partition)):
|
|
1807
|
+
return True
|
|
1808
|
+
elif isinstance(x, list):
|
|
1809
|
+
for i in x:
|
|
1810
|
+
if (not isinstance(i, (int, Integer))) and i not in ZZ:
|
|
1811
|
+
return False
|
|
1812
|
+
if i < 0:
|
|
1813
|
+
return False
|
|
1814
|
+
return True
|
|
1815
|
+
else:
|
|
1816
|
+
return False
|
|
1817
|
+
|
|
1818
|
+
def from_descents(self, descents, nps=None) -> Composition:
|
|
1819
|
+
"""
|
|
1820
|
+
Return a composition from the list of descents.
|
|
1821
|
+
|
|
1822
|
+
INPUT:
|
|
1823
|
+
|
|
1824
|
+
- ``descents`` -- an iterable
|
|
1825
|
+
|
|
1826
|
+
- ``nps`` -- integer or ``None`` (default: ``None``)
|
|
1827
|
+
|
|
1828
|
+
OUTPUT:
|
|
1829
|
+
|
|
1830
|
+
- The composition of ``nps`` whose descents are listed in
|
|
1831
|
+
``descents``, assuming that ``nps`` is not ``None`` (otherwise,
|
|
1832
|
+
the last element of ``descents`` is removed from ``descents``, and
|
|
1833
|
+
``nps`` is set to be this last element plus 1).
|
|
1834
|
+
|
|
1835
|
+
EXAMPLES::
|
|
1836
|
+
|
|
1837
|
+
sage: [x-1 for x in Composition([1, 1, 3, 4, 3]).to_subset()]
|
|
1838
|
+
[0, 1, 4, 8]
|
|
1839
|
+
sage: Compositions().from_descents([1,0,4,8],12)
|
|
1840
|
+
[1, 1, 3, 4, 3]
|
|
1841
|
+
sage: Compositions().from_descents([1,0,4,8,11])
|
|
1842
|
+
[1, 1, 3, 4, 3]
|
|
1843
|
+
"""
|
|
1844
|
+
d = [x + 1 for x in sorted(descents)]
|
|
1845
|
+
if nps is None:
|
|
1846
|
+
nps = d.pop()
|
|
1847
|
+
return self.from_subset(d, nps)
|
|
1848
|
+
|
|
1849
|
+
def from_subset(self, S, n) -> Composition:
|
|
1850
|
+
r"""
|
|
1851
|
+
The composition of `n` corresponding to the subset ``S`` of
|
|
1852
|
+
`\{1, 2, \ldots, n-1\}` under the bijection that maps the composition
|
|
1853
|
+
`(i_1, i_2, \ldots, i_k)` of `n` to the subset
|
|
1854
|
+
`\{i_1, i_1 + i_2, i_1 + i_2 + i_3, \ldots, i_1 + \cdots + i_{k-1}\}`
|
|
1855
|
+
(see :meth:`Composition.to_subset`).
|
|
1856
|
+
|
|
1857
|
+
INPUT:
|
|
1858
|
+
|
|
1859
|
+
- ``S`` -- an iterable, a subset of `\{1, 2, \ldots, n-1\}`
|
|
1860
|
+
|
|
1861
|
+
- ``n`` -- integer
|
|
1862
|
+
|
|
1863
|
+
EXAMPLES::
|
|
1864
|
+
|
|
1865
|
+
sage: Compositions().from_subset([2,1,5,9], 12)
|
|
1866
|
+
[1, 1, 3, 4, 3]
|
|
1867
|
+
sage: Compositions().from_subset({2,1,5,9}, 12)
|
|
1868
|
+
[1, 1, 3, 4, 3]
|
|
1869
|
+
|
|
1870
|
+
sage: Compositions().from_subset([], 12)
|
|
1871
|
+
[12]
|
|
1872
|
+
sage: Compositions().from_subset([], 0)
|
|
1873
|
+
[]
|
|
1874
|
+
|
|
1875
|
+
TESTS::
|
|
1876
|
+
|
|
1877
|
+
sage: Compositions().from_subset([2,1,5,9],9)
|
|
1878
|
+
Traceback (most recent call last):
|
|
1879
|
+
...
|
|
1880
|
+
ValueError: S (=[1, 2, 5, 9]) is not a subset of {1, ..., 8}
|
|
1881
|
+
"""
|
|
1882
|
+
d = sorted(S)
|
|
1883
|
+
|
|
1884
|
+
if not d:
|
|
1885
|
+
if n == 0:
|
|
1886
|
+
return self.element_class(self, [])
|
|
1887
|
+
else:
|
|
1888
|
+
return self.element_class(self, [n])
|
|
1889
|
+
|
|
1890
|
+
if n <= d[-1]:
|
|
1891
|
+
raise ValueError("S (=%s) is not a subset of {1, ..., %s}"
|
|
1892
|
+
% (d, n - 1))
|
|
1893
|
+
else:
|
|
1894
|
+
d.append(n)
|
|
1895
|
+
|
|
1896
|
+
co = [d[0]]
|
|
1897
|
+
co.extend(d[i + 1] - d[i] for i in range(len(d) - 1))
|
|
1898
|
+
|
|
1899
|
+
return self.element_class(self, co)
|
|
1900
|
+
|
|
1901
|
+
def from_code(self, code) -> Composition:
|
|
1902
|
+
r"""
|
|
1903
|
+
Return the composition from its code. The code of a composition
|
|
1904
|
+
`I` is a list of length `\mathrm{size}(I)` consisting of 1s and
|
|
1905
|
+
0s such that there is a 1 wherever a new part starts.
|
|
1906
|
+
(Exceptional case: When the composition is empty, the code is
|
|
1907
|
+
``[0]``.)
|
|
1908
|
+
|
|
1909
|
+
EXAMPLES::
|
|
1910
|
+
|
|
1911
|
+
sage: Composition([4,1,2,3,5]).to_code()
|
|
1912
|
+
[1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0]
|
|
1913
|
+
sage: Compositions().from_code(_)
|
|
1914
|
+
[4, 1, 2, 3, 5]
|
|
1915
|
+
sage: Composition([3,1,2,3,5]).to_code()
|
|
1916
|
+
[1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0]
|
|
1917
|
+
sage: Compositions().from_code(_)
|
|
1918
|
+
[3, 1, 2, 3, 5]
|
|
1919
|
+
"""
|
|
1920
|
+
if code == [0]:
|
|
1921
|
+
return self.element_class(self, [])
|
|
1922
|
+
|
|
1923
|
+
L = [x for x in range(len(code)) if code[x] == 1] # the positions of the letter 1
|
|
1924
|
+
c = [L[i] - L[i - 1] for i in range(1, len(L))] + [len(code) - L[-1]]
|
|
1925
|
+
return self.element_class(self, c)
|
|
1926
|
+
|
|
1927
|
+
|
|
1928
|
+
# Allows to unpickle old constrained Compositions_constraints objects.
|
|
1929
|
+
class Compositions_constraints(IntegerListsLex):
|
|
1930
|
+
def __setstate__(self, data):
|
|
1931
|
+
"""
|
|
1932
|
+
TESTS::
|
|
1933
|
+
|
|
1934
|
+
# This is the unpickling sequence for Compositions(4, max_part=2) in sage <= 4.1.1
|
|
1935
|
+
sage: pg_Compositions_constraints = unpickle_global('sage.combinat.composition', 'Compositions_constraints')
|
|
1936
|
+
sage: si = unpickle_newobj(pg_Compositions_constraints, ())
|
|
1937
|
+
sage: pg_make_integer = unpickle_global('sage.rings.integer', 'make_integer')
|
|
1938
|
+
sage: unpickle_build(si, {'constraints':{'max_part':pg_make_integer('2')}, 'n':pg_make_integer('4')})
|
|
1939
|
+
sage: si
|
|
1940
|
+
Integer lists of sum 4 satisfying certain constraints
|
|
1941
|
+
sage: si.list()
|
|
1942
|
+
[[2, 2], [2, 1, 1], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]]
|
|
1943
|
+
"""
|
|
1944
|
+
n = data['n']
|
|
1945
|
+
self.__class__ = IntegerListsLex
|
|
1946
|
+
constraints = {'min_part': 1,
|
|
1947
|
+
'element_class': Composition}
|
|
1948
|
+
constraints.update(data['constraints'])
|
|
1949
|
+
self.__init__(n, **constraints)
|
|
1950
|
+
|
|
1951
|
+
|
|
1952
|
+
class Compositions_all(Compositions):
|
|
1953
|
+
"""
|
|
1954
|
+
Class of all compositions.
|
|
1955
|
+
"""
|
|
1956
|
+
|
|
1957
|
+
def __init__(self):
|
|
1958
|
+
"""
|
|
1959
|
+
Initialize ``self``.
|
|
1960
|
+
|
|
1961
|
+
TESTS::
|
|
1962
|
+
|
|
1963
|
+
sage: C = Compositions()
|
|
1964
|
+
sage: TestSuite(C).run()
|
|
1965
|
+
"""
|
|
1966
|
+
cat = AdditiveMonoids()
|
|
1967
|
+
Compositions.__init__(self, True, category=cat)
|
|
1968
|
+
|
|
1969
|
+
def _repr_(self) -> str:
|
|
1970
|
+
"""
|
|
1971
|
+
Return a string representation of ``self``.
|
|
1972
|
+
|
|
1973
|
+
TESTS::
|
|
1974
|
+
|
|
1975
|
+
sage: repr(Compositions())
|
|
1976
|
+
'Compositions of nonnegative integers'
|
|
1977
|
+
"""
|
|
1978
|
+
return "Compositions of nonnegative integers"
|
|
1979
|
+
|
|
1980
|
+
def subset(self, size=None):
|
|
1981
|
+
"""
|
|
1982
|
+
Return the set of compositions of the given size.
|
|
1983
|
+
|
|
1984
|
+
EXAMPLES::
|
|
1985
|
+
|
|
1986
|
+
sage: C = Compositions()
|
|
1987
|
+
sage: C.subset(4)
|
|
1988
|
+
Compositions of 4
|
|
1989
|
+
sage: C.subset(size=3)
|
|
1990
|
+
Compositions of 3
|
|
1991
|
+
"""
|
|
1992
|
+
if size is None:
|
|
1993
|
+
return self
|
|
1994
|
+
return Compositions(size)
|
|
1995
|
+
|
|
1996
|
+
def zero(self):
|
|
1997
|
+
"""
|
|
1998
|
+
Return the zero of the additive monoid.
|
|
1999
|
+
|
|
2000
|
+
This is the empty composition.
|
|
2001
|
+
|
|
2002
|
+
EXAMPLES::
|
|
2003
|
+
|
|
2004
|
+
sage: C = Compositions()
|
|
2005
|
+
sage: C.zero()
|
|
2006
|
+
[]
|
|
2007
|
+
"""
|
|
2008
|
+
return Composition([])
|
|
2009
|
+
|
|
2010
|
+
def _an_element_(self):
|
|
2011
|
+
"""
|
|
2012
|
+
Return an element of ``self``.
|
|
2013
|
+
|
|
2014
|
+
EXAMPLES::
|
|
2015
|
+
|
|
2016
|
+
sage: C = Compositions()
|
|
2017
|
+
sage: C.an_element()
|
|
2018
|
+
[]
|
|
2019
|
+
"""
|
|
2020
|
+
return self.zero()
|
|
2021
|
+
|
|
2022
|
+
def __iter__(self):
|
|
2023
|
+
"""
|
|
2024
|
+
Iterate over all compositions.
|
|
2025
|
+
|
|
2026
|
+
TESTS::
|
|
2027
|
+
|
|
2028
|
+
sage: C = Compositions()
|
|
2029
|
+
sage: it = C.__iter__()
|
|
2030
|
+
sage: [next(it) for i in range(10)]
|
|
2031
|
+
[[], [1], [1, 1], [2], [1, 1, 1], [1, 2], [2, 1], [3], [1, 1, 1, 1], [1, 1, 2]]
|
|
2032
|
+
"""
|
|
2033
|
+
n = 0
|
|
2034
|
+
while True:
|
|
2035
|
+
for c in Compositions(n):
|
|
2036
|
+
yield self.element_class(self, list(c))
|
|
2037
|
+
n += 1
|
|
2038
|
+
|
|
2039
|
+
|
|
2040
|
+
class Compositions_n(Compositions):
|
|
2041
|
+
"""
|
|
2042
|
+
Class of compositions of a fixed `n`.
|
|
2043
|
+
"""
|
|
2044
|
+
@staticmethod
|
|
2045
|
+
def __classcall_private__(cls, n):
|
|
2046
|
+
"""
|
|
2047
|
+
Standardize input to ensure a unique representation.
|
|
2048
|
+
|
|
2049
|
+
EXAMPLES::
|
|
2050
|
+
|
|
2051
|
+
sage: C = Compositions(5)
|
|
2052
|
+
sage: C2 = Compositions(int(5))
|
|
2053
|
+
sage: C3 = Compositions(ZZ(5))
|
|
2054
|
+
sage: C is C2
|
|
2055
|
+
True
|
|
2056
|
+
sage: C is C3
|
|
2057
|
+
True
|
|
2058
|
+
"""
|
|
2059
|
+
return super().__classcall__(cls, Integer(n))
|
|
2060
|
+
|
|
2061
|
+
def __init__(self, n):
|
|
2062
|
+
"""
|
|
2063
|
+
TESTS::
|
|
2064
|
+
|
|
2065
|
+
sage: C = Compositions(3)
|
|
2066
|
+
sage: C == loads(dumps(C))
|
|
2067
|
+
True
|
|
2068
|
+
sage: TestSuite(C).run()
|
|
2069
|
+
"""
|
|
2070
|
+
self.n = n
|
|
2071
|
+
Compositions.__init__(self, False)
|
|
2072
|
+
|
|
2073
|
+
def _repr_(self) -> str:
|
|
2074
|
+
"""
|
|
2075
|
+
Return a string representation of ``self``.
|
|
2076
|
+
|
|
2077
|
+
TESTS::
|
|
2078
|
+
|
|
2079
|
+
sage: repr(Compositions(3))
|
|
2080
|
+
'Compositions of 3'
|
|
2081
|
+
"""
|
|
2082
|
+
return "Compositions of %s" % self.n
|
|
2083
|
+
|
|
2084
|
+
def __contains__(self, x) -> bool:
|
|
2085
|
+
"""
|
|
2086
|
+
TESTS::
|
|
2087
|
+
|
|
2088
|
+
sage: [2,1,3] in Compositions(6)
|
|
2089
|
+
True
|
|
2090
|
+
sage: [2,1,2] in Compositions(6)
|
|
2091
|
+
False
|
|
2092
|
+
sage: [] in Compositions(0)
|
|
2093
|
+
True
|
|
2094
|
+
sage: [0] in Compositions(0)
|
|
2095
|
+
True
|
|
2096
|
+
"""
|
|
2097
|
+
return x in Compositions() and sum(x) == self.n
|
|
2098
|
+
|
|
2099
|
+
def cardinality(self) -> Integer:
|
|
2100
|
+
"""
|
|
2101
|
+
Return the number of compositions of `n`.
|
|
2102
|
+
|
|
2103
|
+
TESTS::
|
|
2104
|
+
|
|
2105
|
+
sage: Compositions(3).cardinality()
|
|
2106
|
+
4
|
|
2107
|
+
sage: Compositions(0).cardinality()
|
|
2108
|
+
1
|
|
2109
|
+
"""
|
|
2110
|
+
if self.n >= 1:
|
|
2111
|
+
return ZZ(2)**(self.n - 1)
|
|
2112
|
+
elif self.n == 0:
|
|
2113
|
+
return ZZ.one()
|
|
2114
|
+
else:
|
|
2115
|
+
return ZZ.zero()
|
|
2116
|
+
|
|
2117
|
+
def random_element(self) -> Composition:
|
|
2118
|
+
r"""
|
|
2119
|
+
Return a random ``Composition`` with uniform probability.
|
|
2120
|
+
|
|
2121
|
+
This method generates a random binary word starting with a 1
|
|
2122
|
+
and then uses the bijection between compositions and their code.
|
|
2123
|
+
|
|
2124
|
+
EXAMPLES::
|
|
2125
|
+
|
|
2126
|
+
sage: Compositions(5).random_element() # random
|
|
2127
|
+
[2, 1, 1, 1]
|
|
2128
|
+
sage: Compositions(0).random_element()
|
|
2129
|
+
[]
|
|
2130
|
+
sage: Compositions(1).random_element()
|
|
2131
|
+
[1]
|
|
2132
|
+
|
|
2133
|
+
TESTS::
|
|
2134
|
+
|
|
2135
|
+
sage: all(Compositions(10).random_element() in Compositions(10) for i in range(20))
|
|
2136
|
+
True
|
|
2137
|
+
"""
|
|
2138
|
+
from sage.misc.prandom import choice
|
|
2139
|
+
|
|
2140
|
+
if self.n == 0:
|
|
2141
|
+
return Compositions()([])
|
|
2142
|
+
return Compositions().from_code([1] + [choice([0, 1]) for _ in range(self.n - 1)])
|
|
2143
|
+
|
|
2144
|
+
def __iter__(self):
|
|
2145
|
+
"""
|
|
2146
|
+
Iterate over the compositions of `n`.
|
|
2147
|
+
|
|
2148
|
+
TESTS::
|
|
2149
|
+
|
|
2150
|
+
sage: Compositions(4).list()
|
|
2151
|
+
[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]
|
|
2152
|
+
sage: Compositions(0).list()
|
|
2153
|
+
[[]]
|
|
2154
|
+
"""
|
|
2155
|
+
for c in composition_iterator_fast(self.n):
|
|
2156
|
+
yield self.element_class(self, c)
|
|
2157
|
+
|
|
2158
|
+
|
|
2159
|
+
def composition_iterator_fast(n):
|
|
2160
|
+
"""
|
|
2161
|
+
Iterator over compositions of `n` yielded as lists.
|
|
2162
|
+
|
|
2163
|
+
TESTS::
|
|
2164
|
+
|
|
2165
|
+
sage: from sage.combinat.composition import composition_iterator_fast
|
|
2166
|
+
sage: L = list(composition_iterator_fast(4)); L
|
|
2167
|
+
[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]
|
|
2168
|
+
sage: type(L[0])
|
|
2169
|
+
<class 'list'>
|
|
2170
|
+
"""
|
|
2171
|
+
# Special cases
|
|
2172
|
+
if n < 0:
|
|
2173
|
+
return
|
|
2174
|
+
if n == 0:
|
|
2175
|
+
yield []
|
|
2176
|
+
return
|
|
2177
|
+
|
|
2178
|
+
s = Integer(0) # Current sum
|
|
2179
|
+
cur = [Integer(0)]
|
|
2180
|
+
while cur:
|
|
2181
|
+
cur[-1] += 1
|
|
2182
|
+
s += 1
|
|
2183
|
+
# Note that because we are adding 1 every time,
|
|
2184
|
+
# we will never have s > n
|
|
2185
|
+
if s == n:
|
|
2186
|
+
yield list(cur)
|
|
2187
|
+
s -= cur.pop()
|
|
2188
|
+
else:
|
|
2189
|
+
cur.append(Integer(0))
|
|
2190
|
+
|
|
2191
|
+
|
|
2192
|
+
register_unpickle_override('sage.combinat.composition', 'Composition_class', Composition)
|