Spero che la risposta alla domanda nel titolo sia che sto facendo qualcosa di stupido!Perché MATLAB/Octave pulisce il pavimento con C++ in Problemi autovalore?
Ecco il problema. Voglio calcolare tutti gli autovalori e gli autovettori di una matrice simmetrica reale. Ho implementato il codice in MATLAB (in realtà, lo eseguo usando Octave) e C++, usando lo GNU Scientific Library. Sto fornendo il mio codice completo qui sotto per entrambe le implementazioni.
Per quanto posso capire, GSL dotato di una propria implementazione delle API BLAS, (qui di seguito rimando a questo come GSLCBLAS) e di utilizzare questa libreria compilo usando:
g++ -O3 -lgsl -lgslcblas
GSL suggerisce here utilizzare una libreria BLAS alternativa, ad esempio la libreria auto-ottimizzante ATLAS, per prestazioni migliorate. Sono in esecuzione Ubuntu 12.04 e ho installato i pacchetti ATLAS dal Ubuntu repository. In questo caso, compilo utilizzando:
esperimentig++ -O3 -lgsl -lcblas -latlas -lm
Per tutti e tre i casi, sono eseguiti con matrici generate in modo casuale di dimensioni 100 a 1000 in passi di 100. Per ciascuna dimensione, effettuo 10 eigendecompositions con differenti matrici e media il tempo impiegato. I risultati sono questi:
La differenza di prestazioni è ridicolo. Per una matrice di dimensione 1000, Octave esegue la decomposizione in meno di un secondo; GSLCBLAS e ATLAS impiegano circa 25 secondi.
Ho il sospetto che possa utilizzare la libreria ATLAS in modo errato. Eventuali spiegazioni sono ben accette; Grazie in anticipo.
Alcune note sul codice:
Nell'implementazione C++, non c'è bisogno di fare la matrice simmetrica , perché the function only uses the lower triangular part of it.
In Octave, la riga
triu(A) + triu(A, 1)'
impone che la matrice sia simmetrica.Se si desidera compilare il codice C++ sulla propria macchina Linux, è inoltre necessario aggiungere la flag
-lrt
, a causa della funzioneclock_gettime
.Purtroppo non penso che le uscite
clock_gettime
su altre piattaforme. Valuta la possibilità di cambiarlo ingettimeofday
.
codice ottava
K = 10;
fileID = fopen('octave_out.txt','w');
for N = 100:100:1000
AverageTime = 0.0;
for k = 1:K
A = randn(N, N);
A = triu(A) + triu(A, 1)';
tic;
eig(A);
AverageTime = AverageTime + toc/K;
end
disp([num2str(N), " ", num2str(AverageTime), "\n"]);
fprintf(fileID, '%d %f\n', N, AverageTime);
end
fclose(fileID);
codice C++
#include <iostream>
#include <fstream>
#include <time.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_eigen.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
int main()
{
const int K = 10;
gsl_rng * RandomNumberGenerator = gsl_rng_alloc(gsl_rng_default);
gsl_rng_set(RandomNumberGenerator, 0);
std::ofstream OutputFile("atlas.txt", std::ios::trunc);
for (int N = 100; N <= 1000; N += 100)
{
gsl_matrix* A = gsl_matrix_alloc(N, N);
gsl_eigen_symmv_workspace* EigendecompositionWorkspace = gsl_eigen_symmv_alloc(N);
gsl_vector* Eigenvalues = gsl_vector_alloc(N);
gsl_matrix* Eigenvectors = gsl_matrix_alloc(N, N);
double AverageTime = 0.0;
for (int k = 0; k < K; k++)
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
gsl_matrix_set(A, i, j, gsl_ran_gaussian(RandomNumberGenerator, 1.0));
}
}
timespec start, end;
clock_gettime(CLOCK_MONOTONIC_RAW, &start);
gsl_eigen_symmv(A, Eigenvalues, Eigenvectors, EigendecompositionWorkspace);
clock_gettime(CLOCK_MONOTONIC_RAW, &end);
double TimeElapsed = (double) ((1e9*end.tv_sec + end.tv_nsec) - (1e9*start.tv_sec + start.tv_nsec))/1.0e9;
AverageTime += TimeElapsed/K;
std::cout << "N = " << N << ", k = " << k << ", Time = " << TimeElapsed << std::endl;
}
OutputFile << N << " " << AverageTime << std::endl;
gsl_matrix_free(A);
gsl_eigen_symmv_free(EigendecompositionWorkspace);
gsl_vector_free(Eigenvalues);
gsl_matrix_free(Eigenvectors);
}
return 0;
}
Qual è l'output di 'ldd $ (which octave)'? Vedi riferimenti a OpenBLAS o ATLAS? Quale utilizzo della CPU mostra 'top' per l'ottava o la versione C++ quando vengono eseguiti? – damienfrancois
non hai chiesto all'ottava di restituire gli autovettori che rendono il problema più semplice. – Memming