# Using Refresh to skip expensive computations

I have several variables in my DynamicModule and some parts of my computation depend only on subset of them. I am trying to use Refresh to "cache" values but can't make it work.

Example of the problem:

verySlowFunction[x_] := Module[{}, Print["SLOW"]; x * x];

DynamicModule[
{a = 1, b = 1},
Dynamic[
Module[
{ x = Refresh[verySlowFunction[a], TrackedSymbols :> {a}] },
Column[{
Slider[Dynamic[a]],
Slider[Dynamic[b]],
{a, b , x + x + b}
}]]]]


I expect "SLOW" to be printed only when I drag "a" slider, but it is printed when I'm dragging "b" slider as well.

I know that Dynamic clones whole expression tree on its evaluation, that's why x is always different, but this one doesn't work as well:

Module[
{x},
DynamicModule[
{a = 1, b = 1},
Dynamic[
x = Refresh[verySlowFunction[a], TrackedSymbols :> {a}] ;
Column[{
Slider[Dynamic[a]],
Slider[Dynamic[b]],
{a, b , x + x + b}
}]]]]

-
This is so useful: 12000.org/my_notes/event_driven_GUI_with_Manipulate/… –  Gustavo Delfino Sep 14 '13 at 0:10
Do you know if this approach is actually used by anybody? I imagine there could be a library of helper functions to make it look simpler. –  mikea Sep 14 '13 at 0:39
Besides the author, I am using it. I don't know who else, but it works beautifully. –  Gustavo Delfino Sep 14 '13 at 13:58

Try this one

DynamicModule[{a = 1, b = 1, x = 1},
Column@{Slider@Dynamic[a, (a = #; x = verySlowFunction[a]) &],
Slider@Dynamic[b], Dynamic@{a, b, x + x + b}}]


The second argument in Dynamic is evaluated when the corresponding variable changes.

Or this one

DynamicModule[{a = 1, b = 1},
Column@{Slider@Dynamic[a], Slider@Dynamic[b], Dynamic@{a, b},
Dynamic[x = verySlowFunction[a]]}]


You can manually insert Refresh with TrackedSymbols in the last Dynamic.

-
Thanks, this will work. However in my actual case verySlowFunction depends on more than one argument, and there are several temporary calculations to perform. This would require me to duplicate re-evaluation into lots of controls, right? –  mikea Sep 14 '13 at 0:43
@mikea There are more elegant approach if you have several arguments. See update. –  ybeltukov Sep 14 '13 at 0:53
The second version has some serious omission: it does not include calculations based on x. That's what causes me troubles. –  mikea Sep 14 '13 at 5:50

That's tricky question, I have to admit I do not have general solution but I usually do what is good for particular case. Here I'd use DynamicWrapper:

verySlowFunction[x_] := Module[{}, Print["SLOW"]; x*x];

DynamicModule[{a = 1, b = 1},
DynamicWrapper[
Column@{
Slider@Dynamic[a],
Slider@Dynamic[b],
Dynamic@{a, b, x + x + b}},
x = verySlowFunction[a];]]


This is not the answer to the question how to use Refresh for your purposes but I think it is not bad approach :). I'm looking forward for more answers how one can deal with this.

About link provided by @Gustavo, imo there is to much acrobatics in there which is not necessary in case of DynamicModule. DynamicModule != Manipulate because the body of DM is not automatically updated when variables are.

I appreciate any comments if I'm mistaken somewhere.

-