Dynamic programming is a technique for avoiding the repeated computation of the same values in a recursive program. Each value computed is immediately stored. If the value is needed again, it is not computed but simply looked up in the table. (1)
I use orthogonal polynomials a fair bit in my work. Since Mathematica supports only the classical ones, I often have to write my own functions. For instance, the monic Charlier polynomials satisfy the three-term recurrence
$$C_{n+1}^{(a)}(x)=(x-a-n)C_n^{(a)}(x)-an C_{n-1}^{(a)}(x)$$
with $C_0^{(a)}(x)=1$ and $C_1^{(a)}(x)=x-a$.
If I want to be able to use monic Charlier polynomials in Mathematica, I can do this:
CharlierC[0, a_, x_] := 1;
CharlierC[1, a_, x_] := x - a;
CharlierC[n_Integer, a_, x_] := (x - a - n + 1) CharlierC[n - 1, a, x] -
a (n - 1) CharlierC[n - 2, a, x]
The problem with this route, of course, is that the effort expended to generate, say, CharlierC[20, a, x]
can't be used for evaluating CharlierC[50, a, x]
. For a one-argument recursive function (e.g. Fibonacci), dynamic programming is fine and dandy for saving evaluation effort. For a multiple-argument function, imagine what would happen if one had used the definition CharlierC[n_Integer, a_, x_] := CharlierC[n, a, x] = (* stuff *)
and then executed Plot[{CharlierC[5, 1, x], CharlierC[6, x, 2]}, {x, -1, 1}]
.
Is there a way to reap the benefits of dynamic programming on a multiple-argument function, while storing only results where the recursion variable (n
in the Charlier example) changes?
CharlierC[n, x, a] == (-1)^n HypergeometricU[-n, 1 - n + x, a]
, so there is no need to use the recursive definition for this one. $\endgroup$QHypergeometricPFQ[]
, but it seems that even a recursive definition can sometimes go a bit faster than using that. But yeah, even the humble Charlier polynomial is fascinating! :) $\endgroup$