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,2269 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-categories
|
|
2
|
+
r"""
|
|
3
|
+
Combinatorial functions
|
|
4
|
+
|
|
5
|
+
This module implements some combinatorial functions, as listed
|
|
6
|
+
below. For a more detailed description, see the relevant
|
|
7
|
+
docstrings.
|
|
8
|
+
|
|
9
|
+
**Numbers:**
|
|
10
|
+
|
|
11
|
+
- Bell numbers :func:`bell_number`
|
|
12
|
+
|
|
13
|
+
- Catalan numbers :func:`catalan_number`
|
|
14
|
+
|
|
15
|
+
- Narayana numbers :func:`narayana_number`
|
|
16
|
+
|
|
17
|
+
- Euler numbers :func:`euler_number`
|
|
18
|
+
|
|
19
|
+
- Eulerian numbers :func:`eulerian_number`
|
|
20
|
+
|
|
21
|
+
- Fibonacci numbers :func:`fibonacci`
|
|
22
|
+
|
|
23
|
+
- Lucas numbers :func:`lucas_number1`, :func:`lucas_number2`
|
|
24
|
+
|
|
25
|
+
- Stirling numbers :func:`stirling_number1`, :func:`stirling_number2`
|
|
26
|
+
|
|
27
|
+
- Polygonal numbers :func:`polygonal_number`
|
|
28
|
+
|
|
29
|
+
**Polynomials**
|
|
30
|
+
|
|
31
|
+
- Eulerian polynomial :func:`eulerian_polynomial`
|
|
32
|
+
|
|
33
|
+
- Bernoulli polynomials :func:`bernoulli_polynomial`
|
|
34
|
+
|
|
35
|
+
**Sets:**
|
|
36
|
+
|
|
37
|
+
- Tuples of a multiset :func:`tuples`, :func:`number_of_tuples`
|
|
38
|
+
|
|
39
|
+
- Unordered tuples of a set :func:`unordered_tuples`, :func:`number_of_unordered_tuples`
|
|
40
|
+
|
|
41
|
+
**Combinatorial functions from other modules:**
|
|
42
|
+
|
|
43
|
+
- Binomial coefficient :func:`sage.arith.misc.binomial`
|
|
44
|
+
|
|
45
|
+
- Factorial :func:`sage.arith.misc.factorial`
|
|
46
|
+
|
|
47
|
+
- Falling power :func:`sage.arith.misc.falling_factorial`
|
|
48
|
+
|
|
49
|
+
- Rising power :func:`sage.arith.misc.rising_factorial`
|
|
50
|
+
|
|
51
|
+
- Number of partitions :func:`sage.combinat.partition.number_of_partitions`
|
|
52
|
+
|
|
53
|
+
- Gaussian binomial coefficient :func:`sage.combinat.q_analogues.gaussian_binomial`
|
|
54
|
+
|
|
55
|
+
.. TODO::
|
|
56
|
+
|
|
57
|
+
Add GUAVA commands:
|
|
58
|
+
|
|
59
|
+
* VandermondeMat
|
|
60
|
+
* GrayMat returns a list of all different vectors of length n over
|
|
61
|
+
the field F, using Gray ordering.
|
|
62
|
+
|
|
63
|
+
Add commands not in GAP:
|
|
64
|
+
|
|
65
|
+
* Rencontres numbers (:wikipedia:`Rencontres_number`)
|
|
66
|
+
|
|
67
|
+
REFERENCES:
|
|
68
|
+
|
|
69
|
+
- :wikipedia:`Twelvefold_way`
|
|
70
|
+
|
|
71
|
+
AUTHORS:
|
|
72
|
+
|
|
73
|
+
- David Joyner (2006-07): initial implementation
|
|
74
|
+
- William Stein (2006-07): editing of docs and code; many
|
|
75
|
+
optimizations, refinements, and bug fixes in corner cases
|
|
76
|
+
- Jon Hanke (2006-08): added ``tuples``
|
|
77
|
+
- David Joyner (2006-09): bug fix for combinations, added
|
|
78
|
+
permutations_iterator, combinations_iterator from Python Cookbook,
|
|
79
|
+
edited docs.
|
|
80
|
+
- David Joyner (2007-11): changed permutations, added hadamard_matrix
|
|
81
|
+
- Blair Sutton (2009-01-26): added ``bell_polynomial``
|
|
82
|
+
- Florent Hivert (2009-02): combinatorial class cleanup
|
|
83
|
+
- Bobby Moretti (2009-02): added ``fibonacci_sequence`` and ``fibonacci_xrange``
|
|
84
|
+
- Fredrik Johansson (2010-07): fast implementation of ``stirling_number2``
|
|
85
|
+
- Robert Gerbicz (2010-10): added Bell numbers
|
|
86
|
+
- Punarbasu Purkayastha (2012-12): deprecate arrangements, combinations,
|
|
87
|
+
combinations_iterator, and clean up very old deprecated methods.
|
|
88
|
+
- Jeroen Demeyer (2014-10): improved implementation of Dobinski formula for Bell numbers
|
|
89
|
+
with more accurate error estimates (:issue:`17157`)
|
|
90
|
+
- Thierry Monteil (2015-09-29): the result of ``bell_polynomial`` must
|
|
91
|
+
always be a polynomial
|
|
92
|
+
- Kei Beauduin (2024-04-06): when univariate, the Bell polynomial is in
|
|
93
|
+
variable ``x0``; extended to complete exponential, partial ordinary and
|
|
94
|
+
complete ordinary Bell polynomials.
|
|
95
|
+
- Kwankyu Lee (2025-01): added Lah numbers
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
# ****************************************************************************
|
|
99
|
+
# Copyright (C) 2006 David Joyner <wdjoyner@gmail.com>
|
|
100
|
+
# 2007-2009 Mike Hansen <mhansen@gmail.com>
|
|
101
|
+
# 2006 William Stein <wstein@gmail.com>
|
|
102
|
+
# 2009 Blair Sutton
|
|
103
|
+
# 2009 Craig Citro
|
|
104
|
+
# 2009-2010 Florent Hivert
|
|
105
|
+
# 2010 Francis Clarke
|
|
106
|
+
# 2010 Fredrik Johansson
|
|
107
|
+
# 2010 Robert Gerbicz
|
|
108
|
+
# 2010-2013 Nathann Cohen
|
|
109
|
+
# 2012 Christian Stump
|
|
110
|
+
# 2013-2015 Travis Scrimshaw
|
|
111
|
+
# 2014 Volker Braun
|
|
112
|
+
# 2014-2015 Darij Grinberg
|
|
113
|
+
# 2014-2015 Jeroen Demeyer
|
|
114
|
+
# 2014-2021 Frédéric Chapoton
|
|
115
|
+
# 2015 Thierry Monteil
|
|
116
|
+
# 2019 Christian Nassau
|
|
117
|
+
# 2019-2020 Alex Shearer
|
|
118
|
+
#
|
|
119
|
+
# This program is free software: you can redistribute it and/or modify
|
|
120
|
+
# it under the terms of the GNU General Public License as published by
|
|
121
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
122
|
+
# (at your option) any later version.
|
|
123
|
+
# https://www.gnu.org/licenses/
|
|
124
|
+
# ****************************************************************************
|
|
125
|
+
from __future__ import annotations
|
|
126
|
+
from collections.abc import Iterator
|
|
127
|
+
|
|
128
|
+
from sage.arith.misc import bernoulli, factorial
|
|
129
|
+
from sage.rings.integer_ring import ZZ
|
|
130
|
+
from sage.rings.rational_field import QQ
|
|
131
|
+
from sage.rings.integer import Integer
|
|
132
|
+
from sage.rings.polynomial.polynomial_element import Polynomial
|
|
133
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
|
134
|
+
from sage.misc.misc_c import prod
|
|
135
|
+
from sage.misc.cachefunc import cached_function
|
|
136
|
+
from sage.structure.sage_object import SageObject
|
|
137
|
+
from sage.misc.lazy_import import lazy_import
|
|
138
|
+
from .combinat_cython import _stirling_number2
|
|
139
|
+
from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass
|
|
140
|
+
from sage.structure.element import Element
|
|
141
|
+
|
|
142
|
+
lazy_import('sage.interfaces.maxima_lib', 'maxima')
|
|
143
|
+
lazy_import('sage.libs.pari', 'pari')
|
|
144
|
+
lazy_import('sage.misc.prandom', 'randint')
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def bell_number(n, algorithm='flint', **options) -> Integer:
|
|
148
|
+
r"""
|
|
149
|
+
Return the `n`-th Bell number.
|
|
150
|
+
|
|
151
|
+
This is the number of ways to partition a set
|
|
152
|
+
of `n` elements into pairwise disjoint nonempty subsets.
|
|
153
|
+
|
|
154
|
+
INPUT:
|
|
155
|
+
|
|
156
|
+
- ``n`` -- positive integer
|
|
157
|
+
|
|
158
|
+
- ``algorithm`` -- (default: ``'flint'``) any one of the following:
|
|
159
|
+
|
|
160
|
+
- ``'dobinski'`` -- use Dobinski's formula
|
|
161
|
+
|
|
162
|
+
- ``'flint'`` -- wrap FLINT's ``arith_bell_number``
|
|
163
|
+
|
|
164
|
+
- ``'gap'`` -- wrap GAP's ``Bell``
|
|
165
|
+
|
|
166
|
+
- ``'mpmath'`` -- wrap mpmath's ``bell``
|
|
167
|
+
|
|
168
|
+
.. WARNING::
|
|
169
|
+
|
|
170
|
+
When using the mpmath algorithm to compute Bell numbers and you specify
|
|
171
|
+
``prec``, it can return incorrect results due to low precision. See
|
|
172
|
+
the examples section.
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
EXAMPLES::
|
|
176
|
+
|
|
177
|
+
sage: # needs sage.libs.flint
|
|
178
|
+
sage: bell_number(10)
|
|
179
|
+
115975
|
|
180
|
+
sage: bell_number(2)
|
|
181
|
+
2
|
|
182
|
+
sage: bell_number(-10)
|
|
183
|
+
Traceback (most recent call last):
|
|
184
|
+
...
|
|
185
|
+
ArithmeticError: Bell numbers not defined for negative indices
|
|
186
|
+
sage: bell_number(1)
|
|
187
|
+
1
|
|
188
|
+
sage: bell_number(1/3)
|
|
189
|
+
Traceback (most recent call last):
|
|
190
|
+
...
|
|
191
|
+
TypeError: no conversion of this rational to integer
|
|
192
|
+
|
|
193
|
+
When using the mpmath algorithm, we are required have mpmath's precision
|
|
194
|
+
set to at least `\log_2(B_n)` bits. If upon computing the Bell number the
|
|
195
|
+
first time, we deem the precision too low, we use our guess to
|
|
196
|
+
(temporarily) raise mpmath's precision and the Bell number is recomputed. ::
|
|
197
|
+
|
|
198
|
+
sage: k = bell_number(30, 'mpmath'); k # needs mpmath
|
|
199
|
+
846749014511809332450147
|
|
200
|
+
sage: k == bell_number(30) # needs mpmath sage.libs.flint
|
|
201
|
+
True
|
|
202
|
+
|
|
203
|
+
If you knows what precision is necessary before computing the Bell number,
|
|
204
|
+
you can use the ``prec`` option::
|
|
205
|
+
|
|
206
|
+
sage: k2 = bell_number(30, 'mpmath', prec=30); k2 # needs mpmath
|
|
207
|
+
846749014511809332450147
|
|
208
|
+
sage: k == k2 # needs mpmath
|
|
209
|
+
True
|
|
210
|
+
|
|
211
|
+
.. WARNING::
|
|
212
|
+
|
|
213
|
+
Running mpmath with the precision set too low can result in
|
|
214
|
+
incorrect results::
|
|
215
|
+
|
|
216
|
+
sage: k = bell_number(30, 'mpmath', prec=15); k # needs mpmath
|
|
217
|
+
846749014511809388871680
|
|
218
|
+
sage: k == bell_number(30) # needs mpmath sage.libs.flint
|
|
219
|
+
False
|
|
220
|
+
|
|
221
|
+
TESTS::
|
|
222
|
+
|
|
223
|
+
sage: all(bell_number(n) == bell_number(n,'dobinski') for n in range(100)) # needs sage.libs.flint
|
|
224
|
+
True
|
|
225
|
+
sage: all(bell_number(n) == bell_number(n,'gap') for n in range(100)) # needs sage.libs.flint sage.libs.gap
|
|
226
|
+
True
|
|
227
|
+
sage: all(bell_number(n) == bell_number(n,'mpmath', prec=500) # needs mpmath sage.libs.flint
|
|
228
|
+
....: for n in range(200, 220))
|
|
229
|
+
True
|
|
230
|
+
|
|
231
|
+
.. NOTE::
|
|
232
|
+
|
|
233
|
+
Let `B_n` denote the `n`-th Bell number. Dobinski's formula is:
|
|
234
|
+
|
|
235
|
+
.. MATH::
|
|
236
|
+
|
|
237
|
+
B_n = e^{-1} \sum_{k=0}^{\infty} \frac{k^n}{k!}.
|
|
238
|
+
|
|
239
|
+
To show our implementation of Dobinski's method works, suppose that `n \geq 5`
|
|
240
|
+
and let `k_0` be the smallest positive integer such that `\frac{k_0^n}{k_0!} < 1`.
|
|
241
|
+
Note that `k_0 > n` and `k_0 \leq 2n` because we can prove that
|
|
242
|
+
`\frac{(2n)^n}{(2n)!} < 1` by Stirling.
|
|
243
|
+
|
|
244
|
+
If `k > k_0`, then we have `\frac{k^n}{k!} < \frac{1}{2^{k-k_0}}`.
|
|
245
|
+
We show this by induction:
|
|
246
|
+
let `c_k = \frac{k^n}{k!}`, if `k > n` then
|
|
247
|
+
|
|
248
|
+
.. MATH::
|
|
249
|
+
|
|
250
|
+
\frac{c_{k+1}}{c_k} = \frac{(1+k^{-1})^n}{k+1} < \frac{(1+n^{-1})^n}{n}
|
|
251
|
+
< \frac{1}{2}.
|
|
252
|
+
|
|
253
|
+
The last inequality can easily be checked numerically for `n \geq 5`.
|
|
254
|
+
|
|
255
|
+
Using this, we can see that `\frac{c_k}{c_{k_0}} < \frac{1}{2^{k-k_0}}`
|
|
256
|
+
for `k > k_0 > n`. So summing this it gives that `\sum_{k=k_0+1}^{\infty}
|
|
257
|
+
\frac{k^n}{k!} < 1`, and hence
|
|
258
|
+
|
|
259
|
+
.. MATH::
|
|
260
|
+
|
|
261
|
+
B_n = e^{-1} \left( \sum_{k=0}^{k_0} \frac{k^n}{k!} + E_1 \right)
|
|
262
|
+
= e^{-1} \sum_{k=0}^{k_0} \frac{k^n}{k!} + E_2,
|
|
263
|
+
|
|
264
|
+
where `0 < E_1 < 1` and `0 < E_2 < e^{-1}`. Next we have for any `q > 0`
|
|
265
|
+
|
|
266
|
+
.. MATH::
|
|
267
|
+
|
|
268
|
+
\sum_{k=0}^{k_0} \frac{k^n}{k!} = \frac{1}{q} \sum_{k=0}^{k_0} \left\lfloor
|
|
269
|
+
\frac{q k^n}{k!} \right\rfloor + \frac{E_3}{q}
|
|
270
|
+
|
|
271
|
+
where `0 \leq E_3 \leq k_0 + 1 \leq 2n + 1`. Let `E_4 = \frac{E_3}{q}`
|
|
272
|
+
and let `q = 2n + 1`. We find `0 \leq E_4 \leq 1`. These two bounds give:
|
|
273
|
+
|
|
274
|
+
.. MATH::
|
|
275
|
+
|
|
276
|
+
\begin{aligned}
|
|
277
|
+
B_n & = \frac{e^{-1}}{q} \sum_{k=0}^{k_0} \left\lfloor
|
|
278
|
+
\frac{q k^n}{k!} \right\rfloor + e^{-1} E_4 + E_2 \\
|
|
279
|
+
& = \frac{e^{-1}}{q} \sum_{k=0}^{k_0} \left\lfloor \frac{q k^n}{k!}
|
|
280
|
+
\right\rfloor + E_5
|
|
281
|
+
\end{aligned}
|
|
282
|
+
|
|
283
|
+
where
|
|
284
|
+
|
|
285
|
+
.. MATH::
|
|
286
|
+
|
|
287
|
+
0 < E_5 = e^{-1} E_4 + E_2 \leq e^{-1} + e^{-1} < \frac{3}{4}.
|
|
288
|
+
|
|
289
|
+
It follows that
|
|
290
|
+
|
|
291
|
+
.. MATH::
|
|
292
|
+
|
|
293
|
+
B_n = \left\lceil \frac{e^{-1}}{q} \sum_{k=0}^{k_0} \left\lfloor
|
|
294
|
+
\frac{q k^n}{k!} \right\rfloor \right\rceil.
|
|
295
|
+
|
|
296
|
+
Now define
|
|
297
|
+
|
|
298
|
+
.. MATH::
|
|
299
|
+
|
|
300
|
+
b = \sum_{k=0}^{k_0} \left\lfloor \frac{q k^n}{k!} \right\rfloor.
|
|
301
|
+
|
|
302
|
+
This `b` can be computed exactly using integer arithmetic.
|
|
303
|
+
To avoid the costly integer division by `k!`, we collect
|
|
304
|
+
more terms and do only one division, for example with 3 terms:
|
|
305
|
+
|
|
306
|
+
.. MATH::
|
|
307
|
+
|
|
308
|
+
\frac{k^n}{k!} + \frac{(k+1)^n}{(k+1)!} + \frac{(k+2)^n}{(k+2)!}
|
|
309
|
+
= \frac{k^n (k+1)(k+2) + (k+1)^n (k+2) + (k+2)^n}{(k+2)!}
|
|
310
|
+
|
|
311
|
+
In the implementation, we collect `\sqrt{n}/2` terms.
|
|
312
|
+
|
|
313
|
+
To actually compute `B_n` from `b`,
|
|
314
|
+
we let `p = \lfloor \log_2(b) \rfloor + 1` such that `b < 2^p` and
|
|
315
|
+
we compute with `p` bits of precision.
|
|
316
|
+
This implies that `b` (and `q < b`) can be represented exactly.
|
|
317
|
+
|
|
318
|
+
We compute `\frac{e^{-1}}{q} b`, rounding down, and we must have an
|
|
319
|
+
absolute error of at most `1/4` (given that `E_5 < 3/4`).
|
|
320
|
+
This means that we need a relative error of at most
|
|
321
|
+
|
|
322
|
+
.. MATH::
|
|
323
|
+
|
|
324
|
+
\frac{e q}{4 b} > \frac{(e q)/4}{2^p} > \frac{7}{2^p}
|
|
325
|
+
|
|
326
|
+
(assuming `n \geq 5`).
|
|
327
|
+
With a precision of `p` bits and rounding down, every rounding
|
|
328
|
+
has a relative error of at most `2^{1-p} = 2/2^p`.
|
|
329
|
+
Since we do 3 roundings (`b` and `q` do not require rounding),
|
|
330
|
+
we get a relative error of at most `6/2^p`.
|
|
331
|
+
All this implies that the precision of `p` bits is sufficient.
|
|
332
|
+
|
|
333
|
+
REFERENCES:
|
|
334
|
+
|
|
335
|
+
- :wikipedia:`Bell_number`
|
|
336
|
+
- http://fredrik-j.blogspot.com/2009/03/computing-generalized-bell-numbers.html
|
|
337
|
+
- http://mathworld.wolfram.com/DobinskisFormula.html
|
|
338
|
+
"""
|
|
339
|
+
n = ZZ(n)
|
|
340
|
+
if n < 0:
|
|
341
|
+
raise ArithmeticError('Bell numbers not defined for negative indices')
|
|
342
|
+
if algorithm == 'mpmath':
|
|
343
|
+
from sage.libs.mpmath.all import bell, mp, mag
|
|
344
|
+
old_prec = mp.dps
|
|
345
|
+
if 'prec' in options:
|
|
346
|
+
mp.dps = options['prec']
|
|
347
|
+
ret = ZZ(int(bell(n)))
|
|
348
|
+
mp.dps = old_prec
|
|
349
|
+
return ret
|
|
350
|
+
ret_mp = bell(n)
|
|
351
|
+
p = mag(ret_mp) + 10
|
|
352
|
+
if p > mp.dps:
|
|
353
|
+
mp.dps = p
|
|
354
|
+
ret = ZZ(int(bell(n)))
|
|
355
|
+
mp.dps = old_prec
|
|
356
|
+
return ret
|
|
357
|
+
return ZZ(int(ret_mp))
|
|
358
|
+
|
|
359
|
+
elif algorithm == 'flint':
|
|
360
|
+
import sage.libs.flint.arith_sage
|
|
361
|
+
return sage.libs.flint.arith_sage.bell_number(n)
|
|
362
|
+
|
|
363
|
+
elif algorithm == 'gap':
|
|
364
|
+
from sage.libs.gap.libgap import libgap
|
|
365
|
+
return libgap.Bell(n).sage()
|
|
366
|
+
|
|
367
|
+
elif algorithm == 'dobinski':
|
|
368
|
+
# Hardcode small cases. We only proved the algorithm below
|
|
369
|
+
# for n >= 5, but it turns out that n = 4 also works.
|
|
370
|
+
if n < 4:
|
|
371
|
+
return Integer((1, 1, 2, 5)[n])
|
|
372
|
+
b = ZZ.zero()
|
|
373
|
+
fact = k = ZZ.one()
|
|
374
|
+
q = 2 * n + 1
|
|
375
|
+
si = Integer(n).sqrtrem()[0] // 2
|
|
376
|
+
while True:
|
|
377
|
+
partfact = ZZ.one()
|
|
378
|
+
v = ZZ.zero()
|
|
379
|
+
for i in range(si - 1, -1, -1):
|
|
380
|
+
v += partfact * (k + i)**n
|
|
381
|
+
partfact *= k + i
|
|
382
|
+
fact *= partfact
|
|
383
|
+
v = (q * v) // fact
|
|
384
|
+
if not v:
|
|
385
|
+
break
|
|
386
|
+
b += v
|
|
387
|
+
k += si
|
|
388
|
+
from sage.rings.real_mpfr import RealField
|
|
389
|
+
R = RealField(b.exact_log(2) + 1, rnd='RNDD')
|
|
390
|
+
return ((R(-1).exp() / q) * b).ceil()
|
|
391
|
+
|
|
392
|
+
raise ValueError("unknown algorithm %r" % algorithm)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def catalan_number(n):
|
|
396
|
+
r"""
|
|
397
|
+
Return the `n`-th Catalan number.
|
|
398
|
+
|
|
399
|
+
The `n`-th Catalan number is given
|
|
400
|
+
directly in terms of binomial coefficients by
|
|
401
|
+
|
|
402
|
+
.. MATH::
|
|
403
|
+
|
|
404
|
+
C_n = \frac{1}{n+1}\binom{2n}{n} = \frac{(2n)!}{(n+1)!\,n!}
|
|
405
|
+
\qquad\mbox{ for }\quad n\ge 0.
|
|
406
|
+
|
|
407
|
+
Consider the set `S = \{ 1, ..., n \}`. A noncrossing
|
|
408
|
+
partition of `S` is a partition in which no two blocks
|
|
409
|
+
"cross" each other, i.e., if `a` and `b` belong to one block and
|
|
410
|
+
`x` and `y` to another, they are not arranged in the order `axby`.
|
|
411
|
+
`C_n` is the number of noncrossing partitions of the set
|
|
412
|
+
`S`. There are many other interpretations (see REFERENCES).
|
|
413
|
+
|
|
414
|
+
When `n=-1`, this function returns the limit value `-1/2`. For
|
|
415
|
+
other `n<0` it returns `0`.
|
|
416
|
+
|
|
417
|
+
INPUT:
|
|
418
|
+
|
|
419
|
+
- ``n`` -- integer
|
|
420
|
+
|
|
421
|
+
OUTPUT: integer
|
|
422
|
+
|
|
423
|
+
EXAMPLES::
|
|
424
|
+
|
|
425
|
+
sage: [catalan_number(i) for i in range(7)]
|
|
426
|
+
[1, 1, 2, 5, 14, 42, 132]
|
|
427
|
+
sage: x = (QQ[['x']].0).O(8)
|
|
428
|
+
sage: (-1/2)*sqrt(1 - 4*x)
|
|
429
|
+
-1/2 + x + x^2 + 2*x^3 + 5*x^4 + 14*x^5 + 42*x^6 + 132*x^7 + O(x^8)
|
|
430
|
+
sage: [catalan_number(i) for i in range(-7,7)]
|
|
431
|
+
[0, 0, 0, 0, 0, 0, -1/2, 1, 1, 2, 5, 14, 42, 132]
|
|
432
|
+
sage: [catalan_number(n).mod(2) for n in range(16)]
|
|
433
|
+
[1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1]
|
|
434
|
+
|
|
435
|
+
REFERENCES:
|
|
436
|
+
|
|
437
|
+
- :wikipedia:`Catalan_number`
|
|
438
|
+
|
|
439
|
+
- http://www-history.mcs.st-andrews.ac.uk/~history/Miscellaneous/CatalanNumbers/catalan.html
|
|
440
|
+
"""
|
|
441
|
+
n = ZZ(n)
|
|
442
|
+
if n < -1:
|
|
443
|
+
return ZZ.zero()
|
|
444
|
+
if n == -1:
|
|
445
|
+
return QQ((-1, 2))
|
|
446
|
+
return (2 * n).binomial(n).divide_knowing_divisible_by(n + 1)
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def narayana_number(n: Integer, k: Integer) -> Integer:
|
|
450
|
+
r"""
|
|
451
|
+
Return the Narayana number of index ``(n, k)``.
|
|
452
|
+
|
|
453
|
+
For every integer `n \geq 1`, the sum of Narayana numbers `\sum_k N_{n,k}`
|
|
454
|
+
is the Catalan number `C_n`.
|
|
455
|
+
|
|
456
|
+
INPUT:
|
|
457
|
+
|
|
458
|
+
- ``n`` -- integer
|
|
459
|
+
|
|
460
|
+
- ``k`` -- integer between `0` and `n - 1`
|
|
461
|
+
|
|
462
|
+
OUTPUT: integer
|
|
463
|
+
|
|
464
|
+
EXAMPLES::
|
|
465
|
+
|
|
466
|
+
sage: from sage.combinat.combinat import narayana_number
|
|
467
|
+
sage: [narayana_number(3, i) for i in range(3)]
|
|
468
|
+
[1, 3, 1]
|
|
469
|
+
sage: sum(narayana_number(7,i) for i in range(7)) == catalan_number(7)
|
|
470
|
+
True
|
|
471
|
+
|
|
472
|
+
REFERENCES:
|
|
473
|
+
|
|
474
|
+
- :wikipedia:`Narayana_number`
|
|
475
|
+
"""
|
|
476
|
+
n = ZZ(n)
|
|
477
|
+
if n <= 0:
|
|
478
|
+
return ZZ.zero()
|
|
479
|
+
return (n.binomial(k + 1) * n.binomial(k)).divide_knowing_divisible_by(n)
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def euler_number(n, algorithm='flint') -> Integer:
|
|
483
|
+
"""
|
|
484
|
+
Return the `n`-th Euler number.
|
|
485
|
+
|
|
486
|
+
INPUT:
|
|
487
|
+
|
|
488
|
+
- ``n`` -- positive integer
|
|
489
|
+
|
|
490
|
+
- ``algorithm`` -- (default: ``'flint'``) any one of the following:
|
|
491
|
+
|
|
492
|
+
- ``'maxima'`` -- wraps Maxima's ``euler``
|
|
493
|
+
|
|
494
|
+
- ``'flint'`` -- wrap FLINT's ``arith_euler_number``
|
|
495
|
+
|
|
496
|
+
EXAMPLES::
|
|
497
|
+
|
|
498
|
+
sage: [euler_number(i) for i in range(10)] # needs sage.libs.flint
|
|
499
|
+
[1, 0, -1, 0, 5, 0, -61, 0, 1385, 0]
|
|
500
|
+
sage: x = PowerSeriesRing(QQ, 'x').gen().O(10)
|
|
501
|
+
sage: 2/(exp(x)+exp(-x))
|
|
502
|
+
1 - 1/2*x^2 + 5/24*x^4 - 61/720*x^6 + 277/8064*x^8 + O(x^10)
|
|
503
|
+
sage: [euler_number(i)/factorial(i) for i in range(11)] # needs sage.libs.flint
|
|
504
|
+
[1, 0, -1/2, 0, 5/24, 0, -61/720, 0, 277/8064, 0, -50521/3628800]
|
|
505
|
+
sage: euler_number(-1)
|
|
506
|
+
Traceback (most recent call last):
|
|
507
|
+
...
|
|
508
|
+
ValueError: n (=-1) must be a nonnegative integer
|
|
509
|
+
|
|
510
|
+
TESTS::
|
|
511
|
+
|
|
512
|
+
sage: euler_number(6, 'maxima') # needs sage.symbolic
|
|
513
|
+
-61
|
|
514
|
+
|
|
515
|
+
REFERENCES:
|
|
516
|
+
|
|
517
|
+
- :wikipedia:`Euler_number`
|
|
518
|
+
"""
|
|
519
|
+
n = ZZ(n)
|
|
520
|
+
if n < 0:
|
|
521
|
+
raise ValueError("n (=%s) must be a nonnegative integer" % n)
|
|
522
|
+
if algorithm == 'maxima':
|
|
523
|
+
return ZZ(maxima.euler(n)) # type:ignore
|
|
524
|
+
elif algorithm == 'flint':
|
|
525
|
+
import sage.libs.flint.arith_sage
|
|
526
|
+
return sage.libs.flint.arith_sage.euler_number(n)
|
|
527
|
+
else:
|
|
528
|
+
raise ValueError("algorithm must be 'flint' or 'maxima'")
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
@cached_function(key=lambda n, k, a: (n, k))
|
|
532
|
+
def eulerian_number(n, k, algorithm='recursive') -> Integer:
|
|
533
|
+
"""
|
|
534
|
+
Return the Eulerian number of index ``(n, k)``.
|
|
535
|
+
|
|
536
|
+
This is the coefficient of `t^k` in the Eulerian polynomial `A_n(t)`.
|
|
537
|
+
|
|
538
|
+
INPUT:
|
|
539
|
+
|
|
540
|
+
- ``n`` -- integer
|
|
541
|
+
- ``k`` -- integer between ``0`` and ``n - 1``
|
|
542
|
+
- ``algorithm`` -- ``'recursive'`` (default) or ``'formula'``
|
|
543
|
+
|
|
544
|
+
OUTPUT: integer
|
|
545
|
+
|
|
546
|
+
.. SEEALSO:: :func:`eulerian_polynomial`
|
|
547
|
+
|
|
548
|
+
EXAMPLES::
|
|
549
|
+
|
|
550
|
+
sage: from sage.combinat.combinat import eulerian_number
|
|
551
|
+
sage: [eulerian_number(5,i) for i in range(5)]
|
|
552
|
+
[1, 26, 66, 26, 1]
|
|
553
|
+
|
|
554
|
+
TESTS::
|
|
555
|
+
|
|
556
|
+
sage: [eulerian_number(6,i,"formula") for i in range(6)]
|
|
557
|
+
[1, 57, 302, 302, 57, 1]
|
|
558
|
+
sage: [eulerian_number(3,i) for i in range(-1, 4)]
|
|
559
|
+
[0, 1, 4, 1, 0]
|
|
560
|
+
"""
|
|
561
|
+
n = ZZ(n)
|
|
562
|
+
if k < 0 or k > n - 1:
|
|
563
|
+
return ZZ.zero()
|
|
564
|
+
if k == 0 or k == n - 1:
|
|
565
|
+
return ZZ.one()
|
|
566
|
+
if algorithm == "recursive":
|
|
567
|
+
s = (n - k) * eulerian_number(n - 1, k - 1, algorithm=algorithm)
|
|
568
|
+
s += (k + 1) * eulerian_number(n - 1, k, algorithm=algorithm)
|
|
569
|
+
return s
|
|
570
|
+
return sum((-1)**m * (n + 1).binomial(m) * (k + 1 - m)**n
|
|
571
|
+
for m in range(k + 1))
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
@cached_function(key=lambda n, a: n)
|
|
575
|
+
def eulerian_polynomial(n, algorithm='derivative'):
|
|
576
|
+
"""
|
|
577
|
+
Return the Eulerian polynomial of index ``n``.
|
|
578
|
+
|
|
579
|
+
This is the generating polynomial counting permutations in the
|
|
580
|
+
symmetric group `S_n` according to their number of descents.
|
|
581
|
+
|
|
582
|
+
INPUT:
|
|
583
|
+
|
|
584
|
+
- ``n`` -- integer
|
|
585
|
+
|
|
586
|
+
- ``algorithm`` -- ``'derivative'`` (default) or ``'coeffs'``
|
|
587
|
+
|
|
588
|
+
OUTPUT: polynomial in one variable ``t``
|
|
589
|
+
|
|
590
|
+
.. SEEALSO:: :func:`eulerian_number`
|
|
591
|
+
|
|
592
|
+
EXAMPLES::
|
|
593
|
+
|
|
594
|
+
sage: from sage.combinat.combinat import eulerian_polynomial
|
|
595
|
+
sage: eulerian_polynomial(5)
|
|
596
|
+
t^4 + 26*t^3 + 66*t^2 + 26*t + 1
|
|
597
|
+
|
|
598
|
+
TESTS::
|
|
599
|
+
|
|
600
|
+
sage: eulerian_polynomial(7)(1) == factorial(7)
|
|
601
|
+
True
|
|
602
|
+
|
|
603
|
+
sage: eulerian_polynomial(6, algorithm='coeffs')
|
|
604
|
+
t^5 + 57*t^4 + 302*t^3 + 302*t^2 + 57*t + 1
|
|
605
|
+
|
|
606
|
+
REFERENCES:
|
|
607
|
+
|
|
608
|
+
- :wikipedia:`Eulerian_number`
|
|
609
|
+
"""
|
|
610
|
+
n = ZZ(n)
|
|
611
|
+
R = PolynomialRing(ZZ, 't')
|
|
612
|
+
if n < 0:
|
|
613
|
+
return R.zero()
|
|
614
|
+
if n == 1:
|
|
615
|
+
return R.one()
|
|
616
|
+
t = R.gen()
|
|
617
|
+
if algorithm == 'derivative':
|
|
618
|
+
A = eulerian_polynomial(n - 1, algorithm=algorithm)
|
|
619
|
+
return t * (1 - t) * A.derivative() + (1 + (n - 1) * t) * A
|
|
620
|
+
elif algorithm == 'coeffs':
|
|
621
|
+
return R([eulerian_number(n, k, "formula") for k in range(n)])
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
def fibonacci(n, algorithm='pari') -> Integer:
|
|
625
|
+
"""
|
|
626
|
+
Return the `n`-th Fibonacci number.
|
|
627
|
+
|
|
628
|
+
The Fibonacci sequence `F_n` is defined by the initial
|
|
629
|
+
conditions `F_1 = F_2 = 1` and the recurrence relation
|
|
630
|
+
`F_{n+2} = F_{n+1} + F_n`. For negative `n` we
|
|
631
|
+
define `F_n = (-1)^{n+1}F_{-n}`, which is consistent with
|
|
632
|
+
the recurrence relation.
|
|
633
|
+
|
|
634
|
+
INPUT:
|
|
635
|
+
|
|
636
|
+
- ``algorithm`` -- string; one of
|
|
637
|
+
|
|
638
|
+
* ``'pari'`` -- (default) use the PARI C library's
|
|
639
|
+
:pari:`fibo` function
|
|
640
|
+
|
|
641
|
+
* ``'gap'`` -- use GAP's Fibonacci function
|
|
642
|
+
|
|
643
|
+
.. NOTE::
|
|
644
|
+
|
|
645
|
+
PARI is tens to hundreds of times faster than GAP here.
|
|
646
|
+
Moreover, PARI works for every large input whereas GAP does not.
|
|
647
|
+
|
|
648
|
+
EXAMPLES::
|
|
649
|
+
|
|
650
|
+
sage: fibonacci(10) # needs sage.libs.pari
|
|
651
|
+
55
|
|
652
|
+
sage: fibonacci(10, algorithm='gap') # needs sage.libs.gap
|
|
653
|
+
55
|
|
654
|
+
|
|
655
|
+
::
|
|
656
|
+
|
|
657
|
+
sage: fibonacci(-100) # needs sage.libs.pari
|
|
658
|
+
-354224848179261915075
|
|
659
|
+
sage: fibonacci(100) # needs sage.libs.pari
|
|
660
|
+
354224848179261915075
|
|
661
|
+
|
|
662
|
+
::
|
|
663
|
+
|
|
664
|
+
sage: fibonacci(0) # needs sage.libs.pari
|
|
665
|
+
0
|
|
666
|
+
sage: fibonacci(1/2)
|
|
667
|
+
Traceback (most recent call last):
|
|
668
|
+
...
|
|
669
|
+
TypeError: no conversion of this rational to integer
|
|
670
|
+
"""
|
|
671
|
+
n = ZZ(n)
|
|
672
|
+
if algorithm == 'pari':
|
|
673
|
+
return ZZ(pari(n).fibonacci())
|
|
674
|
+
elif algorithm == 'gap':
|
|
675
|
+
from sage.libs.gap.libgap import libgap
|
|
676
|
+
return libgap.Fibonacci(n).sage()
|
|
677
|
+
else:
|
|
678
|
+
raise ValueError("no algorithm {}".format(algorithm))
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
def lucas_number1(n, P, Q):
|
|
682
|
+
r"""
|
|
683
|
+
Return the `n`-th Lucas number "of the first kind" (this is not
|
|
684
|
+
standard terminology). The Lucas sequence `L^{(1)}_n` is
|
|
685
|
+
defined by the initial conditions `L^{(1)}_1 = 0`,
|
|
686
|
+
`L^{(1)}_2 = 1` and the recurrence relation
|
|
687
|
+
`L^{(1)}_{n+2} = P \cdot L^{(1)}_{n+1} - Q \cdot L^{(1)}_n`.
|
|
688
|
+
|
|
689
|
+
Wraps GAP's ``Lucas(...)[1]``.
|
|
690
|
+
|
|
691
|
+
`P=1`, `Q=-1` gives the Fibonacci sequence.
|
|
692
|
+
|
|
693
|
+
INPUT:
|
|
694
|
+
|
|
695
|
+
- ``n`` -- integer
|
|
696
|
+
|
|
697
|
+
- ``P``, ``Q`` -- integer or rational numbers
|
|
698
|
+
|
|
699
|
+
OUTPUT: integer or rational number
|
|
700
|
+
|
|
701
|
+
EXAMPLES::
|
|
702
|
+
|
|
703
|
+
sage: # needs sage.libs.gap
|
|
704
|
+
sage: lucas_number1(5,1,-1)
|
|
705
|
+
5
|
|
706
|
+
sage: lucas_number1(6,1,-1)
|
|
707
|
+
8
|
|
708
|
+
sage: lucas_number1(7,1,-1)
|
|
709
|
+
13
|
|
710
|
+
sage: lucas_number1(7,1,-2)
|
|
711
|
+
43
|
|
712
|
+
sage: lucas_number1(5,2,3/5)
|
|
713
|
+
229/25
|
|
714
|
+
sage: lucas_number1(5,2,1.5)
|
|
715
|
+
1/4
|
|
716
|
+
|
|
717
|
+
There was a conjecture that the sequence `L_n` defined by
|
|
718
|
+
`L_{n+2} = L_{n+1} + L_n`, `L_1=1`,
|
|
719
|
+
`L_2=3`, has the property that `n` prime implies
|
|
720
|
+
that `L_n` is prime. ::
|
|
721
|
+
|
|
722
|
+
sage: def lucas(n):
|
|
723
|
+
....: return Integer((5/2)*lucas_number1(n,1,-1) + (1/2)*lucas_number2(n,1,-1))
|
|
724
|
+
sage: [[lucas(n), is_prime(lucas(n)), n+1, is_prime(n+1)] for n in range(15)] # needs sage.libs.gap
|
|
725
|
+
[[1, False, 1, False],
|
|
726
|
+
[3, True, 2, True],
|
|
727
|
+
[4, False, 3, True],
|
|
728
|
+
[7, True, 4, False],
|
|
729
|
+
[11, True, 5, True],
|
|
730
|
+
[18, False, 6, False],
|
|
731
|
+
[29, True, 7, True],
|
|
732
|
+
[47, True, 8, False],
|
|
733
|
+
[76, False, 9, False],
|
|
734
|
+
[123, False, 10, False],
|
|
735
|
+
[199, True, 11, True],
|
|
736
|
+
[322, False, 12, False],
|
|
737
|
+
[521, True, 13, True],
|
|
738
|
+
[843, False, 14, False],
|
|
739
|
+
[1364, False, 15, False]]
|
|
740
|
+
|
|
741
|
+
Can you use Sage to find a counterexample to the conjecture?
|
|
742
|
+
"""
|
|
743
|
+
n = ZZ(n)
|
|
744
|
+
P = QQ(P)
|
|
745
|
+
Q = QQ(Q)
|
|
746
|
+
from sage.libs.gap.libgap import libgap
|
|
747
|
+
return libgap.Lucas(P, Q, n)[0].sage()
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
def lucas_number2(n, P, Q):
|
|
751
|
+
r"""
|
|
752
|
+
Return the `n`-th Lucas number "of the second kind" (this is not
|
|
753
|
+
standard terminology). The Lucas sequence `L^{(2)}_n` is
|
|
754
|
+
defined by the initial conditions `L^{(2)}_1 = 2`,
|
|
755
|
+
`L^{(2)}_2 = P` and the recurrence relation
|
|
756
|
+
`L^{(2)}_{n+2} = P \cdot L^{(2)}_{n+1} - Q \cdot L^{(2)}_n`.
|
|
757
|
+
|
|
758
|
+
INPUT:
|
|
759
|
+
|
|
760
|
+
- ``n`` -- integer
|
|
761
|
+
|
|
762
|
+
- ``P``, ``Q`` -- integer or rational numbers
|
|
763
|
+
|
|
764
|
+
OUTPUT: integer or rational number
|
|
765
|
+
|
|
766
|
+
EXAMPLES::
|
|
767
|
+
|
|
768
|
+
sage: [lucas_number2(i,1,-1) for i in range(10)] # needs sage.libs.gap
|
|
769
|
+
[2, 1, 3, 4, 7, 11, 18, 29, 47, 76]
|
|
770
|
+
sage: [fibonacci(i-1)+fibonacci(i+1) for i in range(10)] # needs sage.libs.pari
|
|
771
|
+
[2, 1, 3, 4, 7, 11, 18, 29, 47, 76]
|
|
772
|
+
|
|
773
|
+
::
|
|
774
|
+
|
|
775
|
+
sage: # needs sage.libs.gap
|
|
776
|
+
sage: n = lucas_number2(5,2,3); n
|
|
777
|
+
2
|
|
778
|
+
sage: type(n)
|
|
779
|
+
<class 'sage.rings.integer.Integer'>
|
|
780
|
+
sage: n = lucas_number2(5,2,-3/9); n
|
|
781
|
+
418/9
|
|
782
|
+
sage: type(n)
|
|
783
|
+
<class 'sage.rings.rational.Rational'>
|
|
784
|
+
|
|
785
|
+
The case `P=1`, `Q=-1` is the Lucas sequence in Brualdi's Introductory
|
|
786
|
+
Combinatorics, 4th ed., Prentice-Hall, 2004::
|
|
787
|
+
|
|
788
|
+
sage: [lucas_number2(n,1,-1) for n in range(10)] # needs sage.libs.gap
|
|
789
|
+
[2, 1, 3, 4, 7, 11, 18, 29, 47, 76]
|
|
790
|
+
"""
|
|
791
|
+
n = ZZ(n)
|
|
792
|
+
P = QQ(P)
|
|
793
|
+
Q = QQ(Q)
|
|
794
|
+
from sage.libs.gap.libgap import libgap
|
|
795
|
+
return libgap.Lucas(P, Q, n)[1].sage()
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
def stirling_number1(n, k, algorithm='gap') -> Integer:
|
|
799
|
+
r"""
|
|
800
|
+
Return the `n`-th Stirling number `S_1(n,k)` of the first kind.
|
|
801
|
+
|
|
802
|
+
This is the number of permutations of `n` points with `k` cycles.
|
|
803
|
+
|
|
804
|
+
See :wikipedia:`Stirling_numbers_of_the_first_kind`.
|
|
805
|
+
|
|
806
|
+
INPUT:
|
|
807
|
+
|
|
808
|
+
- ``n`` -- nonnegative machine-size integer
|
|
809
|
+
- ``k`` -- nonnegative machine-size integer
|
|
810
|
+
- ``algorithm``:
|
|
811
|
+
|
|
812
|
+
* ``'gap'`` -- default; use GAP's ``Stirling1`` function
|
|
813
|
+
* ``'flint'`` -- use flint's ``arith_stirling_number_1u`` function
|
|
814
|
+
|
|
815
|
+
EXAMPLES::
|
|
816
|
+
|
|
817
|
+
sage: # needs sage.libs.gap
|
|
818
|
+
sage: stirling_number1(3,2)
|
|
819
|
+
3
|
|
820
|
+
sage: stirling_number1(5,2)
|
|
821
|
+
50
|
|
822
|
+
sage: 9*stirling_number1(9,5) + stirling_number1(9,4)
|
|
823
|
+
269325
|
|
824
|
+
sage: stirling_number1(10,5)
|
|
825
|
+
269325
|
|
826
|
+
|
|
827
|
+
Indeed, `S_1(n,k) = S_1(n-1,k-1) + (n-1)S_1(n-1,k)`.
|
|
828
|
+
|
|
829
|
+
TESTS::
|
|
830
|
+
|
|
831
|
+
sage: stirling_number1(10,5, algorithm='flint') # needs sage.libs.flint
|
|
832
|
+
269325
|
|
833
|
+
|
|
834
|
+
sage: s_sage = stirling_number1(50,3, algorithm='mutta')
|
|
835
|
+
Traceback (most recent call last):
|
|
836
|
+
...
|
|
837
|
+
ValueError: unknown algorithm: mutta
|
|
838
|
+
"""
|
|
839
|
+
n = ZZ(n)
|
|
840
|
+
k = ZZ(k)
|
|
841
|
+
if k > n:
|
|
842
|
+
return ZZ.zero()
|
|
843
|
+
if k == 0:
|
|
844
|
+
return ZZ.zero() if n else ZZ.one()
|
|
845
|
+
if algorithm == 'gap':
|
|
846
|
+
from sage.libs.gap.libgap import libgap
|
|
847
|
+
return libgap.Stirling1(n, k).sage()
|
|
848
|
+
if algorithm == 'flint':
|
|
849
|
+
import sage.libs.flint.arith_sage
|
|
850
|
+
return sage.libs.flint.arith_sage.stirling_number_1(n, k)
|
|
851
|
+
raise ValueError("unknown algorithm: %s" % algorithm)
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
def stirling_number2(n, k, algorithm=None) -> Integer:
|
|
855
|
+
r"""
|
|
856
|
+
Return the `n`-th Stirling number `S_2(n,k)` of the second kind.
|
|
857
|
+
|
|
858
|
+
This is the number of ways to partition a set of `n` elements into `k`
|
|
859
|
+
pairwise disjoint nonempty subsets. The `n`-th Bell number is the
|
|
860
|
+
sum of the `S_2(n,k)`'s, `k=0,...,n`.
|
|
861
|
+
|
|
862
|
+
See :wikipedia:`Stirling_numbers_of_the_second_kind`.
|
|
863
|
+
|
|
864
|
+
INPUT:
|
|
865
|
+
|
|
866
|
+
- ``n`` -- nonnegative machine-size integer
|
|
867
|
+
- ``k`` -- nonnegative machine-size integer
|
|
868
|
+
- ``algorithm``:
|
|
869
|
+
|
|
870
|
+
* ``None`` -- default; use native implementation
|
|
871
|
+
* ``'flint'`` -- use flint's ``arith_stirling_number_2`` function
|
|
872
|
+
* ``'gap'`` -- use GAP's ``Stirling2`` function
|
|
873
|
+
* ``'maxima'`` -- use Maxima's ``stirling2`` function
|
|
874
|
+
|
|
875
|
+
EXAMPLES:
|
|
876
|
+
|
|
877
|
+
Print a table of the first several Stirling numbers of the second kind::
|
|
878
|
+
|
|
879
|
+
sage: for n in range(10):
|
|
880
|
+
....: for k in range(10):
|
|
881
|
+
....: print(str(stirling_number2(n,k)).rjust(k and 6))
|
|
882
|
+
1 0 0 0 0 0 0 0 0 0
|
|
883
|
+
0 1 0 0 0 0 0 0 0 0
|
|
884
|
+
0 1 1 0 0 0 0 0 0 0
|
|
885
|
+
0 1 3 1 0 0 0 0 0 0
|
|
886
|
+
0 1 7 6 1 0 0 0 0 0
|
|
887
|
+
0 1 15 25 10 1 0 0 0 0
|
|
888
|
+
0 1 31 90 65 15 1 0 0 0
|
|
889
|
+
0 1 63 301 350 140 21 1 0 0
|
|
890
|
+
0 1 127 966 1701 1050 266 28 1 0
|
|
891
|
+
0 1 255 3025 7770 6951 2646 462 36 1
|
|
892
|
+
|
|
893
|
+
Stirling numbers satisfy `S_2(n,k) = S_2(n-1,k-1) + kS_2(n-1,k)`::
|
|
894
|
+
|
|
895
|
+
sage: 5*stirling_number2(9,5) + stirling_number2(9,4)
|
|
896
|
+
42525
|
|
897
|
+
sage: stirling_number2(10,5)
|
|
898
|
+
42525
|
|
899
|
+
|
|
900
|
+
TESTS::
|
|
901
|
+
|
|
902
|
+
sage: stirling_number2(500,501)
|
|
903
|
+
0
|
|
904
|
+
sage: stirling_number2(500,500)
|
|
905
|
+
1
|
|
906
|
+
sage: stirling_number2(500,499)
|
|
907
|
+
124750
|
|
908
|
+
sage: stirling_number2(500,498)
|
|
909
|
+
7739801875
|
|
910
|
+
sage: stirling_number2(500,497)
|
|
911
|
+
318420320812125
|
|
912
|
+
sage: stirling_number2(500,0)
|
|
913
|
+
0
|
|
914
|
+
sage: stirling_number2(500,1)
|
|
915
|
+
1
|
|
916
|
+
sage: stirling_number2(500,2)
|
|
917
|
+
1636695303948070935006594848413799576108321023021532394741645684048066898202337277441635046162952078575443342063780035504608628272942696526664263794687
|
|
918
|
+
sage: stirling_number2(500,3)
|
|
919
|
+
6060048632644989473730877846590553186337230837666937173391005972096766698597315914033083073801260849147094943827552228825899880265145822824770663507076289563105426204030498939974727520682393424986701281896187487826395121635163301632473646
|
|
920
|
+
sage: stirling_number2(500,30)
|
|
921
|
+
13707767141249454929449108424328432845001327479099713037876832759323918134840537229737624018908470350134593241314462032607787062188356702932169472820344473069479621239187226765307960899083230982112046605340713218483809366970996051181537181362810003701997334445181840924364501502386001705718466534614548056445414149016614254231944272872440803657763210998284198037504154374028831561296154209804833852506425742041757849726214683321363035774104866182331315066421119788248419742922490386531970053376982090046434022248364782970506521655684518998083846899028416459701847828711541840099891244700173707021989771147674432503879702222276268661726508226951587152781439224383339847027542755222936463527771486827849728880
|
|
922
|
+
sage: stirling_number2(500,31)
|
|
923
|
+
5832088795102666690960147007601603328246123996896731854823915012140005028360632199516298102446004084519955789799364757997824296415814582277055514048635928623579397278336292312275467402957402880590492241647229295113001728653772550743446401631832152281610081188041624848850056657889275564834450136561842528589000245319433225808712628826136700651842562516991245851618481622296716433577650218003181535097954294609857923077238362717189185577756446945178490324413383417876364657995818830270448350765700419876347023578011403646501685001538551891100379932684279287699677429566813471166558163301352211170677774072447414719380996777162087158124939742564291760392354506347716119002497998082844612434332155632097581510486912
|
|
924
|
+
sage: n = stirling_number2(20,11); n
|
|
925
|
+
1900842429486
|
|
926
|
+
sage: type(n)
|
|
927
|
+
<class 'sage.rings.integer.Integer'>
|
|
928
|
+
sage: n_gap = stirling_number2(20, 11, algorithm='gap'); n_gap # needs sage.libs.gap
|
|
929
|
+
1900842429486
|
|
930
|
+
sage: type(n_gap) # needs sage.libs.gap
|
|
931
|
+
<class 'sage.rings.integer.Integer'>
|
|
932
|
+
sage: n_flint = stirling_number2(20, 11, algorithm='flint'); n_flint # needs sage.libs.flint
|
|
933
|
+
1900842429486
|
|
934
|
+
sage: type(n_flint) # needs sage.libs.flint
|
|
935
|
+
<class 'sage.rings.integer.Integer'>
|
|
936
|
+
|
|
937
|
+
Sage's implementation splitting the computation of the Stirling
|
|
938
|
+
numbers of the second kind in two cases according to `n`, let us
|
|
939
|
+
check the result it gives agree with both flint and gap.
|
|
940
|
+
|
|
941
|
+
For `n<200`::
|
|
942
|
+
|
|
943
|
+
sage: for n in Subsets(range(100,200), 5).random_element(): # needs sage.libs.flint sage.libs.gap
|
|
944
|
+
....: for k in Subsets(range(n), 5).random_element():
|
|
945
|
+
....: s_sage = stirling_number2(n,k)
|
|
946
|
+
....: s_flint = stirling_number2(n,k, algorithm = "flint")
|
|
947
|
+
....: s_gap = stirling_number2(n,k, algorithm = "gap")
|
|
948
|
+
....: if not (s_sage == s_flint and s_sage == s_gap):
|
|
949
|
+
....: print("Error with n<200")
|
|
950
|
+
|
|
951
|
+
For `n\geq 200`::
|
|
952
|
+
|
|
953
|
+
sage: for n in Subsets(range(200,300), 5).random_element(): # needs sage.libs.flint sage.libs.gap
|
|
954
|
+
....: for k in Subsets(range(n), 5).random_element():
|
|
955
|
+
....: s_sage = stirling_number2(n,k)
|
|
956
|
+
....: s_flint = stirling_number2(n,k, algorithm = "flint")
|
|
957
|
+
....: s_gap = stirling_number2(n,k, algorithm = "gap")
|
|
958
|
+
....: if not (s_sage == s_flint and s_sage == s_gap):
|
|
959
|
+
....: print("Error with n<200")
|
|
960
|
+
|
|
961
|
+
sage: stirling_number2(20, 3, algorithm='maxima') # needs sage.symbolic
|
|
962
|
+
580606446
|
|
963
|
+
|
|
964
|
+
sage: s_sage = stirling_number2(5, 3, algorithm='namba')
|
|
965
|
+
Traceback (most recent call last):
|
|
966
|
+
...
|
|
967
|
+
ValueError: unknown algorithm: namba
|
|
968
|
+
"""
|
|
969
|
+
n = ZZ(n)
|
|
970
|
+
k = ZZ(k)
|
|
971
|
+
if k > n:
|
|
972
|
+
return ZZ.zero()
|
|
973
|
+
if k == 0:
|
|
974
|
+
return ZZ.zero() if n else ZZ.one()
|
|
975
|
+
if algorithm is None:
|
|
976
|
+
return _stirling_number2(n, k)
|
|
977
|
+
if algorithm == 'gap':
|
|
978
|
+
from sage.libs.gap.libgap import libgap
|
|
979
|
+
return libgap.Stirling2(n, k).sage()
|
|
980
|
+
if algorithm == 'flint':
|
|
981
|
+
import sage.libs.flint.arith_sage
|
|
982
|
+
return sage.libs.flint.arith_sage.stirling_number_2(n, k)
|
|
983
|
+
if algorithm == 'maxima':
|
|
984
|
+
return ZZ(maxima.stirling2(n, k)) # type:ignore
|
|
985
|
+
raise ValueError("unknown algorithm: %s" % algorithm)
|
|
986
|
+
|
|
987
|
+
|
|
988
|
+
def lah_number(n, k) -> Integer:
|
|
989
|
+
r"""
|
|
990
|
+
Return the Lah number `L(n,k)`
|
|
991
|
+
|
|
992
|
+
This is the number of ways to partition a set of `n` elements into `k`
|
|
993
|
+
pairwise disjoint nonempty linearly-ordered subsets.
|
|
994
|
+
|
|
995
|
+
This is also called the Stirling number of the third kind.
|
|
996
|
+
|
|
997
|
+
See :wikipedia:`Lah_number`.
|
|
998
|
+
|
|
999
|
+
INPUT:
|
|
1000
|
+
|
|
1001
|
+
- ``n`` -- nonnegative integer
|
|
1002
|
+
|
|
1003
|
+
- ``k`` -- nonnegative integer
|
|
1004
|
+
|
|
1005
|
+
EXAMPLES::
|
|
1006
|
+
|
|
1007
|
+
sage: from sage.combinat.combinat import lah_number
|
|
1008
|
+
sage: lah_number(50, 30)
|
|
1009
|
+
3242322638238907670866645288893161825894400000
|
|
1010
|
+
|
|
1011
|
+
We verify a well-known identity::
|
|
1012
|
+
|
|
1013
|
+
sage: S1 = stirling_number1; S2 = stirling_number2
|
|
1014
|
+
sage: all(lah_number(n, k) == sum(S1(n, j) * S2(j, k) for j in [k..n]) # needs sage.libs.gap
|
|
1015
|
+
....: for n in range(10) for k in range(10))
|
|
1016
|
+
True
|
|
1017
|
+
|
|
1018
|
+
TESTS:
|
|
1019
|
+
|
|
1020
|
+
Verify the usual convention for the degenerate case `k = 0`::
|
|
1021
|
+
|
|
1022
|
+
sage: lah_number(0, 0) == 1 and lah_number(1, 0) == 0
|
|
1023
|
+
True
|
|
1024
|
+
"""
|
|
1025
|
+
n = ZZ(n)
|
|
1026
|
+
k = ZZ(k)
|
|
1027
|
+
if k > n:
|
|
1028
|
+
return ZZ.zero()
|
|
1029
|
+
if k == 0:
|
|
1030
|
+
return ZZ.zero() if n else ZZ.one()
|
|
1031
|
+
# Exact form of the formula was chosen for performance after extensive
|
|
1032
|
+
# experiments. See Issue #39379.
|
|
1033
|
+
a = n.binomial(k)
|
|
1034
|
+
return a * k // n * a * (n - k).factorial()
|
|
1035
|
+
|
|
1036
|
+
|
|
1037
|
+
def polygonal_number(s, n):
|
|
1038
|
+
r"""
|
|
1039
|
+
Return the `n`-th `s`-gonal number.
|
|
1040
|
+
|
|
1041
|
+
Polygonal sequences are represented by dots forming a regular polygon.
|
|
1042
|
+
Two famous sequences are the triangular numbers (3rd column of Pascal's
|
|
1043
|
+
Triangle) and the square numbers. The `n`-th term in a polygonal sequence
|
|
1044
|
+
is defined by
|
|
1045
|
+
|
|
1046
|
+
.. MATH::
|
|
1047
|
+
|
|
1048
|
+
P(s, n) = \frac{n^2(s-2) - n(s-4)}{2},
|
|
1049
|
+
|
|
1050
|
+
where `s` is the number of sides of the polygon.
|
|
1051
|
+
|
|
1052
|
+
INPUT:
|
|
1053
|
+
|
|
1054
|
+
- ``s`` -- integer greater than 1; the number of sides of the polygon
|
|
1055
|
+
|
|
1056
|
+
- ``n`` -- integer; the index of the returned `s`-gonal number
|
|
1057
|
+
|
|
1058
|
+
OUTPUT: integer
|
|
1059
|
+
|
|
1060
|
+
EXAMPLES:
|
|
1061
|
+
|
|
1062
|
+
The triangular numbers::
|
|
1063
|
+
|
|
1064
|
+
sage: [polygonal_number(3, n) for n in range(10)]
|
|
1065
|
+
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
|
|
1066
|
+
|
|
1067
|
+
sage: [polygonal_number(3, n) for n in range(-10, 0)]
|
|
1068
|
+
[45, 36, 28, 21, 15, 10, 6, 3, 1, 0]
|
|
1069
|
+
|
|
1070
|
+
The square numbers::
|
|
1071
|
+
|
|
1072
|
+
sage: [polygonal_number(4, n) for n in range(10)]
|
|
1073
|
+
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
|
|
1074
|
+
|
|
1075
|
+
The pentagonal numbers::
|
|
1076
|
+
|
|
1077
|
+
sage: [polygonal_number(5, n) for n in range(10)]
|
|
1078
|
+
[0, 1, 5, 12, 22, 35, 51, 70, 92, 117]
|
|
1079
|
+
|
|
1080
|
+
The hexagonal numbers::
|
|
1081
|
+
|
|
1082
|
+
sage: [polygonal_number(6, n) for n in range(10)]
|
|
1083
|
+
[0, 1, 6, 15, 28, 45, 66, 91, 120, 153]
|
|
1084
|
+
|
|
1085
|
+
The input is converted into an integer::
|
|
1086
|
+
|
|
1087
|
+
sage: polygonal_number(3.0, 2.0)
|
|
1088
|
+
3
|
|
1089
|
+
|
|
1090
|
+
A non-integer input returns an error::
|
|
1091
|
+
|
|
1092
|
+
sage: polygonal_number(3.5, 1) # needs sage.rings.real_mpfr
|
|
1093
|
+
Traceback (most recent call last):
|
|
1094
|
+
...
|
|
1095
|
+
TypeError: Attempt to coerce non-integral RealNumber to Integer
|
|
1096
|
+
|
|
1097
|
+
`s` must be greater than 1::
|
|
1098
|
+
|
|
1099
|
+
sage: polygonal_number(1, 4)
|
|
1100
|
+
Traceback (most recent call last):
|
|
1101
|
+
...
|
|
1102
|
+
ValueError: s (=1) must be greater than 1
|
|
1103
|
+
|
|
1104
|
+
REFERENCES:
|
|
1105
|
+
|
|
1106
|
+
- :wikipedia:`Polygonal_number`
|
|
1107
|
+
"""
|
|
1108
|
+
s = ZZ(s)
|
|
1109
|
+
n = ZZ(n)
|
|
1110
|
+
if s < 2:
|
|
1111
|
+
raise ValueError("s (=%s) must be greater than 1" % s)
|
|
1112
|
+
return (((n**2) * (s - 2)) - (n * (s - 4))) // 2
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
class CombinatorialObject(SageObject):
|
|
1116
|
+
def __init__(self, l, copy=True):
|
|
1117
|
+
"""
|
|
1118
|
+
CombinatorialObject provides a thin wrapper around a list. The main
|
|
1119
|
+
differences are that __setitem__ is disabled so that
|
|
1120
|
+
CombinatorialObjects are shallowly immutable, and the intention is
|
|
1121
|
+
that they are semantically immutable.
|
|
1122
|
+
|
|
1123
|
+
Because of this, CombinatorialObjects provide a __hash__
|
|
1124
|
+
function which computes the hash of the string representation of a
|
|
1125
|
+
list and the hash of its parent's class. Thus, each
|
|
1126
|
+
CombinatorialObject should have a unique string representation.
|
|
1127
|
+
|
|
1128
|
+
.. SEEALSO::
|
|
1129
|
+
|
|
1130
|
+
:class:`CombinatorialElement` if you want a combinatorial
|
|
1131
|
+
object which is an element of a parent.
|
|
1132
|
+
|
|
1133
|
+
.. WARNING::
|
|
1134
|
+
|
|
1135
|
+
This class is slowly being deprecated. Use
|
|
1136
|
+
:class:`~sage.structure.list_clone.ClonableList` instead.
|
|
1137
|
+
|
|
1138
|
+
INPUT:
|
|
1139
|
+
|
|
1140
|
+
- ``l`` -- list or any object that can be converted to a
|
|
1141
|
+
list by calling ``list()``
|
|
1142
|
+
|
|
1143
|
+
- ``copy`` -- boolean (default: ``True``); if ``False``, then
|
|
1144
|
+
``l`` must be a ``list``, which is assigned to ``self._list``
|
|
1145
|
+
without copying
|
|
1146
|
+
|
|
1147
|
+
EXAMPLES::
|
|
1148
|
+
|
|
1149
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1150
|
+
sage: c == loads(dumps(c))
|
|
1151
|
+
True
|
|
1152
|
+
sage: c._list
|
|
1153
|
+
[1, 2, 3]
|
|
1154
|
+
sage: c._hash is None
|
|
1155
|
+
True
|
|
1156
|
+
|
|
1157
|
+
For efficiency, you can specify ``copy=False`` if you know what
|
|
1158
|
+
you are doing::
|
|
1159
|
+
|
|
1160
|
+
sage: from sage.combinat.combinat import CombinatorialObject
|
|
1161
|
+
sage: x = [3, 2, 1]
|
|
1162
|
+
sage: C = CombinatorialObject(x, copy=False)
|
|
1163
|
+
sage: C
|
|
1164
|
+
[3, 2, 1]
|
|
1165
|
+
sage: x[0] = 5
|
|
1166
|
+
sage: C
|
|
1167
|
+
[5, 2, 1]
|
|
1168
|
+
|
|
1169
|
+
TESTS:
|
|
1170
|
+
|
|
1171
|
+
Test indirectly that we copy the input (see :issue:`18184`)::
|
|
1172
|
+
|
|
1173
|
+
sage: # needs sage.combinat
|
|
1174
|
+
sage: L = IntegerListsLex(element_class=Partition)
|
|
1175
|
+
sage: x = [3, 2, 1]
|
|
1176
|
+
sage: P = L(x)
|
|
1177
|
+
sage: x[0] = 5
|
|
1178
|
+
sage: list(P)
|
|
1179
|
+
[3, 2, 1]
|
|
1180
|
+
"""
|
|
1181
|
+
if copy:
|
|
1182
|
+
self._list = list(l)
|
|
1183
|
+
else:
|
|
1184
|
+
self._list = l
|
|
1185
|
+
self._hash = None
|
|
1186
|
+
|
|
1187
|
+
def __str__(self):
|
|
1188
|
+
"""
|
|
1189
|
+
EXAMPLES::
|
|
1190
|
+
|
|
1191
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1192
|
+
sage: str(c)
|
|
1193
|
+
'[1, 2, 3]'
|
|
1194
|
+
"""
|
|
1195
|
+
return str(self._list)
|
|
1196
|
+
|
|
1197
|
+
def _repr_(self):
|
|
1198
|
+
"""
|
|
1199
|
+
EXAMPLES::
|
|
1200
|
+
|
|
1201
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1202
|
+
sage: c.__repr__()
|
|
1203
|
+
'[1, 2, 3]'
|
|
1204
|
+
"""
|
|
1205
|
+
return repr(self._list)
|
|
1206
|
+
|
|
1207
|
+
def __eq__(self, other):
|
|
1208
|
+
"""
|
|
1209
|
+
Test equality of ``self`` and ``other``.
|
|
1210
|
+
|
|
1211
|
+
EXAMPLES::
|
|
1212
|
+
|
|
1213
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1214
|
+
sage: d = CombinatorialObject([2,3,4])
|
|
1215
|
+
sage: c == [1,2,3]
|
|
1216
|
+
True
|
|
1217
|
+
sage: c == [2,3,4]
|
|
1218
|
+
False
|
|
1219
|
+
sage: c == d
|
|
1220
|
+
False
|
|
1221
|
+
sage: c == c
|
|
1222
|
+
True
|
|
1223
|
+
|
|
1224
|
+
.. WARNING::
|
|
1225
|
+
|
|
1226
|
+
:class:`CombinatorialObject` must come **before** :class:`Element`
|
|
1227
|
+
for this to work because :class:`Element` is ahead of
|
|
1228
|
+
:class:`CombinatorialObject` in the MRO (method resolution
|
|
1229
|
+
order)::
|
|
1230
|
+
|
|
1231
|
+
sage: from sage.structure.element import Element
|
|
1232
|
+
sage: class Bar(Element, CombinatorialObject):
|
|
1233
|
+
....: def __init__(self, l):
|
|
1234
|
+
....: CombinatorialObject.__init__(self, l)
|
|
1235
|
+
sage: L = [Bar([4-i]) for i in range(4)]
|
|
1236
|
+
sage: sorted(L)
|
|
1237
|
+
Traceback (most recent call last):
|
|
1238
|
+
...
|
|
1239
|
+
TypeError: '<' not supported between instances of 'Bar' and 'Bar'
|
|
1240
|
+
"""
|
|
1241
|
+
if isinstance(other, CombinatorialObject):
|
|
1242
|
+
return self._list == other._list
|
|
1243
|
+
else:
|
|
1244
|
+
return self._list == other
|
|
1245
|
+
|
|
1246
|
+
def __lt__(self, other):
|
|
1247
|
+
"""
|
|
1248
|
+
EXAMPLES::
|
|
1249
|
+
|
|
1250
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1251
|
+
sage: d = CombinatorialObject([2,3,4])
|
|
1252
|
+
sage: c < d
|
|
1253
|
+
True
|
|
1254
|
+
sage: c < [2,3,4]
|
|
1255
|
+
True
|
|
1256
|
+
sage: c < c
|
|
1257
|
+
False
|
|
1258
|
+
|
|
1259
|
+
Check that :issue:`14065` is fixed::
|
|
1260
|
+
|
|
1261
|
+
sage: from sage.structure.element import Element
|
|
1262
|
+
sage: class Foo(CombinatorialObject, Element): pass
|
|
1263
|
+
sage: L = [Foo([4-i]) for i in range(4)]; L
|
|
1264
|
+
[[4], [3], [2], [1]]
|
|
1265
|
+
sage: sorted(L)
|
|
1266
|
+
[[1], [2], [3], [4]]
|
|
1267
|
+
sage: f = Foo([4])
|
|
1268
|
+
sage: f is None
|
|
1269
|
+
False
|
|
1270
|
+
sage: f is not None
|
|
1271
|
+
True
|
|
1272
|
+
"""
|
|
1273
|
+
if isinstance(other, CombinatorialObject):
|
|
1274
|
+
return self._list < other._list
|
|
1275
|
+
else:
|
|
1276
|
+
return self._list < other
|
|
1277
|
+
|
|
1278
|
+
def __le__(self, other):
|
|
1279
|
+
"""
|
|
1280
|
+
EXAMPLES::
|
|
1281
|
+
|
|
1282
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1283
|
+
sage: d = CombinatorialObject([2,3,4])
|
|
1284
|
+
sage: c <= c
|
|
1285
|
+
True
|
|
1286
|
+
sage: c <= d
|
|
1287
|
+
True
|
|
1288
|
+
sage: c <= [1,2,3]
|
|
1289
|
+
True
|
|
1290
|
+
"""
|
|
1291
|
+
if isinstance(other, CombinatorialObject):
|
|
1292
|
+
return self._list <= other._list
|
|
1293
|
+
else:
|
|
1294
|
+
return self._list <= other
|
|
1295
|
+
|
|
1296
|
+
def __gt__(self, other):
|
|
1297
|
+
"""
|
|
1298
|
+
EXAMPLES::
|
|
1299
|
+
|
|
1300
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1301
|
+
sage: d = CombinatorialObject([2,3,4])
|
|
1302
|
+
sage: c > c
|
|
1303
|
+
False
|
|
1304
|
+
sage: c > d
|
|
1305
|
+
False
|
|
1306
|
+
sage: c > [1,2,3]
|
|
1307
|
+
False
|
|
1308
|
+
"""
|
|
1309
|
+
if isinstance(other, CombinatorialObject):
|
|
1310
|
+
return self._list > other._list
|
|
1311
|
+
else:
|
|
1312
|
+
return self._list > other
|
|
1313
|
+
|
|
1314
|
+
def __ge__(self, other):
|
|
1315
|
+
"""
|
|
1316
|
+
EXAMPLES::
|
|
1317
|
+
|
|
1318
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1319
|
+
sage: d = CombinatorialObject([2,3,4])
|
|
1320
|
+
sage: c >= c
|
|
1321
|
+
True
|
|
1322
|
+
sage: c >= d
|
|
1323
|
+
False
|
|
1324
|
+
sage: c >= [1,2,3]
|
|
1325
|
+
True
|
|
1326
|
+
"""
|
|
1327
|
+
if isinstance(other, CombinatorialObject):
|
|
1328
|
+
return self._list >= other._list
|
|
1329
|
+
else:
|
|
1330
|
+
return self._list >= other
|
|
1331
|
+
|
|
1332
|
+
def __ne__(self, other):
|
|
1333
|
+
"""
|
|
1334
|
+
EXAMPLES::
|
|
1335
|
+
|
|
1336
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1337
|
+
sage: d = CombinatorialObject([2,3,4])
|
|
1338
|
+
sage: c != c
|
|
1339
|
+
False
|
|
1340
|
+
sage: c != d
|
|
1341
|
+
True
|
|
1342
|
+
sage: c != [1,2,3]
|
|
1343
|
+
False
|
|
1344
|
+
"""
|
|
1345
|
+
if isinstance(other, CombinatorialObject):
|
|
1346
|
+
return self._list != other._list
|
|
1347
|
+
else:
|
|
1348
|
+
return self._list != other
|
|
1349
|
+
|
|
1350
|
+
def __add__(self, other):
|
|
1351
|
+
"""
|
|
1352
|
+
EXAMPLES::
|
|
1353
|
+
|
|
1354
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1355
|
+
sage: c + [4]
|
|
1356
|
+
[1, 2, 3, 4]
|
|
1357
|
+
sage: type(_)
|
|
1358
|
+
<class 'list'>
|
|
1359
|
+
"""
|
|
1360
|
+
return self._list + other
|
|
1361
|
+
|
|
1362
|
+
def __hash__(self):
|
|
1363
|
+
"""
|
|
1364
|
+
Compute the hash of ``self`` by computing the hash of the string
|
|
1365
|
+
representation of self._list. The hash is cached and stored in
|
|
1366
|
+
self._hash.
|
|
1367
|
+
|
|
1368
|
+
EXAMPLES::
|
|
1369
|
+
|
|
1370
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1371
|
+
sage: c._hash is None
|
|
1372
|
+
True
|
|
1373
|
+
sage: hash(c) #random
|
|
1374
|
+
1335416675971793195
|
|
1375
|
+
sage: c._hash #random
|
|
1376
|
+
1335416675971793195
|
|
1377
|
+
"""
|
|
1378
|
+
if self._hash is None:
|
|
1379
|
+
self._hash = hash(str(self._list))
|
|
1380
|
+
return self._hash
|
|
1381
|
+
|
|
1382
|
+
def __bool__(self) -> bool:
|
|
1383
|
+
"""
|
|
1384
|
+
Return ``True`` if ``self`` is nonzero.
|
|
1385
|
+
|
|
1386
|
+
We consider a list to be zero if it has length zero.
|
|
1387
|
+
|
|
1388
|
+
TESTS::
|
|
1389
|
+
|
|
1390
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1391
|
+
sage: not c
|
|
1392
|
+
False
|
|
1393
|
+
sage: c = CombinatorialObject([])
|
|
1394
|
+
sage: not c
|
|
1395
|
+
True
|
|
1396
|
+
|
|
1397
|
+
Check that :issue:`14065` is fixed::
|
|
1398
|
+
|
|
1399
|
+
sage: from sage.structure.element import Element
|
|
1400
|
+
sage: class Foo(CombinatorialObject, Element): pass
|
|
1401
|
+
...
|
|
1402
|
+
sage: f = Foo([4])
|
|
1403
|
+
sage: not f
|
|
1404
|
+
False
|
|
1405
|
+
sage: f = Foo([])
|
|
1406
|
+
sage: not f
|
|
1407
|
+
True
|
|
1408
|
+
|
|
1409
|
+
.. WARNING::
|
|
1410
|
+
|
|
1411
|
+
:class:`CombinatorialObject` must come **before** :class:`Element`
|
|
1412
|
+
for this to work because :class:`Element` is ahead of
|
|
1413
|
+
:class:`CombinatorialObject` in the MRO (method resolution
|
|
1414
|
+
order)::
|
|
1415
|
+
|
|
1416
|
+
sage: from sage.structure.element import Element
|
|
1417
|
+
sage: class Bar(Element, CombinatorialObject):
|
|
1418
|
+
....: def __init__(self, l):
|
|
1419
|
+
....: CombinatorialObject.__init__(self, l)
|
|
1420
|
+
sage: b = Bar([4])
|
|
1421
|
+
sage: not b
|
|
1422
|
+
False
|
|
1423
|
+
"""
|
|
1424
|
+
return bool(self._list)
|
|
1425
|
+
|
|
1426
|
+
def __len__(self) -> Integer:
|
|
1427
|
+
"""
|
|
1428
|
+
EXAMPLES::
|
|
1429
|
+
|
|
1430
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1431
|
+
sage: len(c)
|
|
1432
|
+
3
|
|
1433
|
+
sage: c.__len__()
|
|
1434
|
+
3
|
|
1435
|
+
"""
|
|
1436
|
+
return len(self._list)
|
|
1437
|
+
|
|
1438
|
+
def __getitem__(self, key):
|
|
1439
|
+
"""
|
|
1440
|
+
EXAMPLES::
|
|
1441
|
+
|
|
1442
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1443
|
+
sage: c[0]
|
|
1444
|
+
1
|
|
1445
|
+
sage: c[1:]
|
|
1446
|
+
[2, 3]
|
|
1447
|
+
sage: type(_)
|
|
1448
|
+
<class 'list'>
|
|
1449
|
+
"""
|
|
1450
|
+
return self._list[key]
|
|
1451
|
+
|
|
1452
|
+
def __iter__(self):
|
|
1453
|
+
"""
|
|
1454
|
+
EXAMPLES::
|
|
1455
|
+
|
|
1456
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1457
|
+
sage: list(iter(c))
|
|
1458
|
+
[1, 2, 3]
|
|
1459
|
+
"""
|
|
1460
|
+
return iter(self._list)
|
|
1461
|
+
|
|
1462
|
+
def __contains__(self, item):
|
|
1463
|
+
"""
|
|
1464
|
+
EXAMPLES::
|
|
1465
|
+
|
|
1466
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1467
|
+
sage: 1 in c
|
|
1468
|
+
True
|
|
1469
|
+
sage: 5 in c
|
|
1470
|
+
False
|
|
1471
|
+
"""
|
|
1472
|
+
return item in self._list
|
|
1473
|
+
|
|
1474
|
+
def index(self, key):
|
|
1475
|
+
"""
|
|
1476
|
+
EXAMPLES::
|
|
1477
|
+
|
|
1478
|
+
sage: c = CombinatorialObject([1,2,3])
|
|
1479
|
+
sage: c.index(1)
|
|
1480
|
+
0
|
|
1481
|
+
sage: c.index(3)
|
|
1482
|
+
2
|
|
1483
|
+
"""
|
|
1484
|
+
return self._list.index(key)
|
|
1485
|
+
|
|
1486
|
+
|
|
1487
|
+
class CombinatorialElement(CombinatorialObject, Element,
|
|
1488
|
+
metaclass=InheritComparisonClasscallMetaclass):
|
|
1489
|
+
"""
|
|
1490
|
+
``CombinatorialElement`` is both a :class:`CombinatorialObject`
|
|
1491
|
+
and an :class:`Element`. So it represents a list which is an
|
|
1492
|
+
element of some parent.
|
|
1493
|
+
|
|
1494
|
+
A ``CombinatorialElement`` subclass also automatically supports
|
|
1495
|
+
the ``__classcall__`` mechanism.
|
|
1496
|
+
|
|
1497
|
+
.. WARNING::
|
|
1498
|
+
|
|
1499
|
+
This class is slowly being deprecated. Use
|
|
1500
|
+
:class:`~sage.structure.list_clone.ClonableList` instead.
|
|
1501
|
+
|
|
1502
|
+
INPUT:
|
|
1503
|
+
|
|
1504
|
+
- ``parent`` -- the :class:`Parent` class for this element
|
|
1505
|
+
|
|
1506
|
+
- ``lst`` -- list or any object that can be converted to a
|
|
1507
|
+
list by calling ``list()``
|
|
1508
|
+
|
|
1509
|
+
EXAMPLES::
|
|
1510
|
+
|
|
1511
|
+
sage: # needs sage.combinat
|
|
1512
|
+
sage: from sage.combinat.combinat import CombinatorialElement
|
|
1513
|
+
sage: e = CombinatorialElement(Partitions(6), [3,2,1])
|
|
1514
|
+
sage: e == loads(dumps(e))
|
|
1515
|
+
True
|
|
1516
|
+
sage: parent(e)
|
|
1517
|
+
Partitions of the integer 6
|
|
1518
|
+
sage: list(e)
|
|
1519
|
+
[3, 2, 1]
|
|
1520
|
+
|
|
1521
|
+
Check classcalls::
|
|
1522
|
+
|
|
1523
|
+
sage: class Foo(CombinatorialElement): # needs sage.combinat
|
|
1524
|
+
....: @staticmethod
|
|
1525
|
+
....: def __classcall__(cls, x):
|
|
1526
|
+
....: return x
|
|
1527
|
+
sage: Foo(17) # needs sage.combinat
|
|
1528
|
+
17
|
|
1529
|
+
"""
|
|
1530
|
+
|
|
1531
|
+
def __init__(self, parent, *args, **kwds):
|
|
1532
|
+
"""
|
|
1533
|
+
Initialize this ``CombinatorialElement`` with a parent and a
|
|
1534
|
+
list.
|
|
1535
|
+
|
|
1536
|
+
EXAMPLES::
|
|
1537
|
+
|
|
1538
|
+
sage: from sage.combinat.combinat import CombinatorialElement
|
|
1539
|
+
sage: e = CombinatorialElement(ZZ, list=(3,2,1))
|
|
1540
|
+
sage: e._list
|
|
1541
|
+
[3, 2, 1]
|
|
1542
|
+
sage: e.parent()
|
|
1543
|
+
Integer Ring
|
|
1544
|
+
|
|
1545
|
+
TESTS::
|
|
1546
|
+
|
|
1547
|
+
sage: CombinatorialElement(ZZ)
|
|
1548
|
+
Traceback (most recent call last):
|
|
1549
|
+
...
|
|
1550
|
+
TypeError: ...__init__() takes exactly 2 arguments (1 given)
|
|
1551
|
+
sage: CombinatorialElement(ZZ, 1, 2)
|
|
1552
|
+
Traceback (most recent call last):
|
|
1553
|
+
...
|
|
1554
|
+
TypeError: ...__init__() takes exactly 2 arguments (3 given)
|
|
1555
|
+
sage: CombinatorialElement(ZZ, 1, list=2)
|
|
1556
|
+
Traceback (most recent call last):
|
|
1557
|
+
...
|
|
1558
|
+
TypeError: ...__init__() takes exactly 2 arguments (3 given)
|
|
1559
|
+
sage: CombinatorialElement(ZZ, a=1, b=2)
|
|
1560
|
+
Traceback (most recent call last):
|
|
1561
|
+
...
|
|
1562
|
+
TypeError: ...__init__() takes exactly 2 arguments (3 given)
|
|
1563
|
+
"""
|
|
1564
|
+
# There should be one "list" argument, which can be given as
|
|
1565
|
+
# positional or keyword argument (in the latter case, the name
|
|
1566
|
+
# doesn't matter).
|
|
1567
|
+
if len(args) == 1 and not kwds:
|
|
1568
|
+
L = args[0]
|
|
1569
|
+
elif len(kwds) == 1 and not args:
|
|
1570
|
+
L, = kwds.values()
|
|
1571
|
+
else:
|
|
1572
|
+
raise TypeError("__init__() takes exactly 2 arguments ({} given)".format(1 + len(args) + len(kwds)))
|
|
1573
|
+
super().__init__(L)
|
|
1574
|
+
super(CombinatorialObject, self).__init__(parent)
|
|
1575
|
+
|
|
1576
|
+
#####################################################
|
|
1577
|
+
# combinatorial sets/lists
|
|
1578
|
+
|
|
1579
|
+
|
|
1580
|
+
def tuples(S, k, algorithm='itertools'):
|
|
1581
|
+
r"""
|
|
1582
|
+
Return a list of all `k`-tuples of elements of a given set ``S``.
|
|
1583
|
+
|
|
1584
|
+
This function accepts the set ``S`` in the form of any iterable
|
|
1585
|
+
(list, tuple or iterator), and returns a list of `k`-tuples.
|
|
1586
|
+
If ``S`` contains duplicate entries, then you should expect the
|
|
1587
|
+
method to return tuples multiple times!
|
|
1588
|
+
|
|
1589
|
+
Recall that `k`-tuples are ordered (in the sense that two `k`-tuples
|
|
1590
|
+
differing in the order of their entries count as different) and
|
|
1591
|
+
can have repeated entries (even if ``S`` is a list with no
|
|
1592
|
+
repetition).
|
|
1593
|
+
|
|
1594
|
+
INPUT:
|
|
1595
|
+
|
|
1596
|
+
- ``S`` -- the base set
|
|
1597
|
+
- ``k`` -- the length of the tuples
|
|
1598
|
+
- ``algorithm`` -- can be one of the following:
|
|
1599
|
+
|
|
1600
|
+
* ``'itertools'`` -- (default) use python's itertools
|
|
1601
|
+
* ``'native'`` -- use a native Sage implementation
|
|
1602
|
+
|
|
1603
|
+
.. NOTE::
|
|
1604
|
+
|
|
1605
|
+
The ordering of the list of tuples depends on the algorithm.
|
|
1606
|
+
|
|
1607
|
+
EXAMPLES::
|
|
1608
|
+
|
|
1609
|
+
sage: S = [1,2]
|
|
1610
|
+
sage: tuples(S,3)
|
|
1611
|
+
[(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2),
|
|
1612
|
+
(2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2)]
|
|
1613
|
+
sage: mset = ["s","t","e","i","n"]
|
|
1614
|
+
sage: tuples(mset, 2)
|
|
1615
|
+
[('s', 's'), ('s', 't'), ('s', 'e'), ('s', 'i'), ('s', 'n'),
|
|
1616
|
+
('t', 's'), ('t', 't'), ('t', 'e'), ('t', 'i'), ('t', 'n'),
|
|
1617
|
+
('e', 's'), ('e', 't'), ('e', 'e'), ('e', 'i'), ('e', 'n'),
|
|
1618
|
+
('i', 's'), ('i', 't'), ('i', 'e'), ('i', 'i'), ('i', 'n'),
|
|
1619
|
+
('n', 's'), ('n', 't'), ('n', 'e'), ('n', 'i'), ('n', 'n')]
|
|
1620
|
+
|
|
1621
|
+
::
|
|
1622
|
+
|
|
1623
|
+
sage: K.<a> = GF(4, 'a') # needs sage.rings.finite_rings
|
|
1624
|
+
sage: mset = [x for x in K if x != 0] # needs sage.rings.finite_rings
|
|
1625
|
+
sage: tuples(mset, 2) # needs sage.rings.finite_rings
|
|
1626
|
+
[(a, a), (a, a + 1), (a, 1), (a + 1, a), (a + 1, a + 1),
|
|
1627
|
+
(a + 1, 1), (1, a), (1, a + 1), (1, 1)]
|
|
1628
|
+
|
|
1629
|
+
We check that the implementations agree (up to ordering)::
|
|
1630
|
+
|
|
1631
|
+
sage: tuples(S, 3, 'native')
|
|
1632
|
+
[(1, 1, 1), (2, 1, 1), (1, 2, 1), (2, 2, 1),
|
|
1633
|
+
(1, 1, 2), (2, 1, 2), (1, 2, 2), (2, 2, 2)]
|
|
1634
|
+
|
|
1635
|
+
Lastly we check on a multiset::
|
|
1636
|
+
|
|
1637
|
+
sage: S = [1,1,2]
|
|
1638
|
+
sage: sorted(tuples(S, 3)) == sorted(tuples(S, 3, 'native'))
|
|
1639
|
+
True
|
|
1640
|
+
"""
|
|
1641
|
+
if algorithm == 'itertools':
|
|
1642
|
+
import itertools
|
|
1643
|
+
return list(itertools.product(S, repeat=k))
|
|
1644
|
+
if algorithm == 'native':
|
|
1645
|
+
return _tuples_native(S, k)
|
|
1646
|
+
raise ValueError('invalid algorithm')
|
|
1647
|
+
|
|
1648
|
+
|
|
1649
|
+
def _tuples_native(S, k):
|
|
1650
|
+
"""
|
|
1651
|
+
Return a list of all `k`-tuples of elements of a given set ``S``.
|
|
1652
|
+
|
|
1653
|
+
This is a helper method used in :meth:`tuples`. It returns the
|
|
1654
|
+
same as ``tuples(S, k, algorithm='native')``.
|
|
1655
|
+
|
|
1656
|
+
EXAMPLES::
|
|
1657
|
+
|
|
1658
|
+
sage: S = [1,2,2]
|
|
1659
|
+
sage: from sage.combinat.combinat import _tuples_native
|
|
1660
|
+
sage: _tuples_native(S,2)
|
|
1661
|
+
[(1, 1), (2, 1), (2, 1), (1, 2), (2, 2), (2, 2),
|
|
1662
|
+
(1, 2), (2, 2), (2, 2)]
|
|
1663
|
+
"""
|
|
1664
|
+
if k <= 0:
|
|
1665
|
+
return [()]
|
|
1666
|
+
if k == 1:
|
|
1667
|
+
return [(x,) for x in S]
|
|
1668
|
+
ans = []
|
|
1669
|
+
for s in S:
|
|
1670
|
+
for x in _tuples_native(S, k - 1):
|
|
1671
|
+
y = list(x)
|
|
1672
|
+
y.append(s)
|
|
1673
|
+
ans.append(tuple(y))
|
|
1674
|
+
return ans
|
|
1675
|
+
|
|
1676
|
+
|
|
1677
|
+
def number_of_tuples(S, k, algorithm='naive') -> Integer:
|
|
1678
|
+
"""
|
|
1679
|
+
Return the size of ``tuples(S, k)`` for a set `S`.
|
|
1680
|
+
|
|
1681
|
+
`S` is first converted to a set. Hence, unlike :meth:`tuples`, this method
|
|
1682
|
+
removes redundant entries from `S`.
|
|
1683
|
+
|
|
1684
|
+
INPUT:
|
|
1685
|
+
|
|
1686
|
+
- ``S`` -- the base set
|
|
1687
|
+
- ``k`` -- the length of the tuples
|
|
1688
|
+
- ``algorithm`` -- can be one of the following:
|
|
1689
|
+
|
|
1690
|
+
* ``'naive'`` -- (default) use the naive counting `|S|^k`
|
|
1691
|
+
* ``'gap'`` -- wraps GAP's ``NrTuples``
|
|
1692
|
+
|
|
1693
|
+
.. WARNING::
|
|
1694
|
+
|
|
1695
|
+
When using ``algorithm='gap'``, ``S`` must be a list of objects
|
|
1696
|
+
that have string representations that can be interpreted by the GAP
|
|
1697
|
+
interpreter. If ``S`` consists of at all complicated Sage
|
|
1698
|
+
objects, this function might *not* do what you expect.
|
|
1699
|
+
|
|
1700
|
+
EXAMPLES::
|
|
1701
|
+
|
|
1702
|
+
sage: S = [1,2,3,4,5]
|
|
1703
|
+
sage: number_of_tuples(S,2)
|
|
1704
|
+
25
|
|
1705
|
+
sage: number_of_tuples(S,2, algorithm='gap') # needs sage.libs.gap
|
|
1706
|
+
25
|
|
1707
|
+
sage: S = [1,1,2,3,4,5]
|
|
1708
|
+
sage: number_of_tuples(S,2)
|
|
1709
|
+
25
|
|
1710
|
+
sage: number_of_tuples(S,2, algorithm='gap') # needs sage.libs.gap
|
|
1711
|
+
25
|
|
1712
|
+
sage: number_of_tuples(S,0)
|
|
1713
|
+
1
|
|
1714
|
+
sage: number_of_tuples(S,0, algorithm='gap') # needs sage.libs.gap
|
|
1715
|
+
1
|
|
1716
|
+
"""
|
|
1717
|
+
if algorithm == 'naive':
|
|
1718
|
+
return ZZ(len(set(S)))**k # The set is there to avoid duplicates
|
|
1719
|
+
if algorithm == 'gap':
|
|
1720
|
+
k = ZZ(k)
|
|
1721
|
+
from sage.libs.gap.libgap import libgap
|
|
1722
|
+
S = libgap.eval(str(S))
|
|
1723
|
+
return libgap.NrTuples(S, k).sage()
|
|
1724
|
+
raise ValueError('invalid algorithm')
|
|
1725
|
+
|
|
1726
|
+
|
|
1727
|
+
def unordered_tuples(S, k, algorithm='itertools'):
|
|
1728
|
+
r"""
|
|
1729
|
+
Return a list of all unordered tuples of length ``k`` of the set ``S``.
|
|
1730
|
+
|
|
1731
|
+
An unordered tuple of length `k` of set `S` is a unordered selection
|
|
1732
|
+
with repetitions of `S` and is represented by a sorted list of length
|
|
1733
|
+
`k` containing elements from `S`.
|
|
1734
|
+
|
|
1735
|
+
Unlike :meth:`tuples`, the result of this method does not depend on
|
|
1736
|
+
how often an element appears in `S`; only the *set* `S` is being
|
|
1737
|
+
used. For example, ``unordered_tuples([1, 1, 1], 2)`` will return
|
|
1738
|
+
``[(1, 1)]``. If you want it to return
|
|
1739
|
+
``[(1, 1), (1, 1), (1, 1)]``, use Python's
|
|
1740
|
+
``itertools.combinations_with_replacement`` instead.
|
|
1741
|
+
|
|
1742
|
+
INPUT:
|
|
1743
|
+
|
|
1744
|
+
- ``S`` -- the base set
|
|
1745
|
+
- ``k`` -- the length of the tuples
|
|
1746
|
+
- ``algorithm`` -- can be one of the following:
|
|
1747
|
+
|
|
1748
|
+
* ``'itertools'`` -- (default) use python's itertools
|
|
1749
|
+
* ``'gap'`` -- wraps GAP's ``UnorderedTuples``
|
|
1750
|
+
|
|
1751
|
+
.. WARNING::
|
|
1752
|
+
|
|
1753
|
+
When using ``algorithm='gap'``, ``S`` must be a list of objects
|
|
1754
|
+
that have string representations that can be interpreted by the GAP
|
|
1755
|
+
interpreter. If ``S`` consists of at all complicated Sage
|
|
1756
|
+
objects, this function might *not* do what you expect.
|
|
1757
|
+
|
|
1758
|
+
EXAMPLES::
|
|
1759
|
+
|
|
1760
|
+
sage: S = [1,2]
|
|
1761
|
+
sage: unordered_tuples(S, 3)
|
|
1762
|
+
[(1, 1, 1), (1, 1, 2), (1, 2, 2), (2, 2, 2)]
|
|
1763
|
+
|
|
1764
|
+
We check that this agrees with GAP::
|
|
1765
|
+
|
|
1766
|
+
sage: unordered_tuples(S, 3, algorithm='gap') # needs sage.libs.gap
|
|
1767
|
+
[(1, 1, 1), (1, 1, 2), (1, 2, 2), (2, 2, 2)]
|
|
1768
|
+
|
|
1769
|
+
We check the result on strings::
|
|
1770
|
+
|
|
1771
|
+
sage: S = ["a","b","c"]
|
|
1772
|
+
sage: unordered_tuples(S, 2)
|
|
1773
|
+
[('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'b'), ('b', 'c'), ('c', 'c')]
|
|
1774
|
+
sage: unordered_tuples(S, 2, algorithm='gap') # needs sage.libs.gap
|
|
1775
|
+
[('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'b'), ('b', 'c'), ('c', 'c')]
|
|
1776
|
+
|
|
1777
|
+
Lastly we check on a multiset::
|
|
1778
|
+
|
|
1779
|
+
sage: S = [1,1,2]
|
|
1780
|
+
sage: unordered_tuples(S, 3) == unordered_tuples(S, 3, 'gap') # needs sage.libs.gap
|
|
1781
|
+
True
|
|
1782
|
+
sage: unordered_tuples(S, 3)
|
|
1783
|
+
[(1, 1, 1), (1, 1, 2), (1, 2, 2), (2, 2, 2)]
|
|
1784
|
+
"""
|
|
1785
|
+
if algorithm == 'itertools':
|
|
1786
|
+
import itertools
|
|
1787
|
+
return list(itertools.combinations_with_replacement(sorted(set(S)), k))
|
|
1788
|
+
if algorithm == 'gap':
|
|
1789
|
+
k = ZZ(k)
|
|
1790
|
+
from sage.libs.gap.libgap import libgap
|
|
1791
|
+
S = libgap.eval(str(S))
|
|
1792
|
+
return [tuple(x) for x in libgap.UnorderedTuples(S, k).sage()]
|
|
1793
|
+
raise ValueError('invalid algorithm')
|
|
1794
|
+
|
|
1795
|
+
|
|
1796
|
+
def number_of_unordered_tuples(S, k, algorithm='naive') -> Integer:
|
|
1797
|
+
r"""
|
|
1798
|
+
Return the size of ``unordered_tuples(S, k)`` when `S` is a set.
|
|
1799
|
+
|
|
1800
|
+
INPUT:
|
|
1801
|
+
|
|
1802
|
+
- ``S`` -- the base set
|
|
1803
|
+
- ``k`` -- the length of the tuples
|
|
1804
|
+
- ``algorithm`` -- can be one of the following:
|
|
1805
|
+
|
|
1806
|
+
* ``'naive'`` -- (default) use the naive counting `\binom{|S|+k-1}{k}`
|
|
1807
|
+
* ``'gap'`` -- wraps GAP's ``NrUnorderedTuples``
|
|
1808
|
+
|
|
1809
|
+
.. WARNING::
|
|
1810
|
+
|
|
1811
|
+
When using ``algorithm='gap'``, ``S`` must be a list of objects
|
|
1812
|
+
that have string representations that can be interpreted by the GAP
|
|
1813
|
+
interpreter. If ``S`` consists of at all complicated Sage
|
|
1814
|
+
objects, this function might *not* do what you expect.
|
|
1815
|
+
|
|
1816
|
+
EXAMPLES::
|
|
1817
|
+
|
|
1818
|
+
sage: S = [1,2,3,4,5]
|
|
1819
|
+
sage: number_of_unordered_tuples(S,2)
|
|
1820
|
+
15
|
|
1821
|
+
sage: number_of_unordered_tuples(S,2, algorithm='gap') # needs sage.libs.gap
|
|
1822
|
+
15
|
|
1823
|
+
sage: S = [1,1,2,3,4,5]
|
|
1824
|
+
sage: number_of_unordered_tuples(S,2)
|
|
1825
|
+
15
|
|
1826
|
+
sage: number_of_unordered_tuples(S,2, algorithm='gap') # needs sage.libs.gap
|
|
1827
|
+
15
|
|
1828
|
+
sage: number_of_unordered_tuples(S,0)
|
|
1829
|
+
1
|
|
1830
|
+
sage: number_of_unordered_tuples(S,0, algorithm='gap') # needs sage.libs.gap
|
|
1831
|
+
1
|
|
1832
|
+
"""
|
|
1833
|
+
if algorithm == 'naive':
|
|
1834
|
+
return ZZ(len(set(S)) + k - 1).binomial(k) # The set is there to avoid duplicates
|
|
1835
|
+
if algorithm == 'gap':
|
|
1836
|
+
k = ZZ(k)
|
|
1837
|
+
from sage.libs.gap.libgap import libgap
|
|
1838
|
+
S = libgap.eval(str(S))
|
|
1839
|
+
return libgap.NrUnorderedTuples(S, k).sage()
|
|
1840
|
+
raise ValueError('invalid algorithm')
|
|
1841
|
+
|
|
1842
|
+
|
|
1843
|
+
def unshuffle_iterator(a, one=1) -> Iterator:
|
|
1844
|
+
r"""
|
|
1845
|
+
Iterate over the unshuffles of a list (or tuple) ``a``, also
|
|
1846
|
+
yielding the signs of the respective permutations.
|
|
1847
|
+
|
|
1848
|
+
If `n` and `k` are integers satisfying `0 \leq k \leq n`, then
|
|
1849
|
+
a `(k, n-k)`-*unshuffle* means a permutation `\pi \in S_n` such
|
|
1850
|
+
that `\pi(1) < \pi(2) < \cdots < \pi(k)` and
|
|
1851
|
+
`\pi(k+1) < \pi(k+2) < \cdots < \pi(n)`. This method provides,
|
|
1852
|
+
for a list `a = (a_1, a_2, \ldots, a_n)` of length `n`, an iterator
|
|
1853
|
+
yielding all pairs:
|
|
1854
|
+
|
|
1855
|
+
.. MATH::
|
|
1856
|
+
|
|
1857
|
+
\Bigl( \bigl( (a_{\pi(1)}, a_{\pi(2)}, \ldots, a_{\pi(k)}),
|
|
1858
|
+
(a_{\pi(k+1)}, a_{\pi(k+2)}, \ldots, a_{\pi(n)}) \bigl),
|
|
1859
|
+
(-1)^{\pi} \Bigr)
|
|
1860
|
+
|
|
1861
|
+
for all `k \in \{0, 1, \ldots, n\}` and all `(k, n-k)`-unshuffles
|
|
1862
|
+
`\pi`. The optional variable ``one`` can be set to a different
|
|
1863
|
+
value which results in the `(-1)^{\pi}` component being multiplied
|
|
1864
|
+
by said value.
|
|
1865
|
+
|
|
1866
|
+
The iterator does not yield these in order of increasing `k`.
|
|
1867
|
+
|
|
1868
|
+
EXAMPLES::
|
|
1869
|
+
|
|
1870
|
+
sage: from sage.combinat.combinat import unshuffle_iterator
|
|
1871
|
+
sage: list(unshuffle_iterator([1, 3, 4]))
|
|
1872
|
+
[(((), (1, 3, 4)), 1), (((1,), (3, 4)), 1), (((3,), (1, 4)), -1),
|
|
1873
|
+
(((1, 3), (4,)), 1), (((4,), (1, 3)), 1), (((1, 4), (3,)), -1),
|
|
1874
|
+
(((3, 4), (1,)), 1), (((1, 3, 4), ()), 1)]
|
|
1875
|
+
sage: list(unshuffle_iterator([3, 1]))
|
|
1876
|
+
[(((), (3, 1)), 1), (((3,), (1,)), 1), (((1,), (3,)), -1),
|
|
1877
|
+
(((3, 1), ()), 1)]
|
|
1878
|
+
sage: list(unshuffle_iterator([8]))
|
|
1879
|
+
[(((), (8,)), 1), (((8,), ()), 1)]
|
|
1880
|
+
sage: list(unshuffle_iterator([]))
|
|
1881
|
+
[(((), ()), 1)]
|
|
1882
|
+
sage: list(unshuffle_iterator([3, 1], 3/2))
|
|
1883
|
+
[(((), (3, 1)), 3/2), (((3,), (1,)), 3/2), (((1,), (3,)), -3/2),
|
|
1884
|
+
(((3, 1), ()), 3/2)]
|
|
1885
|
+
"""
|
|
1886
|
+
from sage.combinat.subset import powerset
|
|
1887
|
+
n = len(a)
|
|
1888
|
+
for I in powerset(range(n)):
|
|
1889
|
+
sorted_I = tuple(sorted(I))
|
|
1890
|
+
nonI = list(range(n))
|
|
1891
|
+
for j in reversed(sorted_I): # probably optimizable
|
|
1892
|
+
nonI.pop(j)
|
|
1893
|
+
sorted_nonI = tuple(nonI)
|
|
1894
|
+
sign = True
|
|
1895
|
+
for i in sorted_I:
|
|
1896
|
+
if i % 2: # aka i % 2 == 1
|
|
1897
|
+
sign = not sign
|
|
1898
|
+
if len(sorted_I) % 4 > 1:
|
|
1899
|
+
sign = not sign
|
|
1900
|
+
yield ((tuple([a[i] for i in sorted_I]),
|
|
1901
|
+
tuple([a[i] for i in sorted_nonI])),
|
|
1902
|
+
(one if sign else - one))
|
|
1903
|
+
|
|
1904
|
+
|
|
1905
|
+
def bell_polynomial(n: Integer, k=None, ordinary=False):
|
|
1906
|
+
r"""
|
|
1907
|
+
Return the partial (or complete) exponential (or ordinary) Bell polynomial.
|
|
1908
|
+
|
|
1909
|
+
The partial exponential *Bell polynomial* is defined by the formula
|
|
1910
|
+
|
|
1911
|
+
.. MATH::
|
|
1912
|
+
|
|
1913
|
+
B_{n,k}(x_0, x_1, \ldots, x_{n-k}) =
|
|
1914
|
+
\sum_{\substack{j_0 + \ldots + j_{n-k} = k \\ 1 j_0 + \ldots + (n-k+1) j_{n-k} = n}}
|
|
1915
|
+
\frac{n!}{j_0!j_1!\cdots j_{n-k}!}
|
|
1916
|
+
\left(\frac{x_0}{(0+1)!}\right)^{j_0}
|
|
1917
|
+
\left(\frac{x_1}{(1+1)!}\right)^{j_1} \cdots
|
|
1918
|
+
\left(\frac{x_{n-k}}{(n-k+1)!}\right)^{j_{n-k}}.
|
|
1919
|
+
|
|
1920
|
+
The complete exponential Bell Polynomial is defined as
|
|
1921
|
+
|
|
1922
|
+
.. MATH::
|
|
1923
|
+
|
|
1924
|
+
B_n(x_0, x_1, \ldots, x_{n-k}) =
|
|
1925
|
+
\sum_{k=0}^n B_{n,k}(x_0, x_1, \ldots, x_{n-k}).
|
|
1926
|
+
|
|
1927
|
+
The ordinary variant of the partial Bell polynomial is defined by
|
|
1928
|
+
|
|
1929
|
+
.. MATH::
|
|
1930
|
+
|
|
1931
|
+
\hat B_{n,k}(x_0, x_1, \ldots, x_{n-k}) =
|
|
1932
|
+
\sum_{\substack{j_0 + \ldots + j_{n-k} = k \\ 1 j_0 + \ldots + (n-k+1) j_{n-k} = n}}
|
|
1933
|
+
\binom{k}{j_0, j_1, \ldots, j_{n-k}}
|
|
1934
|
+
x_0^{j_0} x_1^{j_1} \cdots x_{n-k}^{j_{n-k}},
|
|
1935
|
+
|
|
1936
|
+
where we have used the multinomial coefficient. The complete version has
|
|
1937
|
+
the same definition as its exponential counterpart.
|
|
1938
|
+
|
|
1939
|
+
If we define `f(z) = \sum_{n=1}^\infty x_{n-1} z^n/n!`
|
|
1940
|
+
then these are alternative definitions for exponential Bell polynomials
|
|
1941
|
+
|
|
1942
|
+
.. MATH::
|
|
1943
|
+
|
|
1944
|
+
\begin{aligned}
|
|
1945
|
+
\exp(f(z)) & = \sum_{n=0}^\infty B_n(x_0, \ldots, x_{n-1}) \frac{z^n}{n!}, \\
|
|
1946
|
+
\frac{f(z)^k}{k!} & = \sum_{n=k}^\infty B_{n, k}(x_0, \ldots, x_{n-k}) \frac{z^n}{n!}.
|
|
1947
|
+
\end{aligned}
|
|
1948
|
+
|
|
1949
|
+
Defining `g(z) = \sum_{n=1}^\infty x_{n-1} z^n`,
|
|
1950
|
+
we have the analogous alternative definitions
|
|
1951
|
+
|
|
1952
|
+
.. MATH::
|
|
1953
|
+
|
|
1954
|
+
\begin{aligned}
|
|
1955
|
+
\frac1{1-f(z)} & = \sum_{n=0}^\infty \hat B_n(x_0, \ldots, x_{n-1}) z^n, \\
|
|
1956
|
+
f(z)^k & = \sum_{n=k}^\infty \hat B_{n, k}(x_0, \ldots, x_{n-k}) z^n.
|
|
1957
|
+
\end{aligned}
|
|
1958
|
+
|
|
1959
|
+
INPUT:
|
|
1960
|
+
|
|
1961
|
+
- ``k`` -- (optional) if specified, returns the partial Bell
|
|
1962
|
+
polynomial, otherwise returns the complete Bell polynomial
|
|
1963
|
+
- ``ordinary`` -- boolean (default: ``False``); if ``True``, returns the
|
|
1964
|
+
(partial) ordinary Bell polynomial, otherwise returns
|
|
1965
|
+
the (partial) exponential Bell polynomial
|
|
1966
|
+
|
|
1967
|
+
EXAMPLES:
|
|
1968
|
+
|
|
1969
|
+
The complete and partial Bell polynomials::
|
|
1970
|
+
|
|
1971
|
+
sage: # needs sage.combinat
|
|
1972
|
+
sage: bell_polynomial(3)
|
|
1973
|
+
x0^3 + 3*x0*x1 + x2
|
|
1974
|
+
sage: bell_polynomial(4)
|
|
1975
|
+
x0^4 + 6*x0^2*x1 + 3*x1^2 + 4*x0*x2 + x3
|
|
1976
|
+
sage: bell_polynomial(6, 3)
|
|
1977
|
+
15*x1^3 + 60*x0*x1*x2 + 15*x0^2*x3
|
|
1978
|
+
sage: bell_polynomial(6, 6)
|
|
1979
|
+
x0^6
|
|
1980
|
+
|
|
1981
|
+
The ordinary variants are::
|
|
1982
|
+
|
|
1983
|
+
sage: # needs sage.combinat sage.arith
|
|
1984
|
+
sage: bell_polynomial(3, ordinary=True)
|
|
1985
|
+
x0^3 + 2*x0*x1 + x2
|
|
1986
|
+
sage: bell_polynomial(4, ordinary=True)
|
|
1987
|
+
x0^4 + 3*x0^2*x1 + x1^2 + 2*x0*x2 + x3
|
|
1988
|
+
sage: bell_polynomial(6, 3, True)
|
|
1989
|
+
x1^3 + 6*x0*x1*x2 + 3*x0^2*x3
|
|
1990
|
+
sage: bell_polynomial(6, 6, True)
|
|
1991
|
+
x0^6
|
|
1992
|
+
|
|
1993
|
+
We verify the alternative definition of the different Bell polynomials
|
|
1994
|
+
using the functions `f` and `g` given above::
|
|
1995
|
+
|
|
1996
|
+
sage: # needs sage.combinat sage.arith
|
|
1997
|
+
sage: n = 6 # positive integer
|
|
1998
|
+
sage: k = 4 # positive integer
|
|
1999
|
+
sage: R.<x> = InfinitePolynomialRing(QQ)
|
|
2000
|
+
sage: PR = PolynomialRing(QQ, 'x', n)
|
|
2001
|
+
sage: d = {x[i]: PR.gen(i) for i in range(n)} # substitution dictionary
|
|
2002
|
+
sage: L.<z> = LazyPowerSeriesRing(R)
|
|
2003
|
+
sage: f = L(lambda i: x[i-1]/factorial(i), valuation=1)
|
|
2004
|
+
sage: all(exp(f)[i].subs(d) * factorial(i) == bell_polynomial(i) for i in range(n+1))
|
|
2005
|
+
True
|
|
2006
|
+
sage: all((f^k/factorial(k))[i].subs(d) * factorial(i) == bell_polynomial(i, k) for i in range(k, n+k))
|
|
2007
|
+
True
|
|
2008
|
+
sage: g = L(lambda i: x[i-1], valuation=1)
|
|
2009
|
+
sage: all((1/(1-g))[i].subs(d) == bell_polynomial(i, ordinary=True) for i in range(n+1))
|
|
2010
|
+
True
|
|
2011
|
+
sage: all((g^k)[i].subs(d) == bell_polynomial(i, k, True) for i in range(k, n+k))
|
|
2012
|
+
True
|
|
2013
|
+
|
|
2014
|
+
TESTS:
|
|
2015
|
+
|
|
2016
|
+
Check that :issue:`18338` is fixed::
|
|
2017
|
+
|
|
2018
|
+
sage: bell_polynomial(0, 0).parent() # needs sage.combinat
|
|
2019
|
+
Univariate Polynomial Ring in x0 over Integer Ring
|
|
2020
|
+
|
|
2021
|
+
sage: for n in (0..4): # needs sage.combinat
|
|
2022
|
+
....: print([bell_polynomial(n,k).coefficients() for k in (0..n)])
|
|
2023
|
+
[[1]]
|
|
2024
|
+
[[], [1]]
|
|
2025
|
+
[[], [1], [1]]
|
|
2026
|
+
[[], [1], [3], [1]]
|
|
2027
|
+
[[], [1], [3, 4], [6], [1]]
|
|
2028
|
+
|
|
2029
|
+
Further checks for :issue:`37727`::
|
|
2030
|
+
|
|
2031
|
+
sage: # needs sage.combinat sage.arith
|
|
2032
|
+
sage: bell_polynomial(0, 0)
|
|
2033
|
+
1
|
|
2034
|
+
sage: bell_polynomial(0, 0, True)
|
|
2035
|
+
1
|
|
2036
|
+
sage: bell_polynomial(1, 1)
|
|
2037
|
+
x0
|
|
2038
|
+
sage: bell_polynomial(2, 2, True)
|
|
2039
|
+
x0^2
|
|
2040
|
+
sage: bell_polynomial(5)
|
|
2041
|
+
x0^5 + 10*x0^3*x1 + 15*x0*x1^2 + 10*x0^2*x2 + 10*x1*x2 + 5*x0*x3 + x4
|
|
2042
|
+
sage: sum(bell_polynomial(5, k) for k in range(6))
|
|
2043
|
+
x0^5 + 10*x0^3*x1 + 15*x0*x1^2 + 10*x0^2*x2 + 10*x1*x2 + 5*x0*x3 + x4
|
|
2044
|
+
sage: bell_polynomial(5, None, True)
|
|
2045
|
+
x0^5 + 4*x0^3*x1 + 3*x0*x1^2 + 3*x0^2*x2 + 2*x1*x2 + 2*x0*x3 + x4
|
|
2046
|
+
sage: sum(bell_polynomial(5, k, True) for k in range(6))
|
|
2047
|
+
x0^5 + 4*x0^3*x1 + 3*x0*x1^2 + 3*x0^2*x2 + 2*x1*x2 + 2*x0*x3 + x4
|
|
2048
|
+
sage: bell_polynomial(0).parent()
|
|
2049
|
+
Univariate Polynomial Ring in x0 over Integer Ring
|
|
2050
|
+
|
|
2051
|
+
REFERENCES:
|
|
2052
|
+
|
|
2053
|
+
- [Bel1927]_
|
|
2054
|
+
- [Com1974]_
|
|
2055
|
+
"""
|
|
2056
|
+
from sage.combinat.partition import Partitions
|
|
2057
|
+
from sage.arith.misc import multinomial
|
|
2058
|
+
if k is None:
|
|
2059
|
+
partitions = Partitions(n)
|
|
2060
|
+
# We set k = 1 to use the correct ring
|
|
2061
|
+
# It is not used in the computation otherwise
|
|
2062
|
+
k = 1
|
|
2063
|
+
else:
|
|
2064
|
+
partitions = Partitions(n, length=k)
|
|
2065
|
+
if n <= k:
|
|
2066
|
+
R = PolynomialRing(ZZ, 'x0')
|
|
2067
|
+
else:
|
|
2068
|
+
R = PolynomialRing(ZZ, 'x', n - k + 1)
|
|
2069
|
+
vars = R.gens()
|
|
2070
|
+
result = R.zero()
|
|
2071
|
+
for p in partitions:
|
|
2072
|
+
if ordinary:
|
|
2073
|
+
coefficient = multinomial(p.to_exp())
|
|
2074
|
+
else:
|
|
2075
|
+
factorial_product = 1
|
|
2076
|
+
for part, count in p.to_exp_dict().items():
|
|
2077
|
+
factorial_product *= factorial(count) * factorial(part)**count
|
|
2078
|
+
coefficient = factorial(n) // factorial_product
|
|
2079
|
+
result += coefficient * prod(vars[i - 1] for i in p)
|
|
2080
|
+
return result
|
|
2081
|
+
|
|
2082
|
+
|
|
2083
|
+
def fibonacci_sequence(start, stop=None, algorithm=None) -> Iterator:
|
|
2084
|
+
r"""
|
|
2085
|
+
Return an iterator over the Fibonacci sequence, for all fibonacci
|
|
2086
|
+
numbers `f_n` from ``n = start`` up to (but
|
|
2087
|
+
not including) ``n = stop``
|
|
2088
|
+
|
|
2089
|
+
INPUT:
|
|
2090
|
+
|
|
2091
|
+
- ``start`` -- starting value
|
|
2092
|
+
|
|
2093
|
+
- ``stop`` -- stopping value
|
|
2094
|
+
|
|
2095
|
+
- ``algorithm`` -- (default: ``None``) passed on to fibonacci function (or
|
|
2096
|
+
not passed on if ``None``, i.e., use the default)
|
|
2097
|
+
|
|
2098
|
+
EXAMPLES::
|
|
2099
|
+
|
|
2100
|
+
sage: fibs = [i for i in fibonacci_sequence(10, 20)]; fibs # needs sage.libs.pari
|
|
2101
|
+
[55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181]
|
|
2102
|
+
|
|
2103
|
+
::
|
|
2104
|
+
|
|
2105
|
+
sage: sum([i for i in fibonacci_sequence(100, 110)]) # needs sage.libs.pari
|
|
2106
|
+
69919376923075308730013
|
|
2107
|
+
|
|
2108
|
+
.. SEEALSO::
|
|
2109
|
+
|
|
2110
|
+
:func:`fibonacci_xrange`
|
|
2111
|
+
"""
|
|
2112
|
+
if stop is None:
|
|
2113
|
+
stop = ZZ(start)
|
|
2114
|
+
start = ZZ(0)
|
|
2115
|
+
else:
|
|
2116
|
+
start = ZZ(start)
|
|
2117
|
+
stop = ZZ(stop)
|
|
2118
|
+
|
|
2119
|
+
if algorithm:
|
|
2120
|
+
for n in range(start, stop):
|
|
2121
|
+
yield fibonacci(n, algorithm=algorithm)
|
|
2122
|
+
else:
|
|
2123
|
+
for n in range(start, stop):
|
|
2124
|
+
yield fibonacci(n)
|
|
2125
|
+
|
|
2126
|
+
|
|
2127
|
+
def fibonacci_xrange(start, stop=None, algorithm='pari') -> Iterator:
|
|
2128
|
+
r"""
|
|
2129
|
+
Return an iterator over all of the Fibonacci numbers in the given
|
|
2130
|
+
range, including ``f_n = start`` up to, but not
|
|
2131
|
+
including, ``f_n = stop``.
|
|
2132
|
+
|
|
2133
|
+
EXAMPLES::
|
|
2134
|
+
|
|
2135
|
+
sage: fibs_in_some_range = [i for i in fibonacci_xrange(10^7, 10^8)] # needs sage.libs.pari
|
|
2136
|
+
sage: len(fibs_in_some_range) # needs sage.libs.pari
|
|
2137
|
+
4
|
|
2138
|
+
sage: fibs_in_some_range # needs sage.libs.pari
|
|
2139
|
+
[14930352, 24157817, 39088169, 63245986]
|
|
2140
|
+
|
|
2141
|
+
::
|
|
2142
|
+
|
|
2143
|
+
sage: fibs = [i for i in fibonacci_xrange(10, 100)]; fibs # needs sage.libs.pari
|
|
2144
|
+
[13, 21, 34, 55, 89]
|
|
2145
|
+
|
|
2146
|
+
::
|
|
2147
|
+
|
|
2148
|
+
sage: list(fibonacci_xrange(13, 34)) # needs sage.libs.pari
|
|
2149
|
+
[13, 21]
|
|
2150
|
+
|
|
2151
|
+
A solution to the second Project Euler problem::
|
|
2152
|
+
|
|
2153
|
+
sage: sum([i for i in fibonacci_xrange(10^6) if is_even(i)]) # needs sage.libs.pari
|
|
2154
|
+
1089154
|
|
2155
|
+
|
|
2156
|
+
.. SEEALSO::
|
|
2157
|
+
|
|
2158
|
+
:func:`fibonacci_sequence`
|
|
2159
|
+
"""
|
|
2160
|
+
if stop is None:
|
|
2161
|
+
stop = ZZ(start)
|
|
2162
|
+
start = ZZ(0)
|
|
2163
|
+
else:
|
|
2164
|
+
start = ZZ(start)
|
|
2165
|
+
stop = ZZ(stop)
|
|
2166
|
+
|
|
2167
|
+
# iterate until we've gotten high enough
|
|
2168
|
+
fn = 0
|
|
2169
|
+
n = 0
|
|
2170
|
+
while fn < start:
|
|
2171
|
+
n += 1
|
|
2172
|
+
fn = fibonacci(n)
|
|
2173
|
+
|
|
2174
|
+
while True:
|
|
2175
|
+
fn = fibonacci(n)
|
|
2176
|
+
n += 1
|
|
2177
|
+
if fn < stop:
|
|
2178
|
+
yield fn
|
|
2179
|
+
else:
|
|
2180
|
+
return
|
|
2181
|
+
|
|
2182
|
+
|
|
2183
|
+
def bernoulli_polynomial(x, n: Integer):
|
|
2184
|
+
r"""
|
|
2185
|
+
Return the ``n``-th Bernoulli polynomial evaluated at ``x``.
|
|
2186
|
+
|
|
2187
|
+
The generating function for the Bernoulli polynomials is
|
|
2188
|
+
|
|
2189
|
+
.. MATH::
|
|
2190
|
+
|
|
2191
|
+
\frac{t e^{xt}}{e^t-1}= \sum_{n=0}^\infty B_n(x) \frac{t^n}{n!},
|
|
2192
|
+
|
|
2193
|
+
and they are given directly by
|
|
2194
|
+
|
|
2195
|
+
.. MATH::
|
|
2196
|
+
|
|
2197
|
+
B_n(x) = \sum_{i=0}^n \binom{n}{i}B_{n-i}x^i.
|
|
2198
|
+
|
|
2199
|
+
One has `B_n(x) = - n\zeta(1 - n,x)`, where `\zeta(s,x)` is the Hurwitz
|
|
2200
|
+
zeta function. Thus, in a certain sense, the Hurwitz zeta function
|
|
2201
|
+
generalizes the Bernoulli polynomials to non-integer values of `n`.
|
|
2202
|
+
|
|
2203
|
+
EXAMPLES::
|
|
2204
|
+
|
|
2205
|
+
sage: # needs sage.libs.flint
|
|
2206
|
+
sage: y = QQ['y'].0
|
|
2207
|
+
sage: bernoulli_polynomial(y, 5)
|
|
2208
|
+
y^5 - 5/2*y^4 + 5/3*y^3 - 1/6*y
|
|
2209
|
+
sage: bernoulli_polynomial(y, 5)(12)
|
|
2210
|
+
199870
|
|
2211
|
+
sage: bernoulli_polynomial(12, 5)
|
|
2212
|
+
199870
|
|
2213
|
+
sage: bernoulli_polynomial(y^2 + 1, 5)
|
|
2214
|
+
y^10 + 5/2*y^8 + 5/3*y^6 - 1/6*y^2
|
|
2215
|
+
sage: P.<t> = ZZ[]
|
|
2216
|
+
sage: p = bernoulli_polynomial(t, 6)
|
|
2217
|
+
sage: p.parent()
|
|
2218
|
+
Univariate Polynomial Ring in t over Rational Field
|
|
2219
|
+
|
|
2220
|
+
We verify an instance of the formula which is the origin of
|
|
2221
|
+
the Bernoulli polynomials (and numbers)::
|
|
2222
|
+
|
|
2223
|
+
sage: power_sum = sum(k^4 for k in range(10))
|
|
2224
|
+
sage: 5*power_sum == bernoulli_polynomial(10, 5) - bernoulli(5) # needs sage.libs.flint
|
|
2225
|
+
True
|
|
2226
|
+
|
|
2227
|
+
TESTS::
|
|
2228
|
+
|
|
2229
|
+
sage: x = polygen(QQ, 'x')
|
|
2230
|
+
sage: bernoulli_polynomial(x, 0).parent()
|
|
2231
|
+
Univariate Polynomial Ring in x over Rational Field
|
|
2232
|
+
|
|
2233
|
+
REFERENCES:
|
|
2234
|
+
|
|
2235
|
+
- :wikipedia:`Bernoulli_polynomials`
|
|
2236
|
+
"""
|
|
2237
|
+
try:
|
|
2238
|
+
n = ZZ(n)
|
|
2239
|
+
if n < 0:
|
|
2240
|
+
raise TypeError
|
|
2241
|
+
except TypeError:
|
|
2242
|
+
raise ValueError("the second argument must be a nonnegative integer")
|
|
2243
|
+
|
|
2244
|
+
if n == 0:
|
|
2245
|
+
return x**0 # result should be in the parent of x
|
|
2246
|
+
|
|
2247
|
+
if n == 1:
|
|
2248
|
+
return x - ZZ.one() / 2
|
|
2249
|
+
|
|
2250
|
+
k = n.mod(2)
|
|
2251
|
+
coeffs = [0] * k + sum(([n.binomial(i) * bernoulli(n - i), 0]
|
|
2252
|
+
for i in range(k, n + 1, 2)), [])
|
|
2253
|
+
coeffs[-3] = -n / 2
|
|
2254
|
+
|
|
2255
|
+
if isinstance(x, Polynomial):
|
|
2256
|
+
try:
|
|
2257
|
+
return x.parent()(coeffs)(x)
|
|
2258
|
+
except TypeError:
|
|
2259
|
+
pass
|
|
2260
|
+
|
|
2261
|
+
x2 = x * x
|
|
2262
|
+
xi = x**k
|
|
2263
|
+
s = 0
|
|
2264
|
+
for i in range(k, n - 1, 2):
|
|
2265
|
+
s += coeffs[i] * xi
|
|
2266
|
+
t = xi
|
|
2267
|
+
xi *= x2
|
|
2268
|
+
s += xi - t * x * n / 2
|
|
2269
|
+
return s
|