【问题标题】:Using ARPACK solving eigenvalueproblem, but getting inconsistent results with Matlab使用 ARPACK 解决特征值问题,但使用 Matlab 得到的结果不一致
【发布时间】:2014-12-18 16:04:48
【问题描述】:

我是 ARPACK 新手,我下载了如下脚本

import time
import numpy as np
from scipy.linalg import eigh
from scipy.sparse.linalg import eigs
np.set_printoptions(suppress=True)

n=30
rstart=0
rend=n

A=np.zeros(shape=(n,n))

# first row
if rstart == 0:
    A[0, :2] = [2, -1]
    rstart += 1
# last row
if rend == n:
    A[n-1, -2:] = [-1, 2]
    rend -= 1
# other rows
for i in range(rstart, rend):
    A[i, i-1:i+2] = [-1, 2, -1]

A[0,8]=30

start_time = time.time()

evals_large, evecs_large = eigs(A, 10, sigma=3.6766133, which='LM')
print evals_large

end_time=time.time()-start_time
print(" Elapsed time: %12f seconds " % end_time)

它解决了一个非常简单的特征值问题(矩阵A不是对称的,我将A[0,8]设置为30)。根据ARPACK结果,最接近3.6766133(设置中的sigma=3.6766133)的3个特征值为

[ 3.68402411+0.j  3.82005897+0.j  3.51120293+0.j]

然后我去MATLAB,解决同样的特征值问题,结果是

4.144524409923138 + 0.000000000000000i 
3.642801014184622 + 0.497479798520641i
3.642801014184622 - 0.497479798520641i
2.372392770347609 + 0.762183281789166i
2.372392770347609 - 0.762183281789166i
3.979221766266502 + 0.000000000000000i
3.918541441830947 + 0.000000000000000i
3.820058967057387 + 0.000000000000000i 
3.684024113506185 + 0.000000000000000i
3.511202932803536 + 0.000000000000000i
3.307439963195127 + 0.000000000000000i
3.080265978640102 + 0.000000000000000i
2.832849552917550 + 0.000000000000000i
2.565972630556613 + 0.000000000000000i
2.283744793210587 + 0.000000000000000i
1.996972474451519 + 0.000000000000000i
0.927737801889518 + 0.670252740725955i
0.927737801889518 - 0.670252740725955i
1.714561796881689 + 0.000000000000000i
-0.015193770830045 + 0.264703483268519i
-0.015193770830045 - 0.264703483268519i
1.438919271663752 + 0.000000000000000i
0.019951101383019 + 0.000000000000000i
0.080534338862828 + 0.000000000000000i 
0.181591307101504 + 0.000000000000000i
0.318955140475174 + 0.000000000000000i
0.488231021129767 + 0.000000000000000i
0.688030188040126 + 0.000000000000000i
1.171318650526539 + 0.000000000000000i
0.917612528393044 + 0.000000000000000i

显然,第二种模式3.642801014184622 + 0.497479798520641i更接近sigma=3.6766133,但是ARPACK没有挑出来。

可能是什么问题?你能帮我解决这个问题吗?非常感谢。

【问题讨论】:

    标签: python matlab scipy eigenvalue arpack


    【解决方案1】:

    如果使用eigs函数,NumPy和Matlab的结果是一致的:

    >> format long
    >> A = diag(-ones(n-1,1),-1) + diag(2*ones(n,1)) + diag(-ones(n-1,1),+1);A(1,9)=30;
    >> eigs(A,3,3.6766133)'
    ans =
       3.684024113506185   3.820058967057386   3.511202932803534
    

    至于为什么没有选择真正最接近的特征值,我认为这与收敛到实矩阵的复杂特征值和选择实数移位有关。 我不知道 ARPACK 如何计算它的迭代,但我记得有人告诉我,具有实数 σ 的实数 A 默认情况下不能收敛到复共轭对,因为它们的绝对值比率为 1(对于逆幂迭代)。 由于 ARPACK 将在第 8th 和 9th 迭代中生成复杂的特征值(+/- 排序是随机的),我猜它们是我的一些解决方法已经忘记或从未知道:

    >> ev = eigs(A,9,3.6766133);ev(8:9)
    ans =
      3.642801014184617 - 0.497479798520639i
      3.642801014184617 + 0.497479798520639i
    

    除了猜测移位的复杂部分或只是获取额外的特征值直到共轭对落入 ARPACK 方法的收敛球之外,我不确定它们是否是解决此问题的一般方法。

    【讨论】:

      【解决方案2】:

      首先介绍一下 MATLAB 函数:

      • eig 返回的特征值是 NOT sorted。在[V,D] = eig(A) 中,我们只保证V 的列是D(i,i) 中特征值的对应右特征向量。另一方面,svd 返回按降序排序的奇异值。

      • d = eigs(A,k) 返回k 最大幅度 特征值。然而,它适用于大型稀疏矩阵,通常不能替代:

        d = eig(full(A));
        d = sort(d, 'descend');
        d = d(1:k);
        

        eigs 基于ARPACK,而eig 使用LAPACK 例程)。

      • There is no natural ordering 的复数。约定是sort 函数sorts complex elements first by magnitude(即abs(x)),然后在幅度相等时按[-pi,pi] 间隔(即angle(x))上的相位角。


      MATLAB

      考虑到这一点,考虑以下 MATLAB 代码:

      % create the same banded matrix you're using
      n = 30;
      A = spdiags(ones(n,1)*[-1,2,-1], [-1 0 1], n, n);
      A(1,9) = 30;
      %A = full(A);
      
      % k eigenvalues closest to sigma
      k = 10; sigma = 3.6766133;
      D = eigs(A, k, sigma);
      
      % lets check they are indeed sorted by distance to sigma
      dist = abs(D-sigma);
      issorted(dist)
      

      我明白了:

      >> D
      D =
        3.684024113506185 + 0.000000000000000i
        3.820058967057386 + 0.000000000000000i
        3.511202932803535 + 0.000000000000000i
        3.918541441830945 + 0.000000000000000i
        3.979221766266508 + 0.000000000000000i
        3.307439963195125 + 0.000000000000000i
        4.144524409923134 + 0.000000000000000i
        3.642801014184618 + 0.497479798520640i
        3.642801014184618 - 0.497479798520640i
        3.080265978640096 + 0.000000000000000i
      
      >> dist
      dist =
         0.007410813506185
         0.143445667057386
         0.165410367196465
         0.241928141830945
         0.302608466266508
         0.369173336804875
         0.467911109923134
         0.498627536953383
         0.498627536953383
         0.596347321359904
      

      您可以尝试使用密集的eig 获得类似的结果:

      % closest k eigenvalues to sigma
      ev = eig(full(A));
      [~,idx] = sort(ev - sigma);
      ev = ev(idx(1:k))
      
      % compare against eigs
      norm(D - ev)
      

      差异小到可以接受(接近机器 epsilon):

      >> norm(ev-D)
      ans =
           1.257079405021441e-14
      

      Python

      在 Python 中也是如此:

      import numpy as np
      from scipy.sparse import spdiags
      from scipy.sparse.linalg import eigs
      
      # create banded matrix
      n = 30
      A = spdiags((np.ones((n,1))*[-1,2,-1]).T, [-1,0,1], n, n).todense()
      A[0,8] = 30
      
      # EIGS: k closest eigenvalues to sigma
      k = 10
      sigma = 3.6766133
      D = eigs(A, k, sigma=sigma, which='LM', return_eigenvectors=False)
      D = D[::-1]
      for x in D:
          print '{:.16f}'.format(x)
      
      # EIG
      ev,_ = np.linalg.eig(A)
      idx = np.argsort(np.abs(ev - sigma))
      ev = ev[idx[:k]]
      for x in ev:
          print '{:.16f}'.format(x)
      

      结果相似:

      # EIGS
      3.6840241135061853+0.0000000000000000j
      3.8200589670573866+0.0000000000000000j
      3.5112029328035343+0.0000000000000000j
      3.9185414418309441+0.0000000000000000j
      3.9792217662665070+0.0000000000000000j
      3.3074399631951246+0.0000000000000000j
      4.1445244099231351+0.0000000000000000j
      3.6428010141846170+0.4974797985206380j
      3.6428010141846170-0.4974797985206380j
      3.0802659786400950+0.0000000000000000j
      
      # EIG
      3.6840241135061880+0.0000000000000000j
      3.8200589670573906+0.0000000000000000j
      3.5112029328035339+0.0000000000000000j
      3.9185414418309468+0.0000000000000000j
      3.9792217662665008+0.0000000000000000j
      3.3074399631951201+0.0000000000000000j
      4.1445244099231271+0.0000000000000000j
      3.6428010141846201+0.4974797985206384j
      3.6428010141846201-0.4974797985206384j
      3.0802659786400906+0.0000000000000000j
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-10-02
        • 2020-11-19
        • 2014-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多