Estoy tratando de calcular pocos (5-500) vectores propios correspondientes a los valores propios más pequeños de matrices dispersas cuadradas simétricas grandes (hasta 30000x30000) con menos del 0.1% de los valores que no son cero.
Actualmente estoy usando scipy.sparse.linalg.eigsh en modo shift-invert (sigma = 0.0), que descubrí a través de varias publicaciones sobre el tema es la solución preferida. Sin embargo, lleva hasta 1 hora resolver el problema en la mayoría de los casos. Por otro lado, la función es muy rápida, si solicito los valores propios más grandes (segundos secundarios en mi sistema), que se esperaba de la documentación.
Como estoy más familiarizado con Matlab desde el trabajo, intenté resolver el problema en Octave, que me dio el mismo resultado usando eigs (sigma = 0) en solo unos segundos (sub 10s). Dado que quiero hacer un barrido de parámetros del algoritmo, incluido el cálculo del vector propio, ese tipo de ganancia de tiempo también sería genial tener en Python.
Primero cambié los parámetros (especialmente la tolerancia), pero eso no cambió mucho en las escalas de tiempo.
Estoy usando Anaconda en Windows, pero intenté cambiar el LAPACK / BLAS utilizado por scipy (que fue un gran dolor) de mkl (Anaconda predeterminado) a OpenBlas (utilizado por Octave según la documentación), pero no pude ver un cambio en actuación.
No pude averiguar si había algo que cambiar sobre el ARPACK usado (y cómo).
Subí un caso de prueba para el siguiente código a la siguiente carpeta de dropbox: https://www.dropbox.com/sh/l6aa6izufzyzqr3/AABqij95hZOvRpnnjRaETQmka?dl=0
En 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)
En octava:
M=dlmread('M.txt');
M=spconvert(M);
[evecs,evals] = eigs(M,6,0);
Cualquier ayuda es solicitada!
Algunas opciones adicionales que probé en función de los comentarios y sugerencias:
Octave:
eigs(M,6,0)
y eigs(M,6,'sm')
dame el mismo resultado:
[1.8725e-05 1.0189e-05 7.5622e-06 7.5420e-07 -1.2239e-18 -2.5674e-16]
mientras eigs(M,6,'sa',struct('tol',2))
converge a
[1.0423 2.7604 6.1548 11.1310 18.0207 25.3933]
mucho más rápido, pero solo si los valores de tolerancia son superiores a 2, de lo contrario no converge en absoluto y los valores son muy diferentes.
Python:
eigsh(M,k=6,which='SA')
y eigsh(M,k=6,which='SM')
ambos no convergen (error ARPACK al no alcanzarse la convergencia). Solo eigsh(M,k=6,sigma=0.0)
da algunos valores propios (después de casi una hora), que son diferentes de octava para los más pequeños (incluso se encuentra 1 valor pequeño adicional):
[3.82923317e-17 3.32269886e-16 2.78039665e-10 7.54202273e-07 7.56251500e-06 1.01893934e-05]
Si la tolerancia es lo suficientemente alta, también obtengo resultados eigsh(M,k=6,which='SA',tol='1')
, que se acercan a los otros valores obtenidos
[4.28732218e-14 7.54194948e-07 7.56220703e-06 1.01889544e-05, 1.87247350e-05 2.02652719e-05]
de nuevo con un número diferente de pequeños valores propios. El tiempo de cálculo aún es de casi 30 minutos. Si bien los diferentes valores muy pequeños pueden ser comprensibles, ya que pueden representar múltiplos de 0, la multiplicidad diferente me desconcierta.
Además, parece haber algunas diferencias fundamentales en SciPy y Octave, que todavía no puedo entender.