Don't cry because it's over, smile because it happened.
- Dr. Seuss
After 12 weeks, CSC148H1 for winter 2014 is coming to a conclusion. Ultimately, this means that this will be the last post I make in this SLOG. It is fitting that for this last post I will be talking about Memo(r)ies - Memoization.
Memoization is the process of keeping track of already computed values, if you know that your algorithm will end up using the same value multiple times. A good example of this is the recursive function to find the fibonacci sequence.
def fib(n): """Return the nth fibonacci number""" if n < 2: return n else: return fib(n - 1) + fib(n - 2)
A function such as the above will call fib multiple times on the same numbers. For example, calling fib(4) will require calling fib(3) and fib(2), which will then call fib(2) again and fib(1). As n increases, fib(n - 1) and fib(n - 2) is called more and more frequently.
So we use memoization:
def fib(n:int): """Return the nth fibonacci number""" computed = {} # already-computed values of fib def fibmem(k:int): if k in computed: # this and next op are O(1) return computed[k] elif k < 2: computed[k] = k else: computed[k] = fibmem(k - 1) + fibmem(k - 2) return computed[k] return fibmem(n)
Memoization in python can be achieved via nested functions, by defining a dictionary of computed values, and then loading from the dictionary within the nested function.
I inadvertently discovered this ability when computing M(n) for assignment I, in order to determine the optimal i value for n number of cheese. However, my approach required the use of the keyword "nonlocal". This keyword is used to specify that a variable should be usable outside of the local function I(n), but not necessarily globally. This was weird however, considering that the fib(n) function shown about did not require this keyword. I looked further into it and discovered that it depended entirely on whether there existed an assignment statement such as x = x ... where x was the non local variable. In other words, you require a special declaration to alter the existing variable based on itself.
# This is okay def f(x): y = 1 def g(x): return x - y return g(x)
# This is not okay def f(x): y = 1 def g(x): y = y * 1 return x - y return g(x)
And this is interesting because it is easy to add new memories, but that doesn't mean you have to alter the existing ones. Thank you for the great year!