Skip to content

Commit 9db06f7

Browse files
committed
PartitionsP[] improve efficiency...
By special casing negative numbers in PartitionsP we can greatly expand efficiency and reduce caching by 1/2. Make sure to include negative values in PartitionsP[] test.
1 parent fc9e35d commit 9db06f7

1 file changed

Lines changed: 15 additions & 9 deletions

File tree

mathics/builtin/combinatorial.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#!/usr/bin/env python3
21
# -*- coding: utf-8 -*-
32
"""
43
Combinatorial Functions
@@ -104,12 +103,13 @@ class Fibonacci(_MPMathFunction):
104103
mpmath_name = "fibonacci"
105104

106105
# 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,
106+
# n different values (positive and negative) occur.
107+
# For this function to be effective across top-level calls,
109108
# it needs to be at the module level rather than inside the class.
110109
# 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
110+
# With 1024 we can handle reasonably values of slightly greater than 1024
111+
# values without trouble:
112+
# PartitionsP[1070] = 366665450770488753893927654278831
113113
@lru_cache(maxsize=1024)
114114
def number_of_partitions(n: int) -> int:
115115
"""Algorithm NumberOfPartitions from Page 67 of Skiena: Implementing
@@ -123,10 +123,16 @@ def number_of_partitions(n: int) -> int:
123123
mx3 = m * 3
124124
j = n - m * (mx3 - 1) / 2
125125
k = n - m * (mx3 + 1) / 2
126+
# Cut down on memoization by filtering negative numbers here.
127+
# In contrast to the multitude of negative numbers, the n==0
128+
# case isn't worth saving memoization checking since that is
129+
# one single entry.
130+
part_j = 0 if j < 0 else number_of_partitions(j)
131+
part_k = 0 if k < 0 else number_of_partitions(k)
126132
if m % 2:
127-
sum += number_of_partitions(j) + number_of_partitions(k)
133+
sum += part_j + part_k
128134
else:
129-
sum += -number_of_partitions(j) - number_of_partitions(k)
135+
sum += -part_j - part_k
130136
return sum
131137

132138
class PartitionsP(Builtin):
@@ -136,8 +142,8 @@ class PartitionsP(Builtin):
136142
<dd>return the number p(n) of unrestricted partitions of the integer $n$.
137143
</dl>
138144
139-
>> Table[PartitionsP[k], {k, 0, 12}]
140-
= {1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42, 56, 77}
145+
>> Table[PartitionsP[k], {k, -2, 12}]
146+
= {0, 0, 1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42, 56, 77}
141147
"""
142148

143149
attributes = ("Listable", "NumericFunction", "Orderless")

0 commit comments

Comments
 (0)