MathGroup Archive 2004

[Date Index] [Thread Index] [Author Index]

Search the Archive

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


  • Prev by Date: Re: multiple derivatives?
  • Next by Date: Re: Palette rememberance
  • Previous by thread: Re: Re: Compile
  • Next by thread: RE: RE: Re: Compile