3

I want to compute the recursively-defined function values r(i,j), which are defined by

r i j  | i<0 || j<0   = 0
       | i==0 && j==0 = 1
       | otherwise    = (i-1) * r (i-2) j + r (i-1) (j-1)

Obviously, the NxN table of these coefficients can be computed in O(N^2). Unfortunately, the straightforward evaluation, like

[[r i j | j <-[0..50]]| i <- [0..50]]

is performed in screamingly ineffective way (exponential complexity). Apparently, Haskell builds the entire recursion tree for each r i j and ignores the values of previously computed r (i-1) (j-1) etc.

What is the elegant and effective way to compute such a table?

3
  • ... I don't know haskell but it seems you want dynamic programming. (googleit) Commented May 17, 2012 at 9:08
  • 4
    You want memoization, see haskell.org/haskellwiki/Memoization Commented May 17, 2012 at 9:23
  • if you want just a single value, rather than the whole table you might want to calculate a generating function for the recursive series. I'm no expert on this but I once heard about that in a lecture about discrete math/combinatorics. maybe the fellas at math.stackexchange.com are able to help you in that regard. Words I associate with that kind of math is "umbral calculus", "gosper algorithm" and "Zeilberger algorithm". Maybe it is helpful. Commented May 17, 2012 at 12:11

1 Answer 1

3

As FUZxxl says, this is a memoisation question.

r i j | i < 0 || j < 0 = 0
      | otherwise      = rss !! i !! j

rss = [[r' i j | j <- [0..]] | i <- [0..]]
  where r' 0 0 = 1
        r' i j = (i-1) * r (i-2) j + r (i-1) (j-1)

If you need an explicit table of precisely the values up to 50, you can use take 51 (map (take 51) rss), or [[r i j | j <-[0..50]]| i <- [0..50]] as you mentioned. Otherwise you can just call r or reference rss directly.

Sign up to request clarification or add additional context in comments.

2 Comments

This is still slower than it could be though, since access will be O(i+j). If you limit yourself to a given size, an array would be more appropriate (lazy array, not unboxed) for O(1) access, and if you want unlimited, a trie of trie (IntMap) should still be faster than a list of list.
And if you are tasteful enough to hate the array library API then use vector instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.