MathGroup Archive 2011

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

Search the Archive

Re: Mathematica 20x slower than Java at arithmetic/special

On Mon, 24 Jan 2011, Leo Alekseyev wrote:

> Vivek, Oliver -- thanks for your input!  My knowledge in using
> Compile[] is somewhat lacking (mostly, due to the fact that I was
> never able to get it to work well for me).  In particular, I tried
> using Compile[] much in the same way that Vivek has suggested, but I
> neglected to use Evaluate[], which leads to a compiled function taking
> substantially longer.  Is there a quick explanation for why Evaluate[]
> (or, in Oliver's example, a construct like
> With[{code=code},Compile[{...},code]] necessary?..

Let me try to do that.

Say I have

In[1]:= a = Sqrt[2]

Out[1]= Sqrt[2]

In[2]:= f[x_] := a^2*x

In[3]:= ?f

f[x_] := a^2*x

So there is a global symbol a and f both with values. We can call the function 
f with a parameter

In[4]:= f[1]

Out[4]= 2

Let us look at how this is evaluated

In[5]:= f[1] // Trace

                 2                          2   1
Out[5]= {f[1], a  1, {{a, Sqrt[2]}, Sqrt[2] , 2 , 2}, 2 1, 2}

We see the call f[1], then on the right hand side x is replaced by the 
parameter 1, the evaluator now looks up what a is and computes a^2, does the 
multiplication and returns the result.

This means that every time you call f with any parameter the lookup of a and 
the computation of a^a needs to be done. This can be expensive. Now, there are 
several ways to deal with this. Depending on the circumstances.

Let us look at the Evaluate first.

The above definition of f can be written as such (FullForm)


Set*Delayed* (:=) has

In[6]:= Attributes[SetDelayed]

Out[6]= {HoldAll, Protected, SequenceHold}

Of interest are the Hold_XY_ attributes. This means the when you specify f, the 
right hand side is *not* evaluated. (In contrast to Set (=)).

So we can force the evaluation of the right hand side with

In[7]:= SetDelayed[f2[x_], Evaluate[a^2*x]]

In[8]:= ?f2

f2[x_] := 2*x


In[9]:= f2[1] // Trace

Out[9]= {f2[1], 2 1, 2}

is much cheaper to compute.

You can also write the above as:
f2[x_] := Evaluate[a^2*x]

OK, now a different approach.

In[10]:= ?With

So With does *replacement* not evaluation. This is different but also valuable.

Say we have

In[11]:= g[u_, i_] := a^2*u[[i]]

In[12]:= u = {1, 2, 3};

In[13]:= g[u, 2] // Trace

Out[13]= {{u, {1, 2, 3}}, g[{1, 2, 3}, 2], a  {1, 2, 3}[[2]],

                            2   1
>    {{a, Sqrt[2]}, Sqrt[2] , 2 , 2}, {{1, 2, 3}[[2]], 2}, 2 2, 4}

If we now apply the above Evaluate technique we get

In[15]:= g[u_, i_] := Evaluate[a^2*u[[i]]]

Part::pspec: Part specification i
      is neither an integer nor a list of integers.

We get a message but what is worse is

In[16]:= ?g

g[u_, i_] := 2*{1, 2, 3}[[i]]

in the function g u has been replaced by the global u.

This can be circumvented with

In[17]:= Clear[g]; With[{a = a}, g[u_, i_] := a^2*u[[i]]]

In[18]:= ?g

g[u$_, i$_] := Sqrt[2]^2*u$[[i$]]

Now, a has been replaced but not evaluated and u is not replaced.

In[20]:= Clear[g]; With[{a = a}, g[u_, i_] := a^2*u[[i]]] // Trace

Out[20]= {With[{a = a}, g[u_, i_] := a  u[[i]]], {a, Sqrt[2]},

>    g[u$_, i$_] := Sqrt[2]  u$[[i$]], Null}

I think of With as a method to inject code into functions that have some kind 
of Hold attribute.

So, strictly speaking in the code I send the Evaluate would have been 

Another scenario where the above techniques come in handy is for conditional 

In[21]:= Attributes[If]

Out[21]= {HoldRest, Protected}

Then you have the option to inject code into the HoldRest part of If

I hope this was useful?


  • Prev by Date: Re: Simple n-tuple problem - with no simple solution
  • Next by Date: Re: Do I need MathLink to run finite-difference fast enough for
  • Previous by thread: Re: LinearRecurrence syntax
  • Next by thread: About Table