2016-02-22 21 views
5

Come parte della mia pipeline, ho bisogno di eseguire la eigendecomposizione di una grande matrice nell'ordine di 6000x6000. La matrice è densa, quindi a meno che non semplifichi il problema (se possibile sicuro, non è possibile utilizzare alcun metodo sparse).C++ Grande velocità di composizione elettronica

Al momento gioco con dati giocattolo. Usando la libreria Eigen per una matrice 513x513 ho bisogno di ~ 6.5 secondi, mentre per una matrice 2049x2049 ho bisogno di ~ 130 secondi, il che suona proibitivo poiché l'aumento non è lineare. Ciò è stato ottenuto con Eigen::SelfAdjointEigenSolver, mentre con altri metodi come Eigen::EigenSolver o Eigen::ComplexEigenSolver non ho ottenuto miglioramenti notevoli. Lo stesso è accaduto quando ho provato Armadillo con arma::eig_sym anche con l'opzione "dc" che dovrebbe dare un risultato più veloce ma approssimativo. Armadillo ha alcuni metodi per ritirare solo i primi X autovalori per l'accelerazione, ma questo è solo per i metodi sparsi. Al momento posso probabilmente scappare con i primi 10-20 autovalori.

C'è un modo o una libreria/metodo che può darmi una notevole accelerazione?

+0

Se avete bisogno solo i pochi autovettori più alti o più piccoli, poi ci sono i metodi più efficaci. – SpamBot

+0

Questo è esattamente quello che ho detto, che potrebbe essere una buona soluzione. Quali sono questi metodi? Qualche puntatore per favore? –

+0

Lapack fornisce tali routine. Per quanto riguarda i tuoi numeri, ho ottenuto 7,5 solo per una matrice 2049x2049 usando 'Eigen :: SelfAdjointEigenSolver' e 280 per una matrice 6000x6000. Assicurati di aver compilato le ottimizzazioni del compilatore ON. Naturalmente, questo è ancora proibitivo e meglio usare un algoritmo dedicato che estrae solo i primi autovettori. – ggael

risposta

0

Consiglierei di provare Arpack-Eigen. So da Octave/Matlab che può calcolare l'autovalore più grande di un 2049x2049 casuale in un secondo e il 10 più grande entro 5-20 secondi, eigs(rand(2049), 10). Ora, la sua documentazione help eigs punta ad ARPACK. Arpack-Eigen https://github.com/yixuan/arpack-eigen consente di richiedere 10 autovalori da una matrice più grande come questa: SymEigsSolver< double, LARGEST_ALGE, DenseGenMatProd<double> > eigs(&op, 10, 30);.

+1

ARPACK-Eigen è ora sostituito da [Spectra] (https://github.com/yixuan/spectra). E il parametro 'ncv' dovrebbe essere all'incirca due o tre volte il numero di autovalori richiesti, quindi' eigs (& op, 10, 30) 'è probabilmente più appropriato. – yixuan

+0

@yixuan Grazie per la correzione, ho modificato la mia risposta. – SpamBot

4

Spectra viene utilizzato per recuperare un numero limitato di autovalori di una matrice di grandi dimensioni.

codice di esempio per calcolare le più grandi e più piccoli 10 autovalori possono apparire come:

#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; 
}