Estou tentando calcular alguns (5-500) autovetores correspondentes aos menores autovalores de matrizes esparsas quadradas simétricas grandes (até 30000x30000) com menos de 0,1% dos valores diferentes de zero.
Atualmente, estou usando scipy.sparse.linalg.eigsh no modo shift-invert (sigma = 0,0), que eu descobri através de várias postagens sobre o tópico como a solução preferida. No entanto, leva até 1 hora para resolver o problema na maioria dos casos. Por outro lado, a função é muito rápida, se eu pedir os maiores valores próprios (sub-segundos no meu sistema), o que era esperado na documentação.
Como eu estou mais familiarizado com o Matlab do trabalho, tentei resolver o problema no Octave, o que me deu o mesmo resultado usando eigs (sigma = 0) em apenas alguns segundos (sub 10s). Como eu quero fazer uma varredura de parâmetro do algoritmo, incluindo o cálculo do vetor próprio, esse tipo de ganho de tempo também seria ótimo em python.
Mudei primeiro os parâmetros (especialmente a tolerância), mas isso não mudou muito nas escalas de tempo.
Estou usando o Anaconda no Windows, mas tentei alternar o LAPACK / BLAS usado pelo scipy (que era uma grande dor) de mkl (padrão Anaconda) para OpenBlas (usado pelo Octave de acordo com a documentação), mas não consegui ver uma alteração no desempenho.
Não consegui descobrir se havia algo a mudar sobre o ARPACK usado (e como)?
Fiz upload de um caso de teste para o código abaixo na seguinte pasta dropbox: https://www.dropbox.com/sh/l6aa6izufzyzqr3/AABqij95hZOvRpnnjRaETQmka?dl=0
Em 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)
Na oitava:
M=dlmread('M.txt');
M=spconvert(M);
[evecs,evals] = eigs(M,6,0);
Qualquer ajuda é apreciada!
Tentei algumas opções adicionais com base nos comentários e sugestões:
Oitava:
eigs(M,6,0)
e eigs(M,6,'sm')
me dê o mesmo resultado:
[1.8725e-05 1.0189e-05 7.5622e-06 7.5420e-07 -1.2239e-18 -2.5674e-16]
enquanto eigs(M,6,'sa',struct('tol',2))
converge para
[1.0423 2.7604 6.1548 11.1310 18.0207 25.3933]
muito mais rápido, mas somente se os valores de tolerância estiverem acima de 2, caso contrário, eles não convergirão e os valores serão fortemente diferentes.
Python:
eigsh(M,k=6,which='SA')
e eigsh(M,k=6,which='SM')
ambos não convergem (erro ARPACK em nenhuma convergência alcançada). eigsh(M,k=6,sigma=0.0)
Fornece apenas alguns autovalores (após quase uma hora), que são diferentes da oitava para os menores (até 1 pequeno valor adicional é encontrado):
[3.82923317e-17 3.32269886e-16 2.78039665e-10 7.54202273e-07 7.56251500e-06 1.01893934e-05]
Se a tolerância é alta o suficiente, também obtenho resultados eigsh(M,k=6,which='SA',tol='1')
, que se aproximam dos outros valores obtidos
[4.28732218e-14 7.54194948e-07 7.56220703e-06 1.01889544e-05, 1.87247350e-05 2.02652719e-05]
novamente com um número diferente de pequenos autovalores. O tempo de computação ainda é quase 30min. Embora os diferentes valores muito pequenos possam ser compreensíveis, uma vez que podem representar múltiplos de 0, a multiplicidade diferente me confunde.
Além disso, parece haver algumas diferenças fundamentais em SciPy e Octave, que ainda não consigo descobrir.