3
$\begingroup$

The following is a toy example that hopefully shows the problem clearly enough.

Why does the following code create a nice, manipulable output:

simulationOutput = {1337, 2337, 30, 3337};
Clear[tmax]
{irrelevantOutput1, irrelevantOutput2, tmax, irrelevantOutput3} = simulationOutput;
Manipulate[
 Plot[t^2, {t, startTime, endTime}], 
{startTime, Manipulator[Dynamic[startTime, (startTime = Min[tmax - 1, #]; 
       endTime = Max[endTime, Min[# + 1, tmax]]) &], {0, tmax}] &}, 
{endTime, Manipulator[Dynamic[endTime, (endTime = Max[1, #]; 
       startTime = Min[startTime, Max[0, # - 1]]) &], {0, tmax}] &}, 
 Initialization :> ({startTime, endTime} = {0, 1})]

enter image description here

But this (almost identical) code, with the additional Block[],

simulationOutput = {1337, 2337, 30, 3337};
Clear[tmax]
Block[{irrelevantOutput1, irrelevantOutput2, tmax, irrelevantOutput3},
  {irrelevantOutput1, irrelevantOutput2, tmax, irrelevantOutput3} = simulationOutput;
Manipulate[
 Plot[t^2, {t, startTime, endTime}], 
{startTime, Manipulator[Dynamic[startTime, (startTime = Min[tmax - 1, #]; 
       endTime = Max[endTime, Min[# + 1, tmax]]) &], {0, tmax}] &}, 
{endTime, Manipulator[Dynamic[endTime, (endTime = Max[1, #]; 
       startTime = Min[startTime, Max[0, # - 1]]) &], {0, tmax}] &}, 
 Initialization :> ({startTime, endTime} = {0, 1})]]

result in this, un-manipulate-able output?

enter image description here

If you're interested, the background behind my question is as follows. I have a simulation of a system of oscillators. The behavior of this system is then studied by providing initial conditions, then using NDSolve to find the behavior from t=0 to t=tmax. The output of the simulation (as simulationOutput) is then fed into a function (of which the following is a simplified example) so that I can see the results - this is the reason why I'm limiting the range of times in which the startTime and endTime can vary in to keep the values in the range of the InterpolatingFunction.

$\endgroup$

1 Answer 1

8
$\begingroup$

What Block does is to change the values of the existing global values for the time its body is evaluated. In your example because Manipulate has attributes HoldAll that means all arguments of the Manipulate don't evalute during evaluation of that Block's body and the Manipulate with unevaluated content is returned from the Block and sent to the FrontEnd for rendering.

Only in the process of rendering the Manipulate its content is sent from the FrontEnd to the Kernel for another evaluation and that then doesn't know anything about the Blocked values during the original evaluation anymore, which is why your code doesn't work as expected.

You can use Module instead of Block and everything will work as intended, at least as a first impression. But what you then do is to actually create new symbols with every call that will survive and will aggregate memory which might become a problem if that's done often. You could solve that by cleaning them up with a Deinitialization when the Manipulate is deleted, but that might have some issues (it's not exactly easy to understand if and when exactly such a deinitialization is executed, the documentation is vague and experiments don't help much to understand these details).

As long as the values of those local variables are small the best solution is to use DynamicModule (or additional Manipulate-variables without controlers) to store that data. If these values become large in memory size, you'll suffer from the extra effor of moving that data from Kernel to FrontEnd and back, though. Here is how that could look like:

Manipulate[
  Plot[t^2, {t, startTime, endTime}], 
  {
     startTime, 
     Manipulator[Dynamic[startTime,(
          startTime = Min[tmax - 1, #];
          endTime = Max[endTime, Min[# + 1, tmax]]
       ) &], {0, tmax}] &
   },{
     endTime, 
     Manipulator[Dynamic[endTime, (
         endTime = Max[1, #];
         startTime = Min[startTime, Max[0, # - 1]]
       ) &], {0, tmax}] &
   },
   {irrelevantOutput1, None},
   {irrelevantOutput2, None},
   {tmax, None},
   {irrelevantOutput3, None},
   Initialization :> (
     {startTime, endTime} = {0, 1};
     {irrelevantOutput1, irrelevantOutput2, tmax, irrelevantOutput3} = 
        simulationOutput;
    )
]

Unfortunately when working with Manipulate and Dynamic (and to some extent with any functionality that has an unusual evaluation order) the scoping constructs available need fairly much care to achieve what one wants without unexpected side effects...

$\endgroup$
6
  • $\begingroup$ +1 Nice explanation of a difficult question! $\endgroup$
    – Michael E2
    Jun 14, 2013 at 14:30
  • $\begingroup$ Just to clarify, I suppose by values of local variables being small or large, you mean their (memory) size? $\endgroup$
    – Michael E2
    Jun 14, 2013 at 14:34
  • $\begingroup$ @MichaelE2: yes, sure. I meant the memory size. I'll edit the answer. Thanks for the clarification... $\endgroup$ Jun 15, 2013 at 10:38
  • $\begingroup$ @AlbertRetey - thank you! So, to clarify, if I want the performance to be as fast as possible, then I would still have to fall back on the first section of code, yes? $\endgroup$ Jun 17, 2013 at 2:07
  • 3
    $\begingroup$ FYI, I think I've fixed all of the issues with the wonky timing of Deinitialization (for Dynamic, DynamicModule, and all derivative constructs such as Manipulate) for v10. $\endgroup$
    – John Fultz
    Apr 29, 2014 at 2:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.