Re: Mathematica 20x slower than Java at arithmetic/special
- To: mathgroup at smc.vnet.net
- Subject: [mg115943] Re: Mathematica 20x slower than Java at arithmetic/special
- From: Oliver Ruebenkoenig <ruebenko at wolfram.com>
- Date: Wed, 26 Jan 2011 05:30:52 -0500 (EST)
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 Global`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) (*SetDelayed[f[x_],a^2*x]*) 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 Global`f2 f2[x_] := 2*x Then 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 2 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 Clear[g] 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 Global`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 Global`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 2 Out[20]= {With[{a = a}, g[u_, i_] := a u[[i]]], {a, Sqrt[2]}, 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 sufficient. Another scenario where the above techniques come in handy is for conditional evaluation. 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? Oliver