# Using block or module to free cache

I'm writing some code at the moment that schematically looks like:

(set initial conditions for some differential equation for given parameters (M,R,...))

M=1;
R=1:


(NDSolve differential equation taking ~10mins or more to give solution dependent on some more paramaters (w,l,m); defining a memoized function)

Phi[w_?NumericQ,l_?IntegerQ,m_?IntegerQ]:=Phi[w,l,m]= "Interpolated Func result of  NDSolve taking 10mins to compute"


(For a given parameter set (w,l,m) compute a few things, such as coefficients and the (w,l,m) term in a sum, for which numerical differentiation ND[..] is needed, hence the necessity of memoizing this Phi to speed this step up)

A[w,l,m]:= "some calc dependent on the Phi";
B[w,l,m]:= "some calc dependent on the Phi"
termSum[w,l,m]:= "some calc dependent on the Phi and A,B"


(write termSum to file)

PutAppend[...]


(clear cache of the memoized Phi[w,l,m] interp func and the other variables like A[w,l,m])

Phi[1,2,3]:=.   (*unset*)


. . . (after the rinse now repeat for a different (w,l,m))

Implemented by some 'do' or 'for' loop.


Some issues I'm considering:

1) Is there a way to use Block/Module say to allow me to better handle my caching of the variables (especially the huge memory hogs like the Phi that is a very large Interpolating Function)?

2) Also if I change my initial parameters M, R etc. I have to start all over again with setting initial conditions and so forth and functions that depend. Could I use Block/Module to incorporate this?

3) Is there a way to run some kind of initialization script in Mathematica that will set my constants, run my standard definitions etc. each time I load the notebook?

4) In a later calculation I will probably use the Phi,A,B for a given (w,l,m) all over again but for different values of 'r' along the range of the interpolating function. I've thought of saving to hard memory the actual interpolating functions of a given (w,l,m) but normal Save leads to 200MB files, and even DumpSave >20MB. Anything I could do about this or do I just have to recompute?

• Just regardng the 4th point. You can export to "mx.gz" or "wdx.gz". This saves a lot of space. Aug 1 '12 at 12:43
• You may find this question relevant, and possibly also this one. Aug 1 '12 at 14:30
• You can use, specially Block, so that your definitions are only valid in it. InternalInheritedBlock can let you add local memoization without you losing the function definition. Also, what's the problem of a >20MB DumpSave? I would definately go for that: memoization inside an InheritedBlock (or Block), dump saving the result for later use.
– Rojo
Aug 1 '12 at 18:18
• Btw, DumpSave can save all your definitions in a single file (question 3) ). Also think of having an external script (a .m file to call with Get), initialization cell. You could even store your already calculated data hidden in your notebook. It all depends on your taste and use case
– Rojo
Aug 1 '12 at 18:20
• Aug 2 '12 at 11:29

I know this is a very old question, but I recently wondered this myself and came up with this solution. My idea is to write a wrapper function the will cache function values for evaluations inside of the wrapper and then forget about them once it's done. You can do this with InheritedBlock:

SetAttributes[WithCachedValues, HoldAll];

WithCachedValues[functions : {__Symbol}, expr_] := InternalInheritedBlock[functions,
Scan[
Function[{fun},
Module[{outsideQ = True},
DownValues[fun] = Prepend[ DownValues[fun],
HoldPattern[fun[args___] /; outsideQ] :> Block[{outsideQ = False},
With[{value = fun[args]},
Set[
fun[args],
value
] /; value =!= Unevaluated[fun[args]]
]
]
]
],
HoldFirst
],
Unevaluated[functions]
];
expr
];


To show how this works, define a dummy function like this:

ClearAll[f]
f[x_] := (Pause[1]; Print[x]; Sin[x]);


Calling f with WithCachedValues will only evaluate each argument of f once and then save the result for subsequent evaluations:

WithCachedValues[{f},
{f[1], f[1], f[2], f[1], f[2]}
] // AbsoluteTiming


1

2

{2.00119, {Sin[1], Sin[1], Sin[2], Sin[1], Sin[2]}}

Once WithCachedValues is finished, the DownValues of f will be reset and the cached values will be cleared:

DownValues[f]


{HoldPattern[f[x_]] :> (Pause[1]; Print[x]; Sin[x])}

# Edit

This function is now also available on the Wolfram Function Repository

• +1. The ideas are not completely new - bit and pieces scattered over the site (one post I remember off the top of my head is this one ), but collecting them together like this is nice. Something rather close to your code can also be found in internal code of Databases  : Needs["GeneralUtilities"]; Needs["Databases"]; PrintDefinitions @ DatabasesCommonDBBlockExtend (of course I don't expect this one to be widely known to the visitors of this site). Oct 4 '20 at 11:03

I appreciate that your code is probably too complex to post here, and that therefore we only have a sketch of what you’re doing, and therefore can’t give you absolutely precise advice. Here are some initial reactions.

1. Yes, you can use Module to scope variables, but this is more about avoiding memory clashes than saving memory. You will find the information in this question useful.
2. Why not make your other functions dependent on M and R? By the way, it is not good practice to use single-capital-letter names for functions in Mathematica, because some of them clash with built-in symbols. Also, it seems that definitions like A[w,l,m]:= aren't really functions because w, l and m aren't patterns. I think you mean A[w_,l_,m_]:=. If you use this version, you don't need to redefine the function every time you change m, assuming this is the same as M.
3. Yes, you could either (a) put these definitions in a package (.m file) and load that using Needs["myPackage"], or (b) put the relevant defintions in initialization cells.
4. Ajasja’s suggestion in comments to use one of the gzipped formats supported by Mathematica. The function \$ExportFormats shows what formats are supported in your version and platform.

A couple of other suggestions:

• Try Clear instead of Unset.
• Try writing the results to individual files instead of using PutAppend. (You will need to use StringJoin and various other functions to automatically construct filenames.)
• 1. I thought if I used Module/Block I could get some automatic resetting of cache facilities? Am I better off just resetting things like Phi at the end of some loop by hand? 2. Yes you're right these are bad names M,R will change these. I already have something like "A[w_,l_,m_]:=" in my code, sorry, was trying to brief. Also m, M are distinct. 3) &4) Thanks I will try these, very useful. Regarding Clear instead of Unset, I tried this first, but on Phi[w,l,m] object it failed; I think because of the fact it's not a symbol being the InterpolatingFunction, or something like that. Aug 1 '12 at 14:27