MathGroup Archive 2009

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

Search the Archive

Re: Why is recursion so slow in Mathematica?

  • To: mathgroup at smc.vnet.net
  • Subject: [mg100569] Re: Why is recursion so slow in Mathematica?
  • From: Daniel <janzon at gmail.com>
  • Date: Mon, 8 Jun 2009 02:07:14 -0400 (EDT)
  • References: <h0d6s8$spq$1@smc.vnet.net> <h0fvo1$rfd$1@smc.vnet.net>

Leonid,

Thanks a lot for your reply. It seems like Wagner's book (Power
Programming in Mathematica) is out of print, too bad! But your book
seems to be interesting as well. I will definately read it the whole
thing; the section on why you think Mathematica is so good was
interesting. I guess I need to learn about reap/sow as well...

I do understand that Mathematica is what it is and is not supposed to
compete with low-level languages on speed.

All the best,
Daniel

On 7 Juni, 11:02, lsh... at gmail.com wrote:
> Daniel,
>
> Let me tell you straight away that you won't get efficiency of OCaml
> in Mathematica,
> the latter really being a CAS, research and prototyping  tool, but not
> an efficiency-oriented production language.
>
> Regarding your question, the short answer is that recursion is slow
> because lists are implemented as arrays in Mathematica. When you
> pattern-match, the whole array <tail> is copied every time. This
> explains both the slowdown - the time becomes effectively quadratic
> (assuming that the complexity of array copying is linear), and the
> (stack) memory use explosion.
>
> So, IMO, indeed Mathematica is unfortunately less suited for the
> straightforward recursive solutions like yours. The closest thing you
> can probably do to stay in the recursive mindset is to use linked
> lists. Here is an implementation that does just that:
>
> Clear[myselectAux];
> myselectAux[{}, predicate_] = {};
> myselectAux[{head_, tail_List}, predicate_] :=
>   If[predicate[head], {head, myselectAux[tail, predicate]},
>    myselectAux[tail, predicate]];
>
> Clear[toLinkedList];
> toLinkedList[x_List] := Fold[{#2, #1} &, {}, Reverse[x]];
>
> Clear[mySelectLL];
> mySelectLL[x_List, predicate_] :=
>   Flatten@myselectAux[toLinkedList[x], predicate];
>
> You can find more info on linked lists in Mathematica in the book of
> David Wagner,
> in the notes by Daniel Lichtblau (see Wolfram library archive, should
> be named
> something like "efficient data structures in Mathematica"), and also
> in my book
> (http://www.mathprogramming-intro.org/book/node525.html).
>
> For example:
>
> In[1] = test = RandomInteger[{1, 10}, 10]
>
> Out[1] = {6, 10, 1, 9, 4, 6, 1, 9, 10, 4}
>
> In[2] = toLinkedList@test
>
> Out[2] = {6, {10, {1, {9, {4, {6, {1, {9, {10, {4, {}}}}}}}}}}}
>
> In[3] = mySelectLL[test, # > 5 &]
>
> Out[3] = {6, 10, 9, 6, 9, 10}
>
> Now, the benchmarks: I use yours, on my 5 years old 1.8 GHz P IV, and
> I get:
>
> In[4] =
> data = Table[Random[], {20000}];
> Block[{$RecursionLimit = Infinity},
>  Timing[data2 = mySelectLL[data, # > 0.5 &];]]
>
> Out[4] = {0.2, Null}
>
> Now, this is not the most efficient implementation. David Wagner in
> his excellent book
> discussed in great detail this sort of problems with the mergesort
> algorithm as an archetypal example. I believe that you can squeeze
> another factor of 2-5 by further optimizing the implementation
> (keeping it recursive) with several performance-tuning techniques
> available in Mathematica.
>
> By the way, I tested the above code with larger lists and it seems to
> continue be linear complexity  up to 100 000 elements, but the kernel
> (v.6) just crashes after that - this
> behavior I can not explain, since the memory usage seems quite decent.
>
> So, to summarize my opinion:  if you prefer to stay in a recursive
> mode, you *can* use recursion in Mathematica rather efficiently by
> switching to linked lists (and this will require some extra work but
> not so much of it). This may be enough to move you from the domain of
> toy problems to that of reasonably complex prototypes.  But don't
> expect efficiency of the highly optimized production language with a
> native-code compiler (or even byte code interpreter) from a rewrite
> system such as Mathematica. Also, I'd say that other programming
> styles such as structural operations (APL - like) will bring you
> closer to efficiency of Ocaml etc. since then you can leverage the
> highly-optimized vectorized operations built in Mathematica.
>
> Hope this helps.
>
> Regards,
> Leonid
>
> On Jun 6, 12:46 am, Daniel <jan... at gmail.com> wrote:
>
> > This post is about functional programming in Mathematica versus other
> > functional languages such as OCaml, SML or Haskell. At least a naive
> > use of functional constructs in Mathematica is horrendously slow. Am I
> > doing something wrong? Or isn't Mathematica really suitable for
> > functional programming beyond toy programs? Couldn't the Wolfram team
> > make a more efficient implementation for recursion, as other
> > functional languages has done? (Instead of the naive C-like behavior
> > for recursively defined functions.)
>
> > As grounds for my question/argument, I wrote my own version of select,
> > as below
>
> > myselect[{}, predicate_] = {}
> > myselect[{head_, tail___}, predicate_] := If[predicate[head],
> >   Join[{head}, myselect[{tail}, predicate]],
> >   myselect[{tail}, predicate]
> >   ]
>
> > Then I tried this function on a 20.000 element vector with machine
> > size floats:
>
> > data = Table[Random[], {20000}];
> > $RecursionLimit = 100000;
> > Timing[data2 = myselect[data, # > 0.5 &];]
>
> > The result is {7.05644, Null}, and hundreds of MB of system memory are
> > allocated. On 1.7 GHZ dual core Intel machine with 1 GB of RAM. For
> > 20.000 floats! It's just a megabyte!
>
> > The following OCaml program executes in apparently no-time. It is not
> > compiled and does the same thing as the above Mathematica code. After
> > increasing the list by a factor of ten to 200.000 elements, it still
> > executes in a blink. (But with 2.000.000 elements my OCaml interpreter
> > says Stack overflow.)
>
> > let rec randlist n = if n=0 then [] else Random.float(1.0) :: randl=
is=
> t
> > (n-1);;
>
> > let rec myselect = function
> >     [],predicate -> []
> >   |  x::xs,predicate -> if predicate(x) then x::myselect(xs,predica=
te=
> )
> > else myselect(xs,predicate);;
>
> > let mypred x = x>0.5;;
>
> > let l=randlist(20000);;
> > let l2=myselect(l,mypred);;  (* lightning-fast compared to Mathemat=
ic=
> a
> > *)



  • Prev by Date: Re: Re: Why is recursion so slow in Mathematica?
  • Next by Date: Re: Why is recursion so slow in Mathematica?
  • Previous by thread: Re: Why is recursion so slow in Mathematica?
  • Next by thread: Re: Why is recursion so slow in Mathematica?