This is a perfect task to solve with dynamic programming. Using a C++-script found here and some additional optimization, I created this script:
num = 100
scores = [[int(j==0 and i>0) for i in range(num)] for j in range(num)]
max_part = num-1
calculated = [1]
def get_combinations(n, x = max_part):
for i in range(calculated[0], n+1):
for j in range(1, x+1):
if (i-j<0):
scores[i][j] = scores[i][j-1]
continue
scores[i][j] = scores[i][j-1] + scores[i-j][j];
calculated[0] = n
return scores[n][x]
print(get_combinations(50))
This script outputs 204226, and additionally its output is identical for any input value (I only tested up to 65, because the function in your question ran slowly after that).
The major drawback of the dynamic solution is that it is space inefficient. To calculate get_combinations(n)
, one must use O(n^2)
memory to store the scores
-array. However, it performs much better for large values of n
. And an additional feature (my addition to the C++-script) is that if you run the function multiple times, it doesn't recalculate any numbers.
Thus, if get_combinations(5)
has been calculated, then a subsequent call to get_combinations(2)
only requires an array lookup, and a subsequent call to get_combinations(10)
is faster.
This function should work without issues for any n
under 1000 (for input larger than 100 the variable num
needs to be adjusted), and is 400 times faster for n = 65
on my machine in the worst case. Sequentially calculating all values between 1 and 1000 runs in <0.5s.
accel_asc
is your best option in terms of speed. Otherwise, you're stuck with your funciton. In this case, I would first try a different implementation such as PyPy or maybe augment Python a bit with Cython. After that I would just use another language honestly. \$\endgroup\$