Reputation: 1223
I have a recursive algorithm in which I calculate some probability values. The input is a list of integers and a single integer value, which represents a constant value.
For instance, p([12,19,13], 2)
makes three recursive calls, which are
p([12,19],0)
and p([13], 2)
p([12,19],1)
and p([13], 1)
p([12,19],2)
and p([13], 0)
since 2 can be decomposed as 0+2, 1+1 or 2+0. Then each call follows a similar approach and makes several other recursive calls.
The recursive algorithm I have
limit = 20
def p(listvals, cval):
# base case
if len(listvals) == 0:
return 0
if len(listvals) == 1:
if cval == 0:
return listvals[0]/limit
elif listvals[0] + cval > limit:
return 0
else:
return 1/limit
result = 0
for c in range(0,cval+1):
c1 = c
c2 = cval-c
listvals1 = listvals[:-1]
listvals2 = [listvals[-1]]
if listvals[-1] + c2 <= limit:
r = p(listvals1, c1) * p(listvals2, c2)
result = result+r
return result
I have been trying to convert this into a bottom up DP code, but could not figure out the way I need to make the iteration.
I wrote down all the intermediate steps that are needed to be calculated for the final result, and it is apparent that there are lots of repetitions at the bottom of the recursive calls.
I tried creating a dictionary of pre-calculated values as given below
m[single_value]=[list of calculated values]
and use those values instead of making the second recursive call p(listvals2, c2)
, but it did not help much as far as the running time is concerned.
How can I improve the running time by using a proper bottom-up approach?
Upvotes: 0
Views: 265
Reputation: 8287
Not sure that I understand what your program wants to compute, so can't help on that, maybe explain a bit more?
Regarding improving performance, you are caching only the leaf nodes of the computations that are repeated in recursive calls. A better way to do that would be have the first parameter of your function p
as a tuple instead of a list, and then use tuple of both the arguments to p
as caching keys in the dictionary.
Python's standard library functools
provides a simple way to do this fairly common piece.
from functools import wraps
def cached(func):
cache = {}
@wraps(func)
def wrapped(listvals, cval):
key = (listvals, cval)
if key not in cache:
cache[key] = func(key)
return cache[key]
return wrapped
Use this decorator to cache all calls function:
@cached
def p(listvals, cval):
Now have your p
take tuple instead of list:
p((12,19,13), 2)
Upvotes: 1