Reputation: 2151
In the Think Python book Chapter 11, Allen Downey mentions that "... a previously computed value that is stored for later use is called a memo" (p. 107).
The following function is then re-written to improve it by using memos:
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fibonacci(n-1) + fibonacci(n-2)
The re-written function looks like the following:
known = {0: 0, 1: 1}
def memoized_fibonacci(n):
if n in known:
return known[n]
res = fibonacci(n-1) + fibonacci(n-2)
known[n] = res
return res
I am wondering, why it is necessary to add the recursion call (here: 'res') to the dictionary (memo) before returning it.
If I print the dictionary after any call of fibonacci, the dictionary just contains the information that has been there before (0:0, 1:1) as well as the information for n:
>> memoized_fibonacci(7)
>> print known
>> {0: 0, 1: 1, 7: 13}
so no intermediate results are being saved that could be helpful to save time (memo). Using the time module, I furthermore can only gain a minimum time advantage of the memoized_fibonacci function over the simpler fibonacci function. (I.e. for memoized_fibonacci(40) I take 58.1 seconds and for fibonacci(40) I take 58.8 seconds)
Deleting the known[n] = res
call does not slow the memoized function down either.
known = {0: 0, 1: 1}
def memoized_fibonacci(n):
if n in known:
return known[n]
return fibonacci(n-1) + fibonacci(n-2) # Not slower!
Am I missing the point here? Could somebody explain to me, why calling known[n] = res
is important? Thanks!
Upvotes: 2
Views: 2364
Reputation: 1222
known[res] = n
is needed otherwise you wont store the result in "known" and you will need to recalculate all the elements of the progression every time.
If you start with known = {0:0, 1:1}, after fibonacci(29) known will be populated with:
{0: 0, 1: 1, 2: 1, 3: 2, 4: 3, 5: 5, 6: 8, 7: 13, 8: 21, 9: 34, 10: 55, 11: 89, 12: 144, 13: 233, 14: 377, 15: 610, 16: 987, 17: 1597, 18: 2584, 19: 4181, 20: 6765, 21: 10946, 22: 17711, 23: 28657, 24: 46368, 25: 75025, 26: 121393, 27: 196418, 28: 317811, 29: 514229}
Then moving to fibonacci(30) is almost instantaneous because both fibonacci(29) and fibonacci(28) are in known.
Upvotes: 1
Reputation: 122136
You have made a typo. The code from the book is:
known = {0:0, 1:1}
def fibonacci(n):
if n in known:
return known[n]
res = fibonacci(n-1) + fibonacci(n-2) # note same name
known[n] = res
return res
If you rename the function (to memoized_fibonacci
) you need to change the recursive calls, too. Otherwise the memoized version is calling the un-memoized version, and you don't get any benefit.
Upvotes: 4