# Function memoization using dynamic binding. (1.02)
from time import process_time
# Class for dynamic binding of a variable.
class Parameter:
def __init__(self, v):
self.v = v
def __call__(self):
return self.v
def bind(self, v, thunk):
t = self.v
self.v = v
thunk()
self.v = t
# Memo.
def setdelayed(m, key, thunk=lambda: None):
if key not in m:
m[key] = thunk()
return m[key]
def memo(f, keyfunc=lambda x: x):
m = {}
def wrapper(*args):
return setdelayed(m, keyfunc(args), lambda: f(*args))
return wrapper
def lru_memo(f, maxsize=128, keyfunc=lambda x: x):
m = {}
def wrapper(*args):
k = keyfunc(args)
if k in m:
m[k] = v = m.pop(k)
else:
m[k] = v = f(*args)
if len(m) > maxsize:
del m[next(iter(m))]
return v
return wrapper
# Main.
fib = Parameter(lambda n: fib()(n-2) + fib()(n-1) if n > 1 else n)
def make_f(f):
return lambda: fib.bind(f, lambda: print(fib()(30), repr(fib())))
def time_f(thunk):
t = process_time()
thunk()
print('Elapsed: {:.6f}s'.format(process_time() - t))
time_f(make_f(lru_memo(fib(), 2)))
time_f(make_f(memo(fib())))
time_f(make_f(fib()))
IyBGdW5jdGlvbiBtZW1vaXphdGlvbiB1c2luZyBkeW5hbWljIGJpbmRpbmcuICgxLjAyKQoKZnJvbSB0aW1lIGltcG9ydCBwcm9jZXNzX3RpbWUKCiMgQ2xhc3MgZm9yIGR5bmFtaWMgYmluZGluZyBvZiBhIHZhcmlhYmxlLgoKY2xhc3MgUGFyYW1ldGVyOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIHYpOgogICAgICAgIHNlbGYudiA9IHYKICAgIGRlZiBfX2NhbGxfXyhzZWxmKToKICAgICAgICByZXR1cm4gc2VsZi52CiAgICBkZWYgYmluZChzZWxmLCB2LCB0aHVuayk6CiAgICAgICAgdCA9IHNlbGYudgogICAgICAgIHNlbGYudiA9IHYKICAgICAgICB0aHVuaygpCiAgICAgICAgc2VsZi52ID0gdAoKIyBNZW1vLgoKZGVmIHNldGRlbGF5ZWQobSwga2V5LCB0aHVuaz1sYW1iZGE6IE5vbmUpOgogICAgaWYga2V5IG5vdCBpbiBtOgogICAgICAgIG1ba2V5XSA9IHRodW5rKCkKICAgIHJldHVybiBtW2tleV0KCmRlZiBtZW1vKGYsIGtleWZ1bmM9bGFtYmRhIHg6IHgpOgogICAgbSA9IHt9CiAgICBkZWYgd3JhcHBlcigqYXJncyk6CiAgICAgICAgcmV0dXJuIHNldGRlbGF5ZWQobSwga2V5ZnVuYyhhcmdzKSwgbGFtYmRhOiBmKCphcmdzKSkKICAgIHJldHVybiB3cmFwcGVyCgpkZWYgbHJ1X21lbW8oZiwgbWF4c2l6ZT0xMjgsIGtleWZ1bmM9bGFtYmRhIHg6IHgpOgogICAgbSA9IHt9CiAgICBkZWYgd3JhcHBlcigqYXJncyk6CiAgICAgICAgayA9IGtleWZ1bmMoYXJncykKICAgICAgICBpZiBrIGluIG06CiAgICAgICAgICAgIG1ba10gPSB2ID0gbS5wb3AoaykKICAgICAgICBlbHNlOgogICAgICAgICAgICBtW2tdID0gdiA9IGYoKmFyZ3MpCiAgICAgICAgICAgIGlmIGxlbihtKSA+IG1heHNpemU6CiAgICAgICAgICAgICAgICBkZWwgbVtuZXh0KGl0ZXIobSkpXQogICAgICAgIHJldHVybiB2CiAgICByZXR1cm4gd3JhcHBlcgoKIyBNYWluLgoKZmliID0gUGFyYW1ldGVyKGxhbWJkYSBuOiBmaWIoKShuLTIpICsgZmliKCkobi0xKSBpZiBuID4gMSBlbHNlIG4pCgpkZWYgbWFrZV9mKGYpOgogICAgcmV0dXJuIGxhbWJkYTogZmliLmJpbmQoZiwgbGFtYmRhOiBwcmludChmaWIoKSgzMCksIHJlcHIoZmliKCkpKSkKCmRlZiB0aW1lX2YodGh1bmspOgogICAgdCA9IHByb2Nlc3NfdGltZSgpCiAgICB0aHVuaygpCiAgICBwcmludCgnRWxhcHNlZDogezouNmZ9cycuZm9ybWF0KHByb2Nlc3NfdGltZSgpIC0gdCkpCgp0aW1lX2YobWFrZV9mKGxydV9tZW1vKGZpYigpLCAyKSkpCnRpbWVfZihtYWtlX2YobWVtbyhmaWIoKSkpKQp0aW1lX2YobWFrZV9mKGZpYigpKSk=