This is what I do. I have been using this method for long time. The idea is simple.
Use the second argument of Dynamics. In there, make any changes to the state of the program you want, that only relates to the change of the current control variable being changed. In your case, in the second argument of a
and b
, you can make your heavy computations. In t
, you do not. The result of the computation is stored in f
Then if you want to update the main display, simply tickle the heart beat
control variable. There is only ONE heart beat control variable to the whole program. No matter how large or complicated the program is.
i.e. one tracked control variable in the whole program. This is called the tick
below.
So, this is like callback programming in openGL and any other event based GUI programing, so it is easy to learn and adopt and very flexible. The callback, is the second argument of Dynamics
.
You can see from the movie below, that f
is only updated when you move a
and b
but remains the same when t
is moved.
This is very flexible as you can change the state machine logic any way you want and it scales to much more complicated logic.
Manipulate[
tick;
Grid[{
{Row[{"f=", f, " a=", a, " b=", b, " t=", t}]},
{Plot[(f t) Sin[t + r], {r, 0, 2 Pi}, ImagePadding -> 30,
ImageSize -> 400, Frame -> True]}
}],
Grid[{
{"a", Manipulator[Dynamic[a, {a = #; f = preCalculateStuff[a, b];
tick = Not[tick]} &], {0, 1, 0.01}], Dynamic[a]},
{"b", Manipulator[Dynamic[b, {b = #; f = preCalculateStuff[a, b];
tick = Not[tick]} &], {0, 1, 0.01}], Dynamic[b] },
{ "t", Manipulator[Dynamic[t, {t = #; tick = Not[tick]} &], {0, 1, 0.01}],
Dynamic[t]}
}, Alignment -> Center, Spacings -> {.5, .5}
],
{{tick, False}, None},
{{a, .5}, None},
{{b, .4}, None},
{{t, .7}, None},
{{f, .5*.4}, None},
TrackedSymbols :> {tick},
Initialization :>
(
preCalculateStuff[a_, b_] := Module[{},
(*heavy computation goes here*)
a*b
]
)
]

update:
Just a small background on this: At first I used a different setup than the above, but which still avoids the problem being discussed here. I documented that method in this event_driven_manipulate note. The above is a simplified and easier to understand version of the earlier method.
I plan to make a second version note to document this pattern more but too many HW's and never got around to it. This simplified method is what I use now and not the first method in the above note for all my demos and any manipulate I write. I used it for small 200 lines demos to more complicated 3000 lines demos, and this method works and scales well I found.
a
andb
discrete or continuous? If discrete I'd use memoization. $\endgroup$