RE: Re: Compile

*To*: mathgroup at smc.vnet.net*Subject*: [mg45446] RE: [mg45430] Re: Compile*From*: "Wolf, Hartmut" <Hartmut.Wolf at t-systems.com>*Date*: Wed, 7 Jan 2004 17:31:10 -0500 (EST)*Sender*: owner-wri-mathgroup at wolfram.com

>-----Original Message----- >From: Maxim [mailto:dontsendhere@.] To: mathgroup at smc.vnet.net >Sent: Wednesday, January 07, 2004 7:10 AM >To: mathgroup at smc.vnet.net >Subject: [mg45446] [mg45430] Re: Compile > > > > >Fred Simons wrote: > >> Many people already commented on Maxim Retin's strange example: >> >> subs = x->x^2 >> Plot[ x /. subs, {x, 0,1}, Compiled->...] >> >> produces different plots depending on the value used in the option Compiled. >> >> I think that the value of an example like this one is that it may help a >> user of Mathematica in getting a better understanding of the way Mathematica >> works. Nobody, not even Maxim himself, will ever try to make a plot of x^2 >> in this way. >> >> Here are some observations that I made about this example. >> >> In a command like Plot[f[x], {x, 0, 1}] the symbol x is a local variable. >> The way Mathematica deals with these local variables depends on the command >> in which it is used. I will shortly discuss three examples: Table, >> NIntegrate and Plot.. >> >> The output of the following command >> >> y:=x; >> Table[Information[x];Print[y]; x, {x, 1, 3}] >> >> shows that in the function Table in each step a value is assigned to the >> local variable x; no immediate substitution in the first argument takes >> place. >> >> The function NIntegrate behaves differently: >> >> y:=x; >> NIntegrate[Information[x];Print[y]; x, {x, 0,1}, Compiled\[Rule]True] >> >> Both with Compiled->True and Compiled->False, no matter how many steps are >> used in the integration procedure, the first argument is called only once >> and no value has been assigned to the local variable x. (Mathematica 4 >> behaves differently). Using Trace in the next command, we see how >> Mathematica proceeds. It evaluates the first argument symbolically, taking >> into account global variables that may occur in the first argument, and uses >> the outcome in the numerical integration. This is Maxim's example: >> >> subs = x -> x^2; >> NIntegrate[ x /. subs, {x, 0, 1}, Compiled -> True] >> >> Compiled->False yields the same result. >> >> Now we turn to Plot: >> >> y:=x; >> Plot[Information[x];Print[y]; x, {x, 0,1}, PlotPoints->3, Compiled->True] >> >> With the option Compiled->True, the values for the local variable are >> substituted into the (compiled) first argument of Plot, no assignment to the >> local variable takes place. >> >> y:=x; >> Plot[Information[x];Print[y]; x, {x, 0,1}, PlotPoints->3, Compiled->False] >> >> Hence with Compiled->False, the values are assigned to the local variable >> and no immediate substitution into the (uncompiled) first argument occurs. >> >> Now the behaviour of Maxim's example(s) is easy to predict: >> >> subs=x\[Rule]x^2; >> Plot[x/.subs, {x, 0, 1}, Compiled\[Rule]True] >> >> The values of x are substituted (no assignment to x) into the (compiled) >> first argument. That (compiled) argument contains an unevaluated variable >> subs. Hence evaluation of subs results in x->x^2 and the plot is a straight >> line. >> >> subs=x\[Rule]x^2; >> Plot[x/.subs, {x, 0, 1}, Compiled\[Rule]False] >> >> In this situation, values are assigned to the local variable x and therefore >> evaluation of the first argument results in x^2 for any of these values. The >> plot is a parabola. >> >> subs=x\[Rule]x^2; >> f[x_]:= x /. subs; >> Table[f[x], {x, 1, 5}] >> Table[f[t], {t, 1, 5}] >> >> In the last command, assignments are done to the local variable t and >> therefore subs remains symbolically. >> >> My final remark is that the first argument in Maxim's example can be >> compiled and that the result is a compiled function in which a global >> variable subs occurs. The above observations and conclusions remain valid >> also for a compiled first argument. I cannot find any reason why Mathematica >> would not compile the first argument when Compiled->True. But I cannot show >> that Mathematica indeed did compile. >> >> Fred Simons >> Eindhoven University of Technology > >I'm afraid that still doesn't explain the difference between > >Module[ > {y := If[NumericQ[x], 1, 0]}, > Plot[x + y, {x, 0, 1}, Compiled -> True] >] >(*plots x*) > >and > >Module[ > {y := x + If[NumericQ[x], 1, 0]}, > Plot[y, {x, 0, 1}, Compiled -> True] >] >(*plots x+1*) > >Maxim Rytin >m.r at prontomail.com > > Maxim, afar from all reason, let's dig in further. I interprete your sentence "...that still doesn't explain the difference...", that you accept Fred's explanations for the outcome of the first result. (Then you come up with a new case.) Taking the risk of becoming bored, let me repeat Fred's arguments. I leave out Module, it's unessential here: the easy case (Compiled -> False) In[21]:= y := (Print[x]; If[NumericQ[x], 1, 0]); Trace[Plot[x + y, {x, 0, 1}, Compiled -> False, AspectRatio -> Automatic, PlotPoints -> 3], x | y, TraceInternal -> True] // InputForm >From In[21]:= 5.*^-7 >From In[21]:= 0.486804 >From In[21]:= 1. = here goes the graphics, correct, we might say = Out[21]//InputForm= {{{HoldForm[x], HoldForm[5.*^-7]}, {HoldForm[y], HoldForm[Print[x]; If[NumericQ[x], 1, 0]], {{HoldForm[x], HoldForm[5.*^-7]}}, {{{HoldForm[x], HoldForm[5.*^-7]}}}}}, {{HoldForm[x], HoldForm[0.4868038988749894]}, {HoldForm[y], HoldForm[Print[x]; If[NumericQ[x], 1, 0]], {{HoldForm[x], HoldForm[ 0.4868038988749894]}}, {{{HoldForm[x], HoldForm[0.4868038988749894]}}}}}, {{HoldForm[x], HoldForm[0.9999995]}, {HoldForm[y], HoldForm[Print[x]; If[NumericQ[x], 1, 0]], {{HoldForm[x], HoldForm[0.9999995]}}, {{{HoldForm[x], HoldForm[0.9999995]}}}}}} In the Trace we see how the symbol x (localized in Plot) gets successive values, which finally come to y (whithin the plotting environment) resulting in NumericQ[x] as True. However when compiled, we get something different: In[22]:= y := (Print[x]; If[NumericQ[x], 1, 0]); Trace[Plot[x + y, {x, 0, 1}, Compiled -> True, AspectRatio -> Automatic, PlotPoints -> 3], x | y, TraceInternal -> True] // InputForm >From In[22]:= x >From In[22]:= x >From In[22]:= x = here goes the graphics, wrong, we tend to say = Out[22]//InputForm= {{{HoldForm[y], HoldForm[Print[x]; If[NumericQ[x], 1, 0]]}}, {{HoldForm[y], HoldForm[Print[x]; If[NumericQ[x], 1, 0]]}}, {{HoldForm[y], HoldForm[Print[x]; If[NumericQ[x], 1, 0]]}}} When y gets evaluated, x is printed but has no value, hence NumericQ[x] becomes False, hence the "wrong" plot. When we look at the Trace we see, that x no longer exists (except within y of course), it never gets a value. Obviously it has been "optimized away", and it appears as if x (within the plot expression) had been literally replaced with the numerical Plot values. The factual machinery behind that is hidden, and at the full Trace we don't see any trace of any compiled expression, which in some way must have been present. After all, what is a "compiled expression" at all? It must contain the binding of the plot variable. But that's hidden. Your new example shows up other "interesting things" (to those who are interested of course). In[27]:= y := (Print[x]; x + If[NumericQ[x], 1, 0]); Trace[Plot[y, {x, 0, 1}, Compiled -> True, AspectRatio -> Automatic, PlotPoints -> 3], x | y, TraceInternal -> True] // InputForm >From In[27]:= x >From In[27]:= x >From In[27]:= 5.*^-7 >From In[27]:= 0.486804 >From In[27]:= 1. = here goes the graphics, correct, we might say = Out[27]//InputForm= {{{HoldForm[y], HoldForm[Print[x]; x + If[NumericQ[x], 1, 0]], {HoldForm[x]}, HoldForm[x]}}, {HoldForm[y], HoldForm[Print[x]; x + If[NumericQ[x], 1, 0]], {HoldForm[x]}, HoldForm[x]}, {{HoldForm[x], HoldForm[5.*^-7]}, {{HoldForm[y], HoldForm[Print[x]; x + If[NumericQ[x], 1, 0]], {{HoldForm[x], HoldForm[5.*^-7]}}, {{HoldForm[x], HoldForm[5.*^-7]}, {{{HoldForm[x], HoldForm[5.*^-7]}}}}}}}, {{HoldForm[x], HoldForm[0.4868038988749894]}, {{HoldForm[y], HoldForm[Print[x]; x + If[NumericQ[x], 1, 0]], {{HoldForm[x], HoldForm[0.4868038988749894]}}, {{HoldForm[x], HoldForm[0.4868038988749894]}, {{{HoldForm[x], HoldForm[ 0.4868038988749894]}}}}}}}, {{HoldForm[x], HoldForm[0.9999995]}, {{HoldForm[y], HoldForm[Print[x]; x + If[NumericQ[x], 1, 0]], {{HoldForm[x], HoldForm[0.9999995]}}, {{HoldForm[x], HoldForm[0.9999995]}, {{{HoldForm[x], HoldForm[0.9999995]}}}}}}}} Although compiled, now the variable x is present, and gets the plot values. It is evaluated within y, is numeric then, and we get the result we expect. What is new, are obviously two (additional) evaluations of y when x has no value, before doing the plot. What comes to my phantasy is a compilator in desperate search of the variable x to become bound, detecting it when an exterior variable becomes evaluated, and now binding it (as in contrary of above) in a function call. (y however is not evaluated within the compiled expression.) In fact, when looking at the full Trace we detect a CompiledFunction. It is the same as we get from directly compiling (check that!): In[30]:= (cc = Compile[{{x, _Real}}, y]) // InputForm Out[30]//InputForm= CompiledFunction[{_Real}, {{3, 0, 0}, {3, 0, 1}}, {0, 0, 2, 0, 0}, {{1, 4}, {21, Function[{x}, y], 3, 0, 0, 3, 0, 1}, {2}}, Function[{x}, y]] When we try it in vitro, however, it doesn't work: In[33]:= cc[.5] >From In[33]:= x >From In[33]:= CompiledFunction::"cfse": "Compiled expression \!\(x\) should be a \ \!\(\"machine-size real number\"\)." >From In[33]:= CompiledFunction::"cfex": "External evaluation error at instruction \!\(2\); \ proceeding with uncompiled evaluation." >From In[33]:= x Out[33]= x Clearly x is not set from the argument, hence the error and its consequences. If we do that, setting x, by ourselves it works: In[37]:= Block[{x = .5}, cc[999.]] >From In[37]:= 0.5 Out[37]= 1.5 The printed value is that of x (of Block) the calculated value comes right. The argument is effectively ignored (well, it is checked to be present and real). We can plot cc, the compiled function In[32]:= Plot[cc[x], {x, 0, 1}, Compiled -> False, AspectRatio -> Automatic, PlotPoints -> 3] >From In[32]:= 5.*^-7 >From In[32]:= 0.486804 >From In[32]:= 1. Out[32]= \[SkeletonIndicator]Graphics\[SkeletonIndicator] giving the "right" graphics. Obviously the plotting variable has been introduced as x into the environment of the plot expression. In distinction to From In[27] the "trial evaluations" are missing, here (and I need not say why Compiled -> False was taken). As you will have guessed now, In[39]:= Plot[cc[999.], {x, 0, 1}, Compiled -> False, AspectRatio -> Automatic, PlotPoints -> 3] gives the same plot. But there is no mystery with that! By the way -- if you desperately need it -- you can, in a similar way, compile the plot expression x + y in the first example: In[41]:= Clear[x] In[42]:= y := (Print[x]; If[NumericQ[x], 1, 0]) In[44]:= (cc1 = Compile[{{x, _Real}}, x + y]) // InputForm Out[44]//InputForm= CompiledFunction[{_Real}, {{3, 0, 0}, {3, 0, 2}}, {0, 0, 3, 0, 0}, {{1, 4}, {21, Function[{x}, y], 3, 0, 0, 3, 0, 1}, {25, 0, 1, 2}, {2}}, Function[{x}, x + y]] In[45]:= cc1[.5] >From In[45]:= x Out[45]= 0.5 In[46]:= Block[{x = .5}, cc1[x]] >From In[46]:= 0.5 Out[46]= 1.5 In[47]:= Plot[cc1[x], {x, 0, 1}, Compiled -> False, AspectRatio -> Automatic, PlotPoints -> 3] >From In[47]:= 5.*^-7 >From In[47]:= 0.486804 >From In[47]:= 1. Out[47]= \[SkeletonIndicator]Graphics\[SkeletonIndicator] And everthing is fine and consistent and compiled, except compiled for Plot, that is. Now you have to supply the correct argument (the plot variable x), as x is explicit part of the compiled expression. Of course. But why should Plot now becompiled? If you do, you are back at the old problem, i.e. variable x not supplied in the environment of the plot expression. Now my guess is -- and I leave it up to you to check this out -- that if you replace Plot[ expression , {x, xmin, xmax}, Compiled -> trueorfalse] with Plot[ Block[{x = xx}, expression] ,{xx, xmin, xmax}, Complied -> trueorfalse] you'll get something satisfying for all expressions and for all cases of the Compiled option. -- Hartmut Wolf