Skip to main content

performance tuning - How can I improve the speed of eigenvalue decompositions for large matrices?


I often need to compute the eigenvalues of large matrices, and I invariably resort to MATLAB for these, simply because it is much faster. I'd like to change that, so that I can work entirely inside my notebook.


Here's a plot comparing the timings between the two for eigenvalue decompositions for matrices of varying sizes (left). The y-axis shows the time in seconds. As you can see, there's about a factor 3 difference between the two (right).


enter image description here enter image description here


Here's a sample code in Mathematica to generate timings:


timings = With[{x = RandomReal[NormalDistribution[], {#, #}]},
Eigenvalues[x]; // Timing // First] & /@ Range[500,5000,500]

and its equivalent in MATLAB:



s = 500:500:5000;
t = zeros(numel(s),1);
for i = 1:numel(s)
x=randn(s(i));
t1=tic;eig(x);t(i)=toc(t1);
end

I do not think that Mathematica's algorithms are inefficient, as the fastest algorithms for eigenvalue decompositions (in the general case, not exploiting symmetry and such) are $\mathcal{O}(N^{2.376})$ and the timings both MATLAB's and Mathematica's implementations have the same correct slope on a log-log plot.


I suspected unpacking in the background during the call to Eigenvalues and turning On["Packing"] confirms this. However, I don't think this alone could be the cause for a 3 fold speed reduction. I'm not expecting the timings to be exact either, as I understand that arrays and matrices are baked into the core of one and not the other, which can lead to performance differences.


However, I'm interested in knowing if




  1. there are reasons other than the simplified one I gave above for the difference in timings and

  2. there ways in which I can improve the speeds or at least, reduce the difference by some amount. Or is this something that one has to accept as a fact of life?



Answer



Mathematica is every bit as fast as Matlab for these types of computations. The source of the discrepancy arises from the fact that Timing keeps track of total time used by all processors when Mathematica distributes the computation across them. We can examine a fair comparison using AbsoluteTiming, which is more comparable to Matlab's tic and toc.


Consider the following computed on my Macbook Pro:


t1 = First[Timing[Eigenvalues[RandomReal[{0, 1},
{1000, 1000}]]]];
t2 = First[AbsoluteTiming[Eigenvalues[RandomReal[{0, 1},

{1000, 1000}]]]];
{t1, t2}

{5.16576, 1.329784}


Again, the only difference is the use of Timing versus AbsoluteTiming. You can watch the wall clock to convince yourself that the faster time is accurate. Let's try this with with the OP's code:


timingsGood = With[{x = RandomReal[NormalDistribution[], {#, #}]}, 
Eigenvalues[x]; // AbsoluteTiming // First] & /@
Range[500, 5000, 500];
timingsBad = With[{x = RandomReal[NormalDistribution[], {#, #}]},
Eigenvalues[x]; // Timing // First] & /@

Range[500, 5000, 500];
Column[{timingsGood, timingsBad, timingsBad/timingsGood}]

enter image description here


Note that the (incorrect) Timing result is always consistently about three times longer than the (correct) AbsoluteTiming result, which accounts just about exactly for the OP's observations.


I ran a suite of numerical comparisons that I created several years ago. Here are my results:


enter image description here


There are differences. Matlab is notably faster at singular value, Cholesky, and QR factorizations. Mathematica is slightly faster at sparse eigenvalue computations. They seem to be generally quite close to one another. There are a few other types of computations as well. Symbolically, Mathematica is way faster than Matlab's symbolic toolbox.


Comments

Popular posts from this blog

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...