55"""
66
77
8+ import math
9+ from functools import lru_cache
810import sympy
911from sympy .functions .combinatorial .numbers import stirling
10- from sympy .utilities .iterables import partitions
1112from mathics .version import __version__ # noqa used in loading to check consistency.
1213
1314from 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
109108class 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
127150class _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).
295319class 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$ non‐ empty 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