From: Andreas on
I start with two 2 dimensional lists. The have equal depths, but may
or may not have equal lengths. Possible data looks like this:

list1 = RandomReal[{0, 1}, {1500, 3}];
list2 = RandomReal[ExponentialDistribution[2], {1000, 3}];

The following produces the results I need, but takes longer to run
than I'd like:

Rest[FoldList[Times, 1, Transpose[(t = #; 1 + Inner[Times, t, # - 1,
Plus] & /@ list1) & /@
list2]]]

Any suggestions rewriting this so I can make it run faster?

Thanks.


From: Szabolcs Horvát on
On 2009.09.03. 11:30, Andreas wrote:
> Rest[FoldList[Times, 1, Transpose[(t = #; 1 + Inner[Times, t, # - 1,
> Plus]& /@ list1)& /@
> list2]]]


First I'd like to say that it's often much easier (at least for me!) to
come up with a solution if you explain what you want to do in plain
English instead of just providing a program to speed up. Now I have to
convert the program to a form that my brain can handle, then convert it
back to program code... Why not avoid the first step if possible? ;-)

So, a few things we might notice about this implementation:

1. Inner is used with Times and Plus, so why not replace it with Dot?
2. That nested function (with the assignment to the global t) looks
discomforting. I'm not sure how Mathematica's compiler can handle that
(Map auto-compiles the function when working on large lists). So let's
try to get rid of that also.

These might not be the main reson for the slowdown. I am just
guessing---predicting Mathematica's performance can be difficult.

So, rewrite the inner part of the program first. Instead of Inner we
can use Dot, instead of the nested function we can use Outer:

list1 = RandomReal[{0, 1}, {1500, 3}];
list2 = RandomReal[ExponentialDistribution[2], {1000, 3}];

In[3]:= Timing[
x = Transpose[(t = #;
1 + Inner[Times, t, # - 1, Plus] & /@ list1) & /@ list2];]
Out[3]= {21.656, Null}

In[4]:= Timing[y = Outer[1 + #2.(#1 - 1) &, list1, list2, 1];]
Out[4]= {10.625, Null}

That's a 2x speedup.

Are the results equivalent?

In[5]:= x == y
Out[5]= False

We got False, but that's only because of numerical errors (the
operations are performed in a different order):

In[6]:= Max(a)Abs[x - y]
Out[6]= 8.88178*10^-16

So the result is correct.

What else can we do to speed things up? Notice that it is not necessary
to subtract/add 1 in the inner function 1 + #2.(#1 - 1) &. This can be
done on the input and output instead. So we can get rid of custom
functions and use the built-in Dot only:

In[7]:= Timing[z = 1 + Outer[Dot, list1 - 1, list2, 1];]
Out[7]= {1.25, Null}

In[8]:= y == z
Out[8]= True

Now that's a 17x speedup compared to the implementation we started with.
Trying to simplify things will often pay off because it will be easier
to see how to rewrite the program to use built-in functions and packed
arrays as much as possible. It's also much easier to see what the
program does.

The FoldList part takes an additional 3 seconds on my machine. I can't
help with speeding that up unfortunately.

I hope this helps,
Szabolcs

From: Daniel Lichtblau on
Andreas wrote:
> I start with two 2 dimensional lists. The have equal depths, but may
> or may not have equal lengths. Possible data looks like this:
>
> list1 = RandomReal[{0, 1}, {1500, 3}];
> list2 = RandomReal[ExponentialDistribution[2], {1000, 3}];
>
> The following produces the results I need, but takes longer to run
> than I'd like:
>
> Rest[FoldList[Times, 1, Transpose[(t = #; 1 + Inner[Times, t, # - 1,
> Plus] & /@ list1) & /@
> list2]]]
>
> Any suggestions rewriting this so I can make it run faster?
>
> Thanks.

Could do:

Rest[FoldList[Times, 1, (list1-1).Transpose[(list2)]+1]]

One bottleneck is that you will run into software arithmetic because
numbers become too small for machine double representation. If you don't
mind having them clipped, I think the code below might do what you want.

foldTimesC = Compile[{{mat,_Real,2}}, Module[
{current=ConstantArray[1.,Length[mat[[1]]]]},
Table[current = current*mat[[j]], {j,Length[mat]}]]]

foldTimesC[(list1-1).Transpose[(list2)]+1];

Daniel Lichtblau
Wolfram Research

From: Ray Koopman on
Rest(a)FoldList[Times,1,1+(list1-1).Transpose(a)list2]

On Sep 3, 2:30 am, Andreas <aa...(a)ix.netcom.com> wrote:
> I start with two 2 dimensional lists. The have equal depths, but may
> or may not have equal lengths. Possible data looks like this:
>
> list1 = RandomReal[{0, 1}, {1500, 3}];
> list2 = RandomReal[ExponentialDistribution[2], {1000, 3}];
>
> The following produces the results I need, but takes longer to run
> than I'd like:
>
> Rest[FoldList[Times, 1, Transpose[(t = #; 1 + Inner[Times, t, # - 1,
> Plus] & /@ list1) & /@ list2]]]
>
> Any suggestions rewriting this so I can make it run faster?
>
> Thanks.

From: pfalloon on
On Sep 3, 7:30 pm, Andreas <aa...(a)ix.netcom.com> wrote:
> I start with two 2 dimensional lists. The have equal depths, but may
> or may not have equal lengths. Possible data looks like this:
>
> list1 = RandomReal[{0, 1}, {1500, 3}];
> list2 = RandomReal[ExponentialDistribution[2], {1000, 3}];
>
> The following produces the results I need, but takes longer to run
> than I'd like:
>
> Rest[FoldList[Times, 1, Transpose[(t = #; 1 + Inner[Times, t, # - 1,
> Plus] & /@ list1) & /@
> list2]]]
>
> Any suggestions rewriting this so I can make it run faster?
>
> Thanks.

I think the main reason for the slowness is that the Inner function is
much less efficient for large numerical matrices than the standard Dot
function. When you re-express the function using Dot, it is much
faster:

(* original definition *)
f1[list1_,list2_] := Module[{t}, Rest[FoldList[Times, 1, Transpose[(t
= #; 1 + Inner[Times, t, # - 1, Plus] & /@ list1) & /@ list2]]]]

(* first attempt: incorporate the addition & subtraction into the
Inner function *)
f2[list1_,list2_] := Inner[Times[#1-1,#2] &, list1, Transpose(a)list2,
Plus[1, ##] &] // FoldList[Times, 1, #] & // Rest

(* best attempt: apply the addition & subtraction to the matrices as a
whole, so we can use the more-efficient Dot function *)
f3[list1_,list2_] := Rest(a)FoldList[Times, 1, 1+(list1-1).Transpose
[list2]]


Here is an example to show the speed-up:

In[62]:= (* sample matricies *)
list1 = RandomReal[{0, 1}, {1000, 3}];
list2 = RandomReal[ExponentialDistribution[2], {1500, 3}];

In[64]:= (* timings *)
res1=f1[list1, list2]; // AbsoluteTiming
res2=f2[list1, list2]; // AbsoluteTiming
res3=f3[list1, list2]; // AbsoluteTiming

Out[64]= {14.0311602,Null}
Out[65]= {9.7811874,Null}
Out[66]= {1.7187390,Null}

However, in testing this I noticed that the function appears to be
highly unstable numerically -- so you may want to investigate that
further:

(* test correctness of results: appears to be numerically unstable! *)
Max /@ Abs[res1 - res2]
Max /@ Abs[res1 - res3]


Hope this helps!

Cheers,
Peter.

 |  Next  |  Last
Pages: 1 2
Prev: plot question
Next: Faster alternative to AppendTo? --