Skip to content

Commit 9d36f4d

Browse files
committed
PartitionsP: uses Euler's method. Revise Factorial
Factorial ia now _MPMathFunction
1 parent 5936541 commit 9d36f4d

1 file changed

Lines changed: 37 additions & 13 deletions

File tree

mathics/builtin/combinatorial.py

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
"""
66

77

8+
import math
9+
from functools import lru_cache
810
import sympy
911
from sympy.functions.combinatorial.numbers import stirling
10-
from sympy.utilities.iterables import partitions
1112
from mathics.version import __version__ # noqa used in loading to check consistency.
1213

1314
from mathics.builtin.base import Builtin
@@ -81,11 +82,11 @@ def apply(self, values, evaluation):
8182
return Expression("Times", *leaves)
8283

8384

84-
class Fibonacci(Builtin):
85+
class Fibonacci(_MPMathFunction):
8586
"""
8687
<dl>
87-
<dt>'Fibonacci[$n$]'
88-
<dd>computes the $n$th Fibonacci number.
88+
<dt>'Fibonacci[$n$]'
89+
<dd>computes the $n$th Fibonacci number.
8990
</dl>
9091
9192
>> Fibonacci[0]
@@ -98,12 +99,10 @@ class Fibonacci(Builtin):
9899
= 280571172992510140037611932413038677189525
99100
"""
100101

102+
nargs = 1
101103
attributes = ("Listable", "NumericFunction", "ReadProtected")
102-
103-
def apply(self, n, evaluation):
104-
"Fibonacci[n_Integer]"
105-
106-
return Integer(sympy.fibonacci(n.get_int_value()))
104+
sympy_name = "fibonacci"
105+
mpmath_name = "fibonacci"
107106

108107

109108
class PartitionsP(Builtin):
@@ -121,7 +120,31 @@ class PartitionsP(Builtin):
121120

122121
def apply(self, n, evaluation):
123122
"PartitionsP[n_Integer]"
124-
return Integer(len(list(partitions(n.get_int_value()))))
123+
124+
@lru_cache
125+
def number_of_partitions(n: int) -> int:
126+
"""Algorithm NumberOfPartitions from Page 67 of Skiena: Implementing
127+
Discrete Mathematics, using Euler's recurrence"""
128+
if n < 0:
129+
return 0
130+
elif n == 0:
131+
return 1
132+
sum = 0
133+
for m in range(math.ceil((1 + math.sqrt(1.0 + 24 * n)) / 6), 0, -1):
134+
mx3 = m * 3
135+
j = n - m * (mx3 - 1) / 2
136+
k = n - m * (mx3 + 1) / 2
137+
if m % 2:
138+
sum += number_of_partitions(j) + number_of_partitions(k)
139+
else:
140+
sum += -number_of_partitions(j) - number_of_partitions(k)
141+
return sum
142+
143+
return Integer(number_of_partitions(n.get_int_value()))
144+
145+
# Simpler but inefficient.
146+
# from sympy.utilities.iterables import partitions
147+
# return Integer(len(list(partitions(n.get_int_value()))))
125148

126149

127150
class _NoBoolVector(Exception):
@@ -291,12 +314,13 @@ def _compute(self, n, c_ff, c_ft, c_tf, c_tt):
291314
r = 2 * (c_tf + c_ft)
292315
return Expression("Divide", r, c_tt + c_ff + r)
293316

317+
294318
# Note: WL allows StirlingS1[{2, 4, 6}, 2], but we don't (yet).
295319
class StirlingS1(Builtin):
296320
"""
297321
<dl>
298322
<dt>'StirlingS1[$n$, $m$]'
299-
<dd>gives the Stirling number of the first kind $𝒮_n^m$.
323+
<dd>gives the Stirling number of the first kind $ _n^m$.
300324
</dl>
301325
302326
Integer mathematical function, suitable for both symbolic and numerical manipulation.
@@ -321,10 +345,10 @@ class StirlingS2(Builtin):
321345
"""
322346
<dl>
323347
<dt>'StirlingS2[$n$, $m$]'
324-
<dd>gives the Stirling number of the second kind 𝒮_n^m.
348+
<dd>gives the Stirling number of the second kind _n^m.
325349
</dl>
326350
327-
returns the number of ways of partitioning a set of $n$ elements into $m$ nonempty subsets.
351+
returns the number of ways of partitioning a set of $n$ elements into $m$ non empty subsets.
328352
329353
>> Table[StirlingS2[10, m], {m, 10}]
330354
= {1, 511, 9330, 34105, 42525, 22827, 5880, 750, 45, 1}

0 commit comments

Comments
 (0)