map instead of loops ?

Hi, people say that for-next loops are the worst way to apply repeated operations (why?). Assume i have the list

L:=[1,3,5,6];

and the command line that does some stuff in it :

for i from 1 to nops(L)-1 do
 sqrt(5*L[i]-L[i+1]);
 end do;

Whats a better way to do this? I guess map is useful here, but i cant get it to work.

 

 

 

 

 

 

 

 

 

 

seq

 The command seq is more efficient than a for loop.  Try this:

restart;
L:=[1,3,5,6];
seq( sqrt(5*L[i]- L[i+1]),i=1..nops(L)-1);
 

Hope this helps.

J. Tarr

jpmay's picture

Not this example

map and seq can be a lot faster that doing a for-do loop, but not in this case:

> L:=[seq](2*i+1, i=10000..100000):
> time(seq( sqrt(5*L[i]- L[i+1]),i=1..nops(L)-1) );
                                     2.316
> restart;
> L:=[seq](2*i+1, i=10000..100000):
> t:=time(): for i from 1 to nops(L)-1 do          
>    sqrt(5*L[i]-L[i+1]):                            
> end do: time() - t;
                                       1.880

seq and map are best in the case when you are creating a list as output. So, the following is extremely slow (I stopped it at 400 seconds)

> restart;
> L:=[seq](2*i+1, i=10000..100000):
> M:=[];
> t:=time(): for i from 1 to nops(L)-1 do
> M := [op(M), sqrt(5*L[i]-L[i+1])]:                            
> end do: time() - t;

But that is mostly due to the bad list construction technique, not the for loop. The following isn't too bad:

> restart;
> L:=[seq](2*i+1, i=10000..100000):
> M := Array(1..(100000-10000), 0);
> t:=time(): for i from 1 to nops(L)-1 do   
>    M[i]:=sqrt(5*L[i]-L[i+1]):                
> end do: M := convert(M, list): time() - t;
                                     2.792

John

alec's picture

zip

time(zip((x,y)->5*x+y,L[1..-2],L[2..-1]));

                                0.140

Alec

jpmay's picture

with sqrt


> L:=[seq](2*i+1, i=10000..100000):
> time(zip((x,y)->sqrt(5*x+y),L[1..-2],L[2..-1]));
                                     2.632
> restart
> L:=[seq](2*i+1, i=10000..100000):
> time(seq( sqrt(5*L[i]- L[i+1]),i=1..nops(L)-1) );
                                     1.676

(timings from a different machine than my earlier post)

John

I will keep those examples in

I will keep those examples in mind, thanks.

@alec: yes, another good and

@alec: yes, another good and compact solution, altough you left out the square root operation, so runtimes aren't comparable. 

alec's picture

map[evalhf,inline]

Yes, zip is usually not very efficient in Maple, and sqrt, certainly, adds some time. Another problem with time comparision is that the answers are different - seq, map, and zip construct a list, or a sequence, and the loop doesn't.

By the way, without the square root, one of the fastest ways is

time(5*L[1..-2]+L[2..-1]);
                                  0.

Something similar can be achieved with square roots, too:

L:=Array(L,datatype=float[8]):
L1:=ArrayTools:-Alias(L,[1..90000]):
L2:=ArrayTools:-Alias(L,1,[1..90000]):
time(map[evalhf,inline](sqrt,5*L1+L2));

                                  0.

Alec

jpmay's picture

Pineapples and Bananas

That a a great example of how to do the numerical computation very fast, but I should point out that it is not really a fair comparison.
For the exact operation this is about the same speed:

L:=[seq](2*i+1, i=10000..100000):
L:=Array(L):
L1:=ArrayTools:-Alias(L,[1..90000]):
L2:=ArrayTools:-Alias(L,1,[1..90000]):
time(map[inline](sqrt,5*L1+L2));
                                    2.708

John

alec's picture

datatype=float[8] and evalhf

datatype=float[8] and evalhf option in map make the difference. Why is it not fair?

Alec

jpmay's picture

  Different Computation

 It is doing a completely different computation:

sqrt(5*L[47]-L[48]): lprint(%);
3*8930^(1/2)

evalf(sqrt(5*L[47]-L[48]));
                                  283.4960317

John

enhancements were made to zip

As stated in ?updates,Maple12,efficiency:

Direct hardware-float callbacks are recognized for certain routines. These can bypass much of the overhead of ordinary interpreted function evaluation resulting in speed similar to that of compiled code.

Which are these "certain routines"? Apparently 'sqrt' is not one of those.

acer's picture

2-parameter routines

That paragraph is in the section covering the zip() function. It's not surprising that sqrt() may not be one of the affected routines. The zip() routine "zips" an action across two parameters, while sqrt() takes the square root of a single parameter.

About the only way I can see to even make zip(sqrt,A,B) valid is for B to be merely an option such as 'symbolic'. But that wouldn't be particularly apt here and would likely not help much in the hardware datatype rtable case, which is also central (but left out, above) to that quoted paragraph covering zip's enhancements..

acer

May be not surprising

and may be that you are right, but it is not obvious and could be otherwise. You have to make an interpretation of the  meaning  of this paragraph: "certain routines" may be binary unary or whatever routines. It would be very simple for the writer of this help page to  be explicit. And I do not find any clear reference to this issue in ?zip either.

 

acer's picture

zip's help page

The first line of the help-page ?zip says, " zip together two lists, matrices, or vectors." 

The first line of zip's help-page's Description says, "The function zip applies the binary function f to the components of two data sets..."

How could it be more clear?

acer

Yes

This paragraph can be written much more clearly.

If that were the case, in that paragraph it should say "this and such binary routines", ie listing them, it is not much work, instead of something so vague as "certain routines". That paragraph does not exclude other interpretations.

Robert Israel's picture

inline?

Where is "inline" documented as an option for map?  The help page only has evalhf and inplace.  Or did you mean inplace? 

alec's picture

inplace

Yes, I meant inplace. In these examples it doesn't seem to make much of a difference though.

Perhaps, the sqrt code for integers could be improved?

Alec

Well i see there are some

Well i see there are some effective ways to accelerate things, although i don't like the idea to specify low level things like datatype=float[8] or similar. Maple should do this for me (probably not possible). Also, thanks for poining out that forNext loops are not generally bad in terms of processing time. Moreover, you can easily specify stepsize->more flexibility.

Of course seq, zip and map allow a more compact notation, as there is no embracing do..end do term.

 

 

 

 

       

acer's picture

original data was exact

The original data was exact, so it would not be appropriate if Maple were automatically to convert the data to floating-point and then give a corresponding floating-point result (which is what those super fast methods above do).

acer

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
}