Skip to content

Commit fc9e35d

Browse files
committed
Merge branch 'add-PartitionsP' of github.com:mathics/Mathics into add-PartitionsP
2 parents a87640c + dfc871e commit fc9e35d

1 file changed

Lines changed: 25 additions & 19 deletions

File tree

mathics/builtin/combinatorial.py

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,31 @@ class Fibonacci(_MPMathFunction):
103103
sympy_name = "fibonacci"
104104
mpmath_name = "fibonacci"
105105

106+
# Note: memoizing functions is a big win. For a value of n, more than
107+
# 1.3 n different values (positive and negative) occur.
108+
# Also for this function to be effective across top-level calls,
109+
# it needs to be at the module level rather than inside the class.
110+
# Finally, docs say that `maxsize` is best at a power of 2.
111+
# With 1024 we can handle reasonably values of n=900:
112+
# PartitionsP[900] = 415873681190459054784114365430
113+
@lru_cache(maxsize=1024)
114+
def number_of_partitions(n: int) -> int:
115+
"""Algorithm NumberOfPartitions from Page 67 of Skiena: Implementing
116+
Discrete Mathematics, using Euler's recurrence"""
117+
if n < 0:
118+
return 0
119+
elif n == 0:
120+
return 1
121+
sum = 0
122+
for m in range(math.ceil((1 + math.sqrt(1.0 + 24 * n)) / 6), 0, -1):
123+
mx3 = m * 3
124+
j = n - m * (mx3 - 1) / 2
125+
k = n - m * (mx3 + 1) / 2
126+
if m % 2:
127+
sum += number_of_partitions(j) + number_of_partitions(k)
128+
else:
129+
sum += -number_of_partitions(j) - number_of_partitions(k)
130+
return sum
106131

107132
class PartitionsP(Builtin):
108133
"""
@@ -120,25 +145,6 @@ class PartitionsP(Builtin):
120145
def apply(self, n, evaluation):
121146
"PartitionsP[n_Integer]"
122147

123-
@lru_cache
124-
def number_of_partitions(n: int) -> int:
125-
"""Algorithm NumberOfPartitions from Page 67 of Skiena: Implementing
126-
Discrete Mathematics, using Euler's recurrence"""
127-
if n < 0:
128-
return 0
129-
elif n == 0:
130-
return 1
131-
sum = 0
132-
for m in range(math.ceil((1 + math.sqrt(1.0 + 24 * n)) / 6), 0, -1):
133-
mx3 = m * 3
134-
j = n - m * (mx3 - 1) / 2
135-
k = n - m * (mx3 + 1) / 2
136-
if m % 2:
137-
sum += number_of_partitions(j) + number_of_partitions(k)
138-
else:
139-
sum += -number_of_partitions(j) - number_of_partitions(k)
140-
return sum
141-
142148
return Integer(number_of_partitions(n.get_int_value()))
143149

144150
# Simpler but inefficient.

0 commit comments

Comments
 (0)