|
from functools import wraps |
|
|
|
|
|
def recurrence_memo(initial): |
|
""" |
|
Memo decorator for sequences defined by recurrence |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.utilities.memoization import recurrence_memo |
|
>>> @recurrence_memo([1]) # 0! = 1 |
|
... def factorial(n, prev): |
|
... return n * prev[-1] |
|
>>> factorial(4) |
|
24 |
|
>>> factorial(3) # use cache values |
|
6 |
|
>>> factorial.cache_length() # cache length can be obtained |
|
5 |
|
>>> factorial.fetch_item(slice(2, 4)) |
|
[2, 6] |
|
|
|
""" |
|
cache = initial |
|
|
|
def decorator(f): |
|
@wraps(f) |
|
def g(n): |
|
L = len(cache) |
|
if n < L: |
|
return cache[n] |
|
for i in range(L, n + 1): |
|
cache.append(f(i, cache)) |
|
return cache[-1] |
|
g.cache_length = lambda: len(cache) |
|
g.fetch_item = lambda x: cache[x] |
|
return g |
|
return decorator |
|
|
|
|
|
def assoc_recurrence_memo(base_seq): |
|
""" |
|
Memo decorator for associated sequences defined by recurrence starting from base |
|
|
|
base_seq(n) -- callable to get base sequence elements |
|
|
|
XXX works only for Pn0 = base_seq(0) cases |
|
XXX works only for m <= n cases |
|
""" |
|
|
|
cache = [] |
|
|
|
def decorator(f): |
|
@wraps(f) |
|
def g(n, m): |
|
L = len(cache) |
|
if n < L: |
|
return cache[n][m] |
|
|
|
for i in range(L, n + 1): |
|
|
|
F_i0 = base_seq(i) |
|
F_i_cache = [F_i0] |
|
cache.append(F_i_cache) |
|
|
|
|
|
|
|
for j in range(1, i + 1): |
|
F_ij = f(i, j, cache) |
|
F_i_cache.append(F_ij) |
|
|
|
return cache[n][m] |
|
|
|
return g |
|
return decorator |
|
|