6

As part of my pipeline I need to perform eigendecomposition of a big matrix in the order of 6000x6000. The matrix is dense, so except if I simplify the problem (sot sure if possible) no sparse method can be used.

At the moment I play with toy data. Using the Eigen library for a 513x513 matrix I need ~6.5 seconds, while for a 2049x2049 matrix I need ~130 seconds, which sounds prohibitive since the increase is not linear. This was achieved with Eigen::SelfAdjointEigenSolver, while with other methods like Eigen::EigenSolver or Eigen::ComplexEigenSolver I didn't get notable improvement. The same happened when I tried Armadillo with arma::eig_sym even with the option "dc"` that is supposed to give a faster but approximate result. Armadillo has some methods thatreturn only the first X eigenvalues for speedup, but this is only for sparse methods. At the moment I can probably get away with the first 10-20 eigenvalues.

Is there a way or a library/method that can give me a notable speedup?

dim_tz
  • 1,451
  • 5
  • 20
  • 37
  • 1
    If you need only the few highest or smallest eigenvectors, then there are more efficient methods. – SpamBot Feb 23 '16 at 12:15
  • 1
    This is exactly what I mention, that this might be a good enough workaround. Which are these methods? Any pointer please? – dim_tz Feb 23 '16 at 18:38
  • 1
    Lapack provides such routines. Regarding your numbers, I obtained 7.5s only for a 2049x2049 matrix using `Eigen::SelfAdjointEigenSolver`, and 280s for a 6000x6000 matrix. Make sure you compiled with compiler optimizations ON. Of course, this is still prohibitive and better use a dedicated algorithm extracting only the first eigenvectors. – ggael Feb 24 '16 at 07:45

2 Answers2

5

Spectra is used to retrieve a few number of eigenvalues of a large matrix.

Sample code to calculate the largest and smallest 10 eigenvalues may look like:

#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include <MatOp/DenseGenMatProd.h>
#include <MatOp/DenseSymShiftSolve.h>
#include <SymEigsSolver.h>
#include <iostream>

using namespace Spectra;

int main()
{
    srand(0);
    // We are going to calculate the eigenvalues of M
    Eigen::MatrixXd A = Eigen::MatrixXd::Random(1000, 1000);
    Eigen::MatrixXd M = A.transpose() * A;

    // Matrix operation objects
    DenseGenMatProd<double> op_largest(M);
    DenseSymShiftSolve<double> op_smallest(M);

    // Construct solver object, requesting the largest 10 eigenvalues
    SymEigsSolver< double, LARGEST_MAGN, DenseGenMatProd<double> >
        eigs_largest(&op_largest, 10, 30);

    // Initialize and compute
    eigs_largest.init();
    eigs_largest.compute();

    std::cout << "Largest 10 Eigenvalues :\n" <<
        eigs_largest.eigenvalues() << std::endl;

    // Construct solver object, requesting the smallest 10 eigenvalues
    SymEigsShiftSolver< double, LARGEST_MAGN, DenseSymShiftSolve<double> >
        eigs_smallest(&op_smallest, 10, 30, 0.0);

    eigs_smallest.init();
    eigs_smallest.compute();
    std::cout << "Smallest 10 Eigenvalues :\n" <<
        eigs_smallest.eigenvalues() << std::endl;

    return 0;
}
yixuan
  • 774
  • 3
  • 6
2

I would recommend to try out Arpack-Eigen. I know from Octave/Matlab that it can compute the largest eigenvalue of a random 2049x2049 within a second, and the largest 10 within 5-20 seconds, eigs(rand(2049), 10). Now, its documentation help eigs points to ARPACK. Arpack-Eigen https://github.com/yixuan/arpack-eigen lets you request 10 eigenvalues from larger matrix like this: SymEigsSolver< double, LARGEST_ALGE, DenseGenMatProd<double> > eigs(&op, 10, 30);.

SpamBot
  • 1,438
  • 11
  • 28
  • 3
    ARPACK-Eigen is now superseded by [Spectra](https://github.com/yixuan/spectra). And the `ncv` parameter should be roughly two or three times the number of eigenvalues requested, so `eigs(&op, 10, 30)` is probably more appropriate. – yixuan Feb 24 '16 at 21:41
  • @yixuan Thanks for the correction, I edited my answer. – SpamBot Feb 25 '16 at 09:22