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.