Skip to content

Commit 8a5f23d

Browse files
committed
Add Lah numbers
1 parent 5188024 commit 8a5f23d

File tree

1 file changed

+50
-15
lines changed

1 file changed

+50
-15
lines changed

src/sage/combinat/combinat.py

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,6 @@
4949
and is represented by a sorted list of length k containing elements
5050
from S.
5151
52-
.. WARNING::
53-
54-
The following function is deprecated and will soon be removed.
55-
56-
- Permutations of a multiset, :func:`permutations`,
57-
:func:`permutations_iterator`, :func:`number_of_permutations`. A
58-
permutation is a list that contains exactly the same elements but possibly
59-
in different order.
60-
6152
**Related functions:**
6253
6354
- Bernoulli polynomials, :func:`bernoulli_polynomial`
@@ -95,8 +86,7 @@
9586
The ``sage.groups.perm_gps.permgroup_elements``
9687
contains the following combinatorial functions:
9788
98-
99-
- matrix method of PermutationGroupElement yielding the
89+
- matrix method of :class:`PermutationGroupElement` yielding the
10090
permutation matrix of the group element.
10191
10292
.. TODO::
@@ -114,7 +104,7 @@
114104
115105
AUTHORS:
116106
117-
- David Joyner (2006-07): initial implementation.
107+
- David Joyner (2006-07): initial implementation
118108
119109
- William Stein (2006-07): editing of docs and code; many
120110
optimizations, refinements, and bug fixes in corner cases
@@ -132,8 +122,7 @@
132122
- Punarbasu Purkayastha (2012-12): deprecate arrangements, combinations,
133123
combinations_iterator, and clean up very old deprecated methods.
134124
135-
Functions and classes
136-
---------------------
125+
- Kwankyu Lee (2025-01): added Lah numbers
137126
"""
138127

139128
# ****************************************************************************
@@ -505,7 +494,7 @@ def narayana_number(n: Integer, k: Integer) -> Integer:
505494
506495
- ``n`` -- integer
507496
508-
- ``k`` -- integer between ``0`` and ``n - 1``
497+
- ``k`` -- integer between `0` and `n - 1`
509498
510499
OUTPUT: integer
511500
@@ -890,6 +879,10 @@ def stirling_number1(n, k, algorithm='gap') -> Integer:
890879
"""
891880
n = ZZ(n)
892881
k = ZZ(k)
882+
if k > n:
883+
return ZZ.zero()
884+
if k == 0:
885+
return ZZ.zero() if n else ZZ.one()
893886
if algorithm == 'gap':
894887
from sage.libs.gap.libgap import libgap
895888
return libgap.Stirling1(n, k).sage()
@@ -1016,6 +1009,10 @@ def stirling_number2(n, k, algorithm=None) -> Integer:
10161009
"""
10171010
n = ZZ(n)
10181011
k = ZZ(k)
1012+
if k > n:
1013+
return ZZ.zero()
1014+
if k == 0:
1015+
return ZZ.zero() if n else ZZ.one()
10191016
if algorithm is None:
10201017
return _stirling_number2(n, k)
10211018
if algorithm == 'gap':
@@ -1029,6 +1026,44 @@ def stirling_number2(n, k, algorithm=None) -> Integer:
10291026
raise ValueError("unknown algorithm: %s" % algorithm)
10301027

10311028

1029+
def lah_number(n, k) -> Integer:
1030+
r"""
1031+
Return the Lah number `L(n,k)`
1032+
1033+
This is the number of ways to partition a set of `n` elements into `k`
1034+
pairwise disjoint nonempty linearly-ordered subsets.
1035+
1036+
This is also called the Stirling number of the third kind.
1037+
1038+
See :wikipedia:`Lah_number`.
1039+
1040+
INPUT:
1041+
1042+
- ``n`` -- nonnegative integer
1043+
- ``k`` -- nonnegative integer
1044+
1045+
EXAMPLES:
1046+
1047+
sage: lah_number(50, 30)
1048+
3242322638238907670866645288893161825894400000
1049+
1050+
We verify a well-known identity::
1051+
1052+
sage: S1 = stirling_number1; S2 = stirling_number2
1053+
sage: all(lah_number(n, k) == sum(S1(n, j) * S2(j, k) for j in [k..n])
1054+
....: for n in range(10) for k in range(10))
1055+
True
1056+
"""
1057+
n = ZZ(n)
1058+
k = ZZ(k)
1059+
if k > n:
1060+
return ZZ.zero()
1061+
if k == 0:
1062+
return ZZ.zero() if n else ZZ.one()
1063+
a = n.factorial() // k.factorial()
1064+
return a**2 * k // (n * (n - k).factorial())
1065+
1066+
10321067
def polygonal_number(s, n):
10331068
r"""
10341069
Return the `n`-th `s`-gonal number.

0 commit comments

Comments
 (0)