scipy.sparse.linalg.eigs和numpy / scipy.eig

时间:2016-10-14 19:05:06

标签: python scipy sparse-matrix eigenvalue

上下文:

我的目标是创建一个Python3程序来对大小为N的向量V进行差分运算。我这样做了,测试它的基本操作并且它可以工作(区分,渐变......)。

我试着用这个基础编写更复杂的方程式(Navier-Stokes,Orr-Sommerfeld,......),我试图通过计算这些方程的特征值来验证我的工作。

由于这些特征值完全出乎意料,我简化了我的问题,我目前正在尝试仅针对微分矩阵计算特征值(见下文)。但结果似乎错了......

先谢谢你的帮助,因为我找不到解决问题的方法......

DM的定义:

我使用Chebyshev谱方法来操作向量的区分。 我使用以下Chebyshev包(从Matlab翻译成Python): http://dip.sun.ac.za/%7Eweideman/research/differ.html

该软件包允许我创建一个微分矩阵DM,通过以下方式获得:

nodes, DM = chebyshev.chebdiff(N, maximal_order)

为了获得第1,第2,第3 ......顺序区分,我写了例如:

dVdx1 = np.dot(DM[0,:,:], V)
d2Vdx2 = np.dot(DM[1,:,:], V)
d3Vdx3 = np.dot(DM[2,:,:], V)

我测试了它并且它有效。 我根据差异化过程构建了不同的运营商。 我试图通过找到它们的特征值来验证它们。它没有顺利,所以我现在只是尝试DM。 我无法找到DM的正确特征值。

我尝试过不同的功能:

numpy.linalg.eigvals(DM)
scipy.linalg.eig(DM)
scipy.sparse.linalg.eigs(DM)
sympy.solve( (DM-x*np.eye).det(), x) [for snall size only]

为什么我使用scipy.sparse.LinearOperator:

我不想直接使用矩阵DM,因此我将其包含在一个运行差异化的函数中(参见下面的代码):

dVdx1 = derivative(V)

我这样做的原因来自全球项目本身。 这对于更复杂的方程非常有用。

创建这样的函数阻止我直接使用矩阵DM来找到它的特征值(因为DM保留在函数内)。 出于这个原因,我使用scipy.sparse.LinearOperator来包装我的方法衍生物()并将其用作scipy.sparse.eig()的输入。

代码和结果:

以下是计算这些特征值的代码:

import numpy as np
import scipy
import sympy

from scipy.sparse.linalg import aslinearoperator
from scipy.sparse.linalg import eigs
from scipy.sparse.linalg import LinearOperator

import chebyshev

N = 20 # should be 4, 20, 50, 100, 300
max_order = 4

option = 1
#option 1: building the differentiation matrix DM for a given order
if option == 1:
    if 0:
        # usage of package chebyshev, but I add a file with the matrix inside
        nodes, DM = chebyshev.chebdiff(N, max_order)
        order = 1
        DM = DM[order-1,:,:]
        #outfile = TemporaryFile()
        np.save('DM20', DM)
    if 1:
        # loading the matrix from the file
        # uncomment depending on N
        #DM = np.load('DM4.npy')
        DM = np.load('DM20.npy')
        #DM = np.load('DM50.npy')
        #DM = np.load('DM100.npy')
        #DM = np.load('DM300.npy')

#option 2: building a random matrix
elif option == 2:
    j = np.complex(0,1)
    np.random.seed(0)
    Real = np.random.random((N, N)) - 0.5
    Im = np.random.random((N,N)) - 0.5

    # If I want DM symmetric:
    #Real = np.dot(Real, Real.T)
    #Im = np.dot(Im, Im.T)

    DM = Real + j*Im

    # If I want DM singular:
    #DM[0,:] = DM[1,:]

# Test DM symmetric
print('Is DM symmetric ? \n', (DM.transpose() == DM).all() )        
# Test DM Hermitian
print('Is DM hermitian ? \n', (DM.transpose().real == DM.real).all() and
                                        (DM.transpose().imag == -DM.imag).all() )  

# building a linear operator which wrap matrix DM
def derivative(v):
    return np.dot(DM, v)

linop_DM = LinearOperator( (N, N), matvec = derivative)

# building a linear operator directly from a matrix DM with asLinearOperator
aslinop_DM = aslinearoperator(DM)

# comparison of LinearOperator and direct Dot Product
V = np.random.random((N))
diff_lo = linop_DM.matvec(V)
diff_mat = np.dot(DM, V)
# diff_lo and diff_mat are equals

# FINDING EIGENVALUES

#number of eigenvalues to find
k = 1
if 1:
    # SCIPY SPARSE LINALG LINEAR OPERATOR
    vals_sparse, vecs = scipy.sparse.linalg.eigs(linop_DM, k, which='SR',
                            maxiter = 10000,
                            tol = 1E-3)
    vals_sparse = np.sort(vals_sparse)
    print('\nEigenvalues (scipy.sparse.linalg Linear Operator) : \n', vals_sparse)

if 1:
    # SCIPY SPARSE ARRAY
    vals_sparse2, vecs2 = scipy.sparse.linalg.eigs(DM, k, which='SR',
                        maxiter = 10000,
                        tol = 1E-3)
    vals_sparse2 = np.sort(vals_sparse2)
    print('\nEigenvalues (scipy.sparse.linalg with matrix DM) : \n', vals_sparse2)

if 1:
    # SCIPY SPARSE AS LINEAR OPERATOR
    vals_sparse3, vecs3 = scipy.sparse.linalg.eigs(aslinop_DM, k, which='SR',
                        maxiter = 10000,
                        tol = 1E-3)
    vals_sparse3 = np.sort(vals_sparse3)
    print('\nEigenvalues (scipy.sparse.linalg AS linear Operator) : \n', vals_sparse3)

if 0:
    # NUMPY LINALG / SAME RESULT AS SCIPY LINALG
    vals_np = np.linalg.eigvals(DM)
    vals_np = np.sort(vals_np)
    print('\nEigenvalues (numpy.linalg) : \n', vals_np)

if 1:
    # SCIPY LINALG
    vals_sp = scipy.linalg.eig(DM)
    vals_sp = np.sort(vals_sp[0])
    print('\nEigenvalues (scipy.linalg.eig) : \n', vals_sp)

if 0:
    x = sympy.Symbol('x')
    D = sympy.Matrix(DM)
    print('\ndet D (sympy):', D.det() )
    E = D - x*np.eye(DM.shape[0])
    eig_sympy = sympy.solve(E.det(), x)
    print('\nEigenvalues (sympy) : \n', eig_sympy)

以下是我的结果(对于N = 20):

Is DM symmetric ? 
 False
Is DM hermitian ? 
 False

Eigenvalues (scipy.sparse.linalg Linear Operator) : 
 [-2.5838015+0.j]

Eigenvalues (scipy.sparse.linalg with matrix DM) : 
 [-2.58059801+0.j]

Eigenvalues (scipy.sparse.linalg AS linear Operator) : 
 [-2.36137671+0.j]

Eigenvalues (scipy.linalg.eig) : 
 [-2.92933791+0.j         -2.72062839-1.01741142j -2.72062839+1.01741142j
 -2.15314244-1.84770128j -2.15314244+1.84770128j -1.36473659-2.38021351j
 -1.36473659+2.38021351j -0.49536645-2.59716913j -0.49536645+2.59716913j
  0.38136094-2.53335888j  0.38136094+2.53335888j  0.55256471-1.68108134j
  0.55256471+1.68108134j  1.26425751-2.25101241j  1.26425751+2.25101241j
  2.03390489-1.74122287j  2.03390489+1.74122287j  2.57770573-0.95982011j
  2.57770573+0.95982011j  2.77749810+0.j        ]

scipy.sparse返回的值应该包含在scipy / numpy找到的值中,但实际情况并非如此。 (同情的同意)

我尝试过使用不同的随机矩阵而不是DM(参见选项2)(对称,非对称,真实,虚数等),它们具有小的N(4,5,6。 。)还有更大的(100,...)。 这工作

通过更改''等参数来改变(LM,SM,LR ......),' tol' (10E-3,10E-6 ..),' maxiter',' sigma' scipy.sparse中的(0)... scipy.sparse.linalg.eigs总是用于随机矩阵但从不用于我的矩阵DM。在最好的情况下,发现特征值接近scipy发现的特征值,但从不匹配。

我真的不知道我的矩阵中有什么特别之处。 我也不知道为什么将scipy.sparse.linagl.eig与矩阵,LinearOperator或AsLinearOperator一起使用会产生不同的结果。

我不知道我如何包含我的包含矩阵DM的文件......

对于N = 4:

[[ 3.16666667 -4.          1.33333333 -0.5       ]
 [ 1.         -0.33333333 -1.          0.33333333]
 [-0.33333333  1.          0.33333333 -1.        ]
 [ 0.5        -1.33333333  4.         -3.16666667]]

欢迎任何想法。

主持人可以用以下方式标记我的问题: scipy.sparse.linalg.eigs / weideman / eigenvalues / scipy.eig /scipy.sparse.lingalg.linearOperator

弗鲁瓦。

1 个答案:

答案 0 :(得分:1)

我和一些同事交谈,部分解决了我的问题。 我的结论是我的矩阵病情非常严重......

在我的项目中,我可以通过强加边界条件来简化矩阵:

[[ 0     0               0               0]
 [ 0     -0.33333333     -1.             0]
 [ 0      1.             0.33333333      0]
 [ 0      0              0               0]]

产生类似于N = 4的矩阵:

{{1}}

通过使用这样的条件,我获得了scipy.sparse.linalg.eigs的特征值,它等于scipy.linalg.eig中的特征值。 我也尝试使用Matlab,它返回相同的值。

为了继续我的工作,我实际上需要使用标准形式的广义特征值问题

  

λBx = DM x

由于我的矩阵B(代表拉普拉斯算子矩阵),它似乎在我的情况下不起作用。 如果您遇到类似问题,我建议您访问该问题: https://scicomp.stackexchange.com/questions/10940/solving-a-generalised-eigenvalue-problem

(我认为)矩阵B需要是肯定的才能使用scipy.sparse。 解决方案是更改B,使用scipy.linalg.eig或使用Matlab。 我稍后会证实。

编辑:

我为上面发布的堆栈交换问题写了一个解决方案,解释了我如何解决我的问题。 我看来,如果矩阵B不是正定的,scipy.sparse.linalg.eigs确实存在一个错误,并且会返回不正确的特征值。