62

General The conceptual problem with memoized pure functions is that pure functions typically (in fact, normally by their mere definition) do not cause side effects, while memoization necessarily requires side effects (changes of state). What was meant was probably to construct a memoized anonymous (lambda) - functions - this is possible, because the latter ...


30

This is quite easy to achieve by direct manipulation of downvalues. Here's a simple example: ClearAll[removeDownValues]; SetAttributes[removeDownValues, HoldAllComplete]; removeDownValues[p : f_[___]] := DownValues[f] = DeleteCases[ DownValues[f, Sort -> False], HoldPattern[Verbatim[HoldPattern][p] :> _] ]; Now let's memoize some values: ...


19

Cause of speed up This is definitely not memoization. The reason for the observed speed up is that for large arrays (e.g. 10^8 elements), the memory clean up operations may take noticeable time. If one doesn't free memory, one can perform some operations a bit faster. Here is a simple example: Let's create a large array, then perform a calculation, and ...


18

The case at hand Here is one possibility: ClearAll[fibon] Options[fibon] = {k -> 1} fibon[0, OptionsPattern[]] = 0; fibon[1, OptionsPattern[]] = 1; fibon[n_, opts : OptionsPattern[]] /; ! OrderedQ[{opts}] := fibon[n, Sequence @@ Sort[{opts}]]; fibon[n_, opts : OptionsPattern[]] := fibon[n, opts] = fibon[n - 1, opts] + OptionValue[k]*fibon[n ...


17

Preamble I will present a sort of a packaged and automated solution, which uses deques and metaprogramming to automate caching. This should work for most normal pattern-based functions. Deques I will use Daniel Lichtblau's implementation for a deque, taken from his great account on Data Structures and Efficient Algorithms in Mathematica. Here it is: ...


15

For individual cases I believe the most straight forward solution is simply using Unset: For instance: f[x_] := f[x] = x f[1]; f[2]; f[5]; DownValues[f] f[5] =. f[3]; DownValues[f] (* {HoldPattern[f[1]] :> 1, HoldPattern[f[2]] :> 2, HoldPattern[f[5]] :> 5, HoldPattern[f[x_]] :> (f[x] = x)} *) (* {HoldPattern[f[1]] :> 1, ...


15

Suggested solution If I understood the question right, then the simplest solution here would probably be to define a helper function like the following: vv[n_] := Internal`InheritedBlock[{v}, v /@ Range[n]]; Then, you get vel = vv[m] and every run of vv would result in different set of values, while the values in the set will all come from the same ...


14

I wrote the code in question... It is pretty much a line for line port of the Julia version of the benchmark: Julia: fib(n) = n < 2 ? n : fib(n-1) + fib(n-2) Mathematica: fib = Compile[{{n, _Integer}}, If[n < 2, n, fib[n - 1] + fib[n - 2]], CompilationTarget -> "WVM" (* WVM is faster than C in this case because of the recursive ...


14

The problem with a normal shared memoized function definition f[x_] := f[x] = (Pause[3]; N[Sin[x]]) is indeed that any evaluation of f[n] on a parallel subkernel causes the rhs f[x] = (Pause[3]; N[Sin[x]]) to be sent back and evaluated on the master kernel. There is an undocumented feature that if such a definition is made on a subkernel, the rhs will ...


14

If your goal is maximum performance in a kernel session, Once is never the answer. It is just too heavyweight. It does, however, provide a real memoization method--we're still talking about sub-second evaluation, for a computation that wouldn't complete without--that is perhaps easier to read for non-experts. And if each step in the computation is ...


12

I will offer a rather cryptic solution using nested version of the injector pattern, but it should be possible to also rewrite it using more readable methods, if really needed. Solution Here is the code: ClearAll[t]; t[a_]:= c[a] t[a_,b_]:= d[a,b] t[a__]:= With[{vars=Table[Unique[],{Length[{a}]}]}, With[{pts=(Pattern[#1,_]&)/@vars}, ...


12

Not much different from your approach and maybe not the best/safest approach, but DumpSave helps a bit because at least you don't have to works with strings: cacheFile = FileNameJoin[{$TemporaryDirectory, "fibonacciCache" <> ".mx"}]; If[FileExistsQ[cacheFile], Get[cacheFile], fibonacci[1] = 1; fibonacci[2] = 1; fibonacci[n_Integer] := Module[{}, ...


12

You are absolutely correct that this memoization is completely unnecessary. What seems to happens is that from the second run onwards on the same data, the builtin functions become faster. I do not understand why (perhaps some internal caching), but it does show that it has absolutely nothing to do with the memoization: In[38]:= AbsoluteTiming[Pick[data, ...


11

f[x_] := x^2 DownValues[h] = DownValues[f] /. f -> h; f[x_] := f[x] = h[x] h is now equal to the original f, and f is a memoized version of it. Some kinds of definitions would require a more specific replacement rule than /. f -> h, for example recursive functions.


9

Here is something that might be more elaborated than really necessary for your task (for which I think Marius answer might work well enough) but shows some helpful techniques. It basically does the same thing that Marius solution does: it separates the recursion in n from the functional dependence in x but tries to do this a bit more robust and not change ...


9

Your problem arrises because you are recursing downward. With large n such as 50000, this mean a huge recursive structure must be built all the way down to n = 1 before the memoization can take place. Mathematica runs out of memory and the kernel crashes. In other words, the memoization isn't doing you much good. As you point out in your update, you can get ...


8

Q[n_, L_] := Q[n, L] = Integrate[Q[n - 1, L] /. L :> L - a - z, {z, 0, L - (n - 1) a}] Q[2, L_] = 1/2 (a - L)^2 Q[4, L] (* 1/24 (-3 a + L)^4 *)


8

In many cases, memoization helps for a given particular computation, and one can (or even has to) then remove the memoized values. For such cases, protection can nicely coexist with the technique which I call "self-blocking". I will illustrate this using the infamous Fibonacci numbers example: Unprotect[fib]; ClearAll[fib]; fib[n_] := Block[{fib}, fib[...


7

Just for fun, here is an explicit formula for the derivative: f[a_,b_,z_,j_] := Sum[ 1/(j-k)! (2j)!/(2k)! 4^k Pochhammer[a,j+k]/Pochhammer[b,j+k] z^(2k) Hypergeometric1F1[a+j+k,b+j+k,z^2], {k,0,j} ] Confirmation: Table[D[Hypergeometric1F1[a, b, z^2], {z, 2j}] == f[a, b, z, j], {j, 20}] {True, True, True, True, True, True, True, True, True, True,...


7

A general approach in this kind of situations is to use memoization. Here, however, some of the parameters should remain patterns (general), so you can use something like this (see this answer for a similar case): ClearAll[f]; f[a_, b_, z_, j_] := Block[{al, bl, zl}, f[al_, bl_, zl_, j] = D[Hypergeometric1F1[al, bl, zl^2], {zl, 2 j}]; f[a, b, z,...


7

I realize this is an old question, but I recently had the same issue and have come across (link to google groups question) what I think is a cleaner solution. I don't want to take credit for coming up with that solution, but I thought it would be helpful to add it to this site. I'll use a simple example function to demonstrate. f[x_] := f[x] = x ...


7

Without memoization but works too :) Block[{i}, (i = 1; # /. a :> i++)] & /@ {{a, b}, {a, b, c}, {a, b, a, a}, {b, c}} And with: ClearAll[f]; f[a, _Integer] = 0; f[a, {p_, _}] := f[a, p] += 1; f[x_, _] := x; MapIndexed[f, {{a, b}, {a, b, c}, {a, b, a, a}, {b, c}}, {2} ] {{1, b}, {1, b, c}, {1, b, 2, 3}, {b, c}}


7

A long time ago, I wrote a note about how to do this with DownValues. Since then, we got Association, which is a much better data structure for caching. MaTeX uses it for its cache (see the store function in MaTeX.m). Here's a very small example of how we can do this. I tied this cache to a single function, and used a recursive Fibonacci for illustration. A ...


6

Here is a crude way using FoldList. foo[lis_, var_] := Module[{i, f}, f[var] := ++i; f[x_List] := f /@ x; f[x_] := x; Rest @ FoldList[(i = 0; f[#2]) &, var, lis] ] Use: foo[list, a] {{1, b}, {1, b, c}, {1, b, 2, 3}, {b, c}}


6

You could just unprotect and protect on the first call of the recursion. To avoid checking in every inner call if it's the first or not, you could implement it in a an extra private symbol, and use the public interface as a non-recursive wrapper. Unprotect[fac]; ClearAll[fac]; Module[{facPvt}, facPvt[1] = 1; facPvt[n_Integer] := facPvt[n] = n facPvt[n - ...


6

Here's a way using BlankNullSequence: Clear[p]; p[k_] := p[k] = a[k] pk : p[k0___, k1_, k2_] := pk = p[k0, k1] + b^Length[{k0, k1}] p[k1 + k2] We can test this on an example: p[k1, k2, k3, k4, k5] (* a[k1] + b a[k1 + k2] + b^2 a[k2 + k3] + b^3 a[k3 + k4] + b^4 a[k4 + k5] *) And then check Definition[p] to make sure the values were correctly memoized: p[...


6

You mean something like this? Clear[h, x]; h[0] = 0.; h[n_] := h[n] = h[n - 1] + Exp[-x^2]/(2^n*n!)*HermiteH[n,x]*HermiteH[n - 1, x]; tab = Table[h[en] /. x -> ex, {en, 1, nmax}, {ex, xmin, xmax, dx}]


5

The kernel crashed because it ran through all the stack space available to it. The Memory Management Tutorial page in the documentation states the following regarding stack space: In the Wolfram System, one of the primary uses of stack space is in handling the calling of one Wolfram Language function by another. All such calls are explicitly recorded in ...


5

Compile f and use a memo-ized version of it Since it seems like NIntegrate decides to symbolically evaluate its argument first, I thought I'd force it not to by compiling the function f. This seems to make a significant difference: Clear[f, f1, g] g[x_] = Nest[f[x] + 1./# &, f[x], 500]; f1 = Compile[{x}, Sum[1/100 Erfc[-(x^2/k)], {k, 100}]]; f[x_?...


5

Memoize p properly (you had a typo), and make sure you use Evaluate inside of function definitions: Clear[p]; q[{m_, n_}, s_] := KroneckerDelta[m, 1] KroneckerDelta[n, 2] b + b n p[m, n + 1][s] + If[m < 2, 0, b n (n - 1) (p[m - 1, n - 2][s] + p[m - 1, n - 1][s] + p[m - 1, n][s])] p[m_, n_] /; m < 1 || n < 1 || n > m + 1 = Function[t, 0]; p[...


Only top voted, non community-wiki answers of a minimum length are eligible