Sto cercando di calcolare pochi (5-500) autovettori corrispondenti ai più piccoli autovalori di grandi matrici quadrate simmetriche (fino a 30000x30000) con meno dello 0,1% dei valori diversi da zero.
Attualmente sto usando scipy.sparse.linalg.eigsh in modalità shift-invert (sigma = 0.0), che ho capito attraverso vari post sull'argomento è la soluzione preferita. Tuttavia, nella maggior parte dei casi sono necessari fino a 1 ora per risolvere il problema. D'altra parte la funzione è molto veloce, se chiedo gli autovalori più grandi (sotto secondi sul mio sistema), come previsto dalla documentazione.
Dato che ho più familiarità con Matlab dal lavoro, ho provato a risolvere il problema in Octave, il che mi ha dato lo stesso risultato usando gli eigs (sigma = 0) in pochi secondi (sotto 10s). Dal momento che voglio fare una scansione dei parametri dell'algoritmo incluso il calcolo degli autovettori, quel tipo di guadagno di tempo sarebbe fantastico avere anche in Python.
Per prima cosa ho modificato i parametri (in particolare la tolleranza), ma ciò non è cambiato molto nei tempi.
Sto usando Anaconda su Windows, ma ho provato a cambiare il LAPACK / BLAS usato da Scipy (che era un grande dolore) da Mkl (predefinito Anaconda) a OpenBlas (usato da Octave secondo la documentazione), ma non sono riuscito a vedere un cambiamento in prestazione.
Non sono riuscito a capire se c'era qualcosa da cambiare sull'ARPACK usato (e come)?
Ho caricato una testcase per il codice seguente nella seguente cartella dropbox: https://www.dropbox.com/sh/l6aa6izufzyzqr3/AABqij95hZOvRpnnjRaETQmka?dl=0
In Python
import numpy as np
from scipy.sparse import csr_matrix, csc_matrix, linalg, load_npz
M = load_npz('M.npz')
evals, evecs = linalg.eigsh(M,k=6,sigma=0.0)
In Octave:
M=dlmread('M.txt');
M=spconvert(M);
[evecs,evals] = eigs(M,6,0);
Qualsiasi aiuto è valutato!
Alcune opzioni aggiuntive che ho provato in base ai commenti e ai suggerimenti:
Octave:
eigs(M,6,0)
e eigs(M,6,'sm')
dammi lo stesso risultato:
[1.8725e-05 1.0189e-05 7.5622e-06 7.5420e-07 -1.2239e-18 -2.5674e-16]
mentre eigs(M,6,'sa',struct('tol',2))
converge a
[1.0423 2.7604 6.1548 11.1310 18.0207 25.3933]
molto più veloce, ma solo se i valori di tolleranza sono superiori a 2, altrimenti non converge affatto e i valori sono fortemente diversi.
Python:
eigsh(M,k=6,which='SA')
ed eigsh(M,k=6,which='SM')
entrambi non convergono (errore ARPACK su nessuna convergenza raggiunta). eigsh(M,k=6,sigma=0.0)
Fornisce solo alcuni autovalori (dopo quasi un'ora), che sono diversi dall'ottava per i più piccoli (viene trovato anche 1 piccolo valore aggiuntivo):
[3.82923317e-17 3.32269886e-16 2.78039665e-10 7.54202273e-07 7.56251500e-06 1.01893934e-05]
Se la tolleranza è abbastanza alta ottengo anche risultati da eigsh(M,k=6,which='SA',tol='1')
, che si avvicinano agli altri valori ottenuti
[4.28732218e-14 7.54194948e-07 7.56220703e-06 1.01889544e-05, 1.87247350e-05 2.02652719e-05]
di nuovo con un diverso numero di piccoli autovalori. Il tempo di calcolo è ancora di quasi 30 minuti. Mentre i diversi valori molto piccoli potrebbero essere comprensibili, poiché potrebbero rappresentare multipli di 0, la diversa molteplicità mi confonde.
Inoltre, sembrano esserci alcune differenze fondamentali in SciPy e Octave, che non riesco ancora a capire.