我有一个50,000 x 50,000的密集矩阵或更大的矩阵。如果我使用numpy或scipy-package,则所有本征向量的条目均为0。如果我使用scipy.sparse仅计算1000-8000个本征向量,则将得到正确的本征向量。但我都需要。
这可能是内存问题吗?或出现此问题的原因是什么? 我可以使用LAPACK或ARPACK来计算正确的特征向量吗?
请注意,我的矩阵是networkx图的表示,因此是稀疏矩阵。我使用numpy.linalg
将它们转换为密集矩阵,否则我将使用scipy.sparse.linalg
。
答案 0 :(得分:2)
与numpy.linalg.eig()
和scipy.linalg.eig()
有关的问题可能是与矩阵大小有关的内存错误:50000x50000双精度密集矩阵占用18Go的内存。
numpy.linalg.eig()
和scipy.linalg.eig()
依赖于LAPACK的例程DGEEV()
。 LAPACK DGEEV()
和DGEEVX()
利用QR algorithm来计算密集矩阵的所有特征值和特征向量。首先,使用dgehrd()
将矩阵简化为上Hessenberg形式,然后在dhseqr()
中执行QR迭代。在DGEEVX()
中,首先对矩阵进行平衡和缩放。
另一方面,scipy.sparse.linalg.eigs()
和scipy.sparse.linalg.eigsh()
依靠ARPACK函数来实现稀疏矩阵上的Implicitly Restarted Arnoldi Method和Implicitly Restarted Lanczos Method。两者都是幂方法的改进,并且在以改进的精度计算最大特征值/特征向量方面非常有效。如果Ax = b可以被快速求解,那么这些迭代方法对于找到最小的特征值/特征向量或接近给定值的特征值/特征向量也非常有效。
Lloyd N. Trefethen and David Bau, NUMERICAL LINEAR ALGEBRA, Lecture 33. The Arnoldi Iteration中说明了这两种方法之间的区别。
...,而Arnoldi迭代基于矩阵的QR分解(33.7),其列为b,A b,...,A ^ {n-1} b,同时迭代和QR算法基于矩阵的QR分解(28.16),其列为A ^ n e_1 ...,A ^ n e_n。
从实际的角度来看,总是将Arnoldi迭代用于检索有限数量的特征向量,这些特征向量显着低于矩阵的大小。但是,通过使用{strong> scipy.sparse.linalg.eigs()
或scipy.sparse.linalg.eigsh()
的自变量sigma
,可以找到sigma
附近的内部特征值和特征向量。因此,可以使用不同的sigma
多次调用scipy.sparse.linalg.eigsh()
。如果特征值均具有有限的多重性,则可以恢复所有特征向量。应通过分离特征值并跟踪其多重性来避免电位重复。
使用sigma
的基本调用写道:
sparsevalue, sparsevector = sp.sparse.linalg.eigsh(M.copy(), k = kkeig,sigma=sig, which='LM', mode='normal')
如果矩阵是Hermitian半
这是一个基于您先前删除的帖子的示例代码,该代码计算一个正半定稀疏矩阵的所有特征值。由于特征值都是实数和正值,因此sigma
会逐渐增加以找到所有特征值:
import numpy as np
import networkx as nx
import scipy as sp
def tolist(sparsevalue, keeplast=False):
listofeigval=[]
listofmultiplicity=[]
curreig=sparsevalue[0]-1.1*np.abs(sparsevalue[0])
for i in range(len(sparsevalue)):
#print curreig, sparsevalue[i], len(listofeigval)
if np.abs(curreig-sparsevalue[i])<1e-11*(np.abs(curreig)+np.abs(sparsevalue[i])):
listofmultiplicity[-1]=listofmultiplicity[-1]+1
else :
curreig=sparsevalue[i]
listofeigval.append(curreig)
listofmultiplicity.append(1)
if keeplast==False:
#the last one is not sure regarding multiplicity:
listofeigval.pop()
listofmultiplicity.pop()
return listofeigval,listofmultiplicity
def test():
N_1 = 2000
R_1 = 0.1
k = 0
iterations = 1
while k < iterations:
G = nx.random_geometric_graph(N_1, R_1)
if nx.is_connected(G) == True:
print 'got connected network'
k = k+1
M=nx.laplacian_matrix(G) #M is here a sparse matrix
M = M.astype(float)
#M[0,0]=M[0,0]+1. # this makes the laplacian_matrix positive definite.
#sparsevalue, sparsevector = sp.sparse.linalg.eigsh(M, k = N_1-2)
kkeig=400
sparsevalue, sparsevector = sp.sparse.linalg.eigsh(M.copy(), k = kkeig, which='SM')
print sparsevalue
listofeigval=[]
listofmultiplicity=[]
listofeigval,listofmultiplicity=tolist(sparsevalue)
print len(listofeigval), len(listofmultiplicity)
nbeigfound=0
for mul in listofmultiplicity:
nbeigfound=nbeigfound+mul
keepgoing=True
while( nbeigfound<N_1):
print '(',nbeigfound,'/',N_1,') is ', listofeigval[-1]
meanspacing=0.
meanspacingnb=0.
for i in range(10):
meanspacingnb=meanspacingnb+listofmultiplicity[len(listofeigval)-i-1]
meanspacing=(listofeigval[-1]-listofeigval[len(listofeigval)-10])/meanspacingnb
sig=listofeigval[-1]+0.1*kkeig*meanspacing
keeplast=False
if nbeigfound<N_1-0.5*kkeig:
sparsevalue, sparsevector = sp.sparse.linalg.eigsh(M.copy(), k = kkeig,sigma=sig, which='LM', mode='normal')
else:
keeplast=True
sparsevalue, sparsevector = sp.sparse.linalg.eigsh(M.copy(), k = kkeig, which='LM')
listofneweigval,listofnewmultiplicity=tolist(sparsevalue,keeplast)
#need to retreive the starting point
index=len(listofeigval)-2*kkeig/10
if listofneweigval[1]>listofeigval[index]:
while(np.abs(listofneweigval[1]-listofeigval[index])>1e-10*(np.abs(listofneweigval[1])+np.abs(listofeigval[index]))):
index=index+1
else:
while(np.abs(listofneweigval[1]-listofeigval[index])>1e-10*(np.abs(listofneweigval[1])+np.abs(listofeigval[index]))):
index=index-1
#The first matching eigenvalue is found.
#zipping the list and checking if it works.
i=1
while index<len(listofeigval) and i<len(listofneweigval) :
if (np.abs(listofneweigval[i]-listofeigval[index])>1e-10*(np.abs(listofneweigval[i])+np.abs(listofeigval[index]))):
print 'failed after ', index, ' different eigenvalues', ': wrong eigenvalue'
return listofeigval[0:index], listofmultiplicity[0:index], 1
if listofmultiplicity[index] != listofnewmultiplicity[i] :
print 'failed after ', index, ' different eigenvalues', ': wrong multiplicity'
return listofeigval[0:index], listofmultiplicity[0:index], 2
index=index+1
i=i+1
#adding the remaining eigenvalues.
while i<len(listofneweigval) :
listofeigval.append(listofneweigval[i])
listofmultiplicity.append(listofnewmultiplicity[i])
nbeigfound=nbeigfound+listofnewmultiplicity[i]
i=i+1
print 'number of eigenvalues: ', nbeigfound
nbl=0
for i in range(len(listofeigval)):
print 'eigenvalue ',i,' (',nbl,'/',N_1,') is %14.8f'% listofeigval[i], ' with multiplicity', listofmultiplicity[i]
nbl=nbl+listofmultiplicity[i]
return listofeigval, listofmultiplicity, 0
#sig=39.1
#sparsevalue, sparsevector = sp.sparse.linalg.eigsh(M.copy(), k = 100,sigma=sig, which='LM', mode='normal')
#print sparsevalue
test()
对于具有真实正负特征值的埃尔米特矩阵,将探索sigma的正负值。如果矩阵不是Hermitian,则特征值可能不是实数,并且将选择复平面上的sigma
值。首先搜索A
的最大特征值的大小会将区域限制为磁盘。
提出的方法非常慢,可能并不总是有效。使用1Go内存,它一次可用于20000x20000矩阵。