我需要找到我使用 Python 和 SciPy 的内置稀疏特征值求解器的哈密顿量(精确对角化)的最小特征值。然而,我注意到,对于我的小型系统(只有 40k x 40k 矩阵),该程序需要数小时,甚至数天。我开始怀疑出事了。
我注意到的一件事是我的矩阵应该有一个零特征值。这会对特征值求解器造成严重破坏吗?如果是这样,有什么方法可以解决这个问题?
我需要找到我使用 Python 和 SciPy 的内置稀疏特征值求解器的哈密顿量(精确对角化)的最小特征值。然而,我注意到,对于我的小型系统(只有 40k x 40k 矩阵),该程序需要数小时,甚至数天。我开始怀疑出事了。
我注意到的一件事是我的矩阵应该有一个零特征值。这会对特征值求解器造成严重破坏吗?如果是这样,有什么方法可以解决这个问题?
SciPy教程明确指出
请注意,ARPACK 通常更擅长寻找极值特征值:即具有较大幅度的特征值。特别是,使用
which = 'SM'可能会导致缓慢的执行时间和/或异常结果。更好的方法是使用移位反转模式。
并继续描述。基本上,如果是最小的量级特征值, 然后 是最大的特征值. (使用相同的技巧,您可以获得最接近给定的特征值通过查看最大的.) 因此,要计算三个最小的幅度特征值,您可以改为使用
eigenval, eigenvec = eigsh(A, 3, sigma=0, which='LM')
如果你已经知道具有零特征值,因此不可逆(并且您知道下一个最接近的位置),您可以改为使用非零移位,例如,sigma=0.01将矩阵从奇异矩阵移开。如果sigma足够小,那仍然应该让你最接近零。
(另外,正如我在评论中所指出的,请确保您安装了适当的优化 BLAS,例如 OpenBLAS ——对于稀疏特征值,SciPy 调用 ARPACK(用 Fortran 编写),这反过来又大量使用了 BLAS。)
编辑:如果它是你所追求的最小代数特征值,你可以使用这个巧妙的技巧:如果你有一个估计的最大特征值(例如,通过使用 计算它which='LM'),您可以使用它来将所有特征值转换为负值——这样最小的代数特征值也是最大幅度的。然后简单地which='LM'使用并向后移动。
虽然可以使用 ARPACK 和通过 SciPy 包装器的一些方便技巧在合理的时间内获得稀疏 40k x 40k 矩阵的最小特征值,正如这里提到的,但问题最多可以扩展为.
对于任何较大的特征值问题,我几乎总是推荐SLEPc,它也有一个 Python 包装器(可能不如 C 版本自然),并且在许多情况下调用 SciPy 例程的并行版本。