Re: A Dynamic mess
- To: mathgroup at smc.vnet.net
- Subject: [mg92993] Re: A Dynamic mess
- From: chandler.seth at gmail.com
- Date: Wed, 22 Oct 2008 05:38:50 -0400 (EDT)
- References: <gdjq6j$mtj$1@smc.vnet.net>
On Oct 21, 12:43 am, John Fultz <jfu... at wolfram.com> wrote:
> On Mon, 20 Oct 2008 07:32:31 -0400 (EDT), chandler.s... at gmail.com wrote:
> > There has just got to be an easier way to do the following. The
> > example is somewhat silly, but if I could understand how to do this
> > competently, I would learn a lot.
>
> > Suppose I want to compute the sum of an integer (z) and a value
> > chosen from some uniform distribution on the interval 0 to a. I want
> > to do this interactively and I do NOT want the draw from the random
> > distribution to change when I change z, just when I change the
> > parameter a. So, we create the number z as follows:
>
> > z=6;SetterBar[Dynamic[z],{6,7,8}]
>
> > If I do the following, it does not work as expected because, I
> > suppose, Dynamic[z] is a FrontEnd object in its heart of hearts (a
> > DynamicBox) and thus does not add to 2 the way an integer would.
>
> Correct. The thing to keep in mind is that Dynamic[z] evaluates to Dyn=
amic[z].
> If you do...
>
> Dynamic[z]//InputForm
>
> you'll see that. In StandardForm, it displays as something else, in pr=
ecisely
> the same way that a/b looks like "a/b" in InputForm, but displays as some=
thing
> else (i.e. a FractionBox) in StandardForm. Any further evaluations are=
a side
> effect of that display, and not a principal effect of evaluating Dynamic[=
].
>
>
>
> > Dynamic[z]+2
>
> > So, this can be fixed with Dynamic[z+2]
>
> > OK, now instead of adding 2, let's add some random value
>
> > a=0.5;Slider[Dynamic[a]];
>
> > Dynamic[z+RandomReal[{0,Setting@Dynamic[a]}]] (* setting is added
> > because if one just uses Dynamic[a] one is referencing a front end
> > object rather than an actual number*)
>
> Are you hoping that the internal Dynamic will somehow freeze the RandomRe=
al[]
> unless 'a' has been explicitly changed? This won't happen for two reas=
ons. One
> is that an outer Dynamic reevaluates its contents entirely, including inn=
er
> Dynamics, whenever it's triggered (as it will be by the change in 'z'). =
But the
> more important reason is that the inner Dynamic doesn't actually have any
> Dynamic functionality. Observe...
>
> In[12]:= Setting[Dynamic[a]] // InputForm
>
> Out[12]//InputForm= 0.5
>
> Recall that I said that Dynamic[] evaluates to itself. But Setting of =
Dynamic[]
> evaluates not to a dynamic result, but to the contents of the Dynamic.
>
> So your statement is effectively the same as...
>
> Dynamic[z + RandomReal[{0, a}]]
>
> Keep reading for the solution...
>
>
>
> > This evaluates, but it does not have the desired behavior. Now, when I
> > change z I also get a new draw from the random distribution. I thought
> > of trying to blocking the redraw by wrapping Dynamic around the
> > RandomReal, like this.
>
> > Dynamic[z+Dynamic@RandomReal[{0,Setting@Dynamic[a]}]]
>
> > But that doesn't work at all. It still redraws when I change z and the
> > addition no longer works in the desired way since the Dynamic
> > expression is not "really" a number but just a box.
>
> > I can solve the latter problem by wrapping a Setting in front of the
> > Dynamic
>
> > Dynamic[z + Setting@Dynamic[RandomReal[{0, Setting@Dynamic[a]}]]]
>
> > Now it adds properly but it still refreshes the random draw every time
> > I change z.
>
> > This doesn't work either and the expression is getting awfully
> > complicated
>
> > Dynamic[z +
> > Refresh[Setting@Dynamic[RandomReal[{0, Setting@Dynamic[a]}]],
> > TrackedSymbols -> {a}]]
>
> > And this doesn't work either
>
> > Dynamic[Setting@Dynamic[z] +
> > Setting@Dynamic[RandomReal[{0, Setting@Dynamic[a]}]]]
>
> > Can someone help!
>
> Yes. Many evaluation ordering issues with Dynamic can be solved using =
With[],
> including this one. Here's my code that does what you want...
>
> Dynamic[With[{draw = RandomReal[{0, a}]}, Dynamic[z + draw]]]
>
> Some important points here. Note that both Dynamics actually display. =
The
> outer Dynamic will obviously display the result of With[], and the result=
of
> With[] is another Dynamic[]. If I had hidden the inner Dynamic behind =
a
> semicolon or Setting, this would not have worked.
>
> So, in the front end, this is represented as two nested DynamicBox object=
s. The
> outer Dynamic will trigger anytime 'a' is changed, and will reevaluate it=
s
> contents entirely, including the inner Dynamic. The inner Dynamic will on=
ly
> change if 'z' has changed, and its reevaluation will never cascade into a
> reevaluation of the outer Dynamic.
>
> In summary, Setting[] won't help you with the kind of problems you're hav=
ing,
> but you'll find With[] very useful. In my Mathematica programs, I almo=
st never
> used With[] until Dynamic[] came along, at which point I found it an inva=
luable
> tool for controlling precisely how things will evaluate.
>
> Sincerely,
>
> John Fultz
> jfu... at wolfram.com
> User Interface Group
> Wolfram Research, Inc.
Thank you John for an extremely helpful answer. I thought I would
amplify your response by showing two pieces of successful code that
implement your idea.
using DynamicModule
DynamicModule[{a = 0.3, b = 0.04, years = 10, insureds = 5,
dist = WeibullDistribution, func = f},
Column[{Manipulator[Dynamic[a], {0.01, 3}],
Manipulator[Dynamic[b], {0.01, 3}],
SetterBar[Dynamic[years], Table[10^i, {i, 0, 2}]],
Slider[Dynamic[insureds],{1,20,1}],
SetterBar[
Dynamic[dist], {WeibullDistribution, GammaDistribution,
LogNormalDistribution}], SetterBar[Dynamic[func], {f, g}],
Dynamic[With[{draw =
RandomReal[
dist @@ {a, b}, {insureds,
years}](*change the draw if any of the symbols in this \
section change *)}, Dynamic[func[draw]]]]}]]
using Manipulate
Manipulate[
Dynamic[With[{draw =
RandomReal[
dist @@ {a, b}, {insureds,
years}](*change the draw if any of the symbols in this section
\
change *)}, Dynamic[func[draw]]]],
{{a, 0.3}, 0.01, 3},
{{b, 0.04}, 0.01, 3},
{{years, 10}, Table[10^i, {i, 0, 2}], ControlType -> SetterBar},
{{insureds, 5}, 1, 20, 1, ControlType -> SetterBar},
{{dist, WeibullDistribution}, {WeibullDistribution,
GammaDistribution, LogNormalDistribution},
ControlType -> SetterBar}, {{func, f}, {f, g}}]
When you change dist, a, b, insureds or years a new draw occurs
When you change func, no new draw occurs
This is precisely the behavior I want and it seems to be a pretty
clean way of going about it.
Suggestions: (1) Add examples something like this to the Advanced
Dynamic and/or Advanced Manipulate tutorials. (2) Clarify
documentation on Setting and DynamicSetting.