1 / 21

Memoization

Memoization. Algorithms Baojian Hua huabj@mail.ustc.edu.cn April 21, 2008. What ’ s memoization?. A systematic method for “ memoizing ” the results of some computation or even arbitrary operations To save the intermediate results To log (debug) …

oliver
Download Presentation

Memoization

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Memoization Algorithms Baojian Hua huabj@mail.ustc.edu.cn April 21, 2008

  2. What’s memoization? • A systematic method for “memoizing” the results of some computation or even arbitrary operations • To save the intermediate results • To log (debug) • … • To ensure correctness (later in this course) • Ex: graph traversal (say DFS) • To reduce complexity • Topic of this slide

  3. Motivating Example /* For an array of string “strs”, we apply some * computation “trans” on each string “s” */ String[] strs = {“aa”, “bb”, “cc”, “aa”, “aa”, …}; void foo(trans:->){ for (String s : strs){ v = trans(s); } }// however, if “trans” is slow, the function // “foo” will be VERY expensive

  4. Motivating Example /* A very simple (but effective) hack is to * memoize the comp’ that have been finished */ String[] strs = {“aa”, “bb”, “cc”, “aa”, “aa”, …}; StringMap<String, X> map; void memoize(trans:->){ for (String s : strs){ if (lookup(map, s)!=null) then return lookup(map, s); else { v = trans(s); enter(map, s, v); } }

  5. Memoizing Intermediate Computations /* Factorial numbers */ fac(int n){ if (n==0) return 1; else return n*fac(n-1); } // It’s crucial to notice that in computing // “fac(n)”, we computed // all values from “fac(0)” to “fac(n-1)”

  6. Memoizing Intermediate Computations /* So, it’s easy to memoize all of them with an * auxiliary map, say an array “result” */ int[] result; fac(int n){ if (n==0) return 1; else{ int tmp = n * fac(n-1); result[n] = tmp; return tmp; } // It’s a save for computing: for (int i=0; i<n; i++) fac(n);

  7. Recursion: Revisited • Divide Conquer • Divide: • Initial problems could be divided into several sub-problems which are NOT overlapping. • Conquer: • Solve these sub-problems individually • Combine • Find the final answer by combing sub-ones

  8. Divide Conquer • Sort: • nearly all • Select: • Searching: • bst, red-black, …

  9. Overlapping Recursions • Overlapping recursions: • with overlapping sub-problems • Ex: int fib (int n){ if (n==0) return 0; else if (n==1) return 1; else return fib (n-1) + fib (n-2); } // though simple, it’s rather slow (try demo …)

  10. Recursion Tree

  11. Complexity • The recurrence equation: T(n) = T(n-1) + T(n-2) The sotion is T(n) = \phi^n, where \phi = 1.618 (golden ratio) Exponential! • It’s elegant, but not usable in practice • The problems is that we are re-computing many sub-items many times…

  12. Another Approach • Use an array arr[n] to store fib(n): arr[0] = 0; arr[1] = 1; for (int i=2; i<=n; i++){ arr[i] = arr[i-1] + arr[i-2]; } // which not only computes fib(n), but also fib(i)

  13. Moral • The total running time is O(n) • We never re-compute any value • any value (array item) is computed and assigned just once (after the initialization) • This is one simplest form of bottom-up memoization

  14. Memoization: top-down int[] arr; // with proper initialization, say -1 int fib (int n){ if (n==0) return 0; else if (n==1) return 1; else if(arr[n]>0) // fib(n) has been computed return arr[n]; else{ int tmp = fib(n-1) + fib(n-2); arr[n] = tmp; return tmp; } }

  15. Memoization: top-down int[] arr; // with proper initialization, say -1 int fib (int n){ if (n==0) return 0; else if (n==1) return 1; else if(arr[n]>0) // fib(n) has been computed return arr[n]; else{ int tmp = fib(n-1) + fib(n-2); arr[n] = tmp; return tmp; } } // with a lazy flavor

  16. Moral • This is the top-down memoization • It’s more attractive for: • it’s more natural for problem trans’ • the order of the computation take care of itself • answers for all of the sub-problems may NOT be computed at all

  17. Table Representation • Above examples make use of a simple table representation • linear structure: int[] arr; • In principal, it’s mapping • map: X->Y • So, any search table rep’ strategies works • arrary-based, list-based, tree-based, hash, … • Next, we explore hash-table

  18. Hash-table (Map)-based HashTable<Integer, Integer> ht = new …(); int fib (int n){ if (n==0) return 0; else if (n==1) return 1; else if(ht.lookup(n)) // fib(n) computed return ht.lookup(n); else{ int tmp = fib(n-1) + fib(n-2); ht.insert(n, tmp); return tmp; } }

  19. Advantage • More natural for problem representation • Uniform: always a map • Don’t blurred by annoying details • Ex: array positions • Easy to extend to more complex situa’ • See next example

  20. Multi-dimension Recursion f(m, n) = 0, if m>n f(m, n) = 1, if m=0 or m=n f(m, n) = f(m, n-1) + f(m-1, n-1) // f maps every integer tuple (m, n) to an // integer f(m, n)

  21. Hash-table (Map)-based HashTable<Tuple<Integer, Integer>, Integer> ht = new …(); int f (int m, int n){ if (m>n) return 0; else if (m==0 || m==n) return 1; else if(ht.lookup(Tuple<m, n>)) return ht.lookup(Tuple<m, n>); else{ int tmp = f (m, n-1) + f (m-1, n-1); ht.insert(Tuple<m, n>, tmp); return tmp; } }

More Related