Python(NumPy,SciPy),find一个matrix的零空间

我试图find给定matrix的零空间(Ax = 0的解空间)。 我find了两个例子,但我似乎无法得到任何工作。 而且,我不明白他们在做什么,所以我不能debugging。 我希望有人能够通过这个来引导我。

文档页面( numpy.linalg.svdnumpy.compress )对我来说是不透明的。 我学会了通过创buildmatrixC = [A|0]来做到这一点,find缩小的行梯forms并逐行求解variables。 我似乎无法仿效这些例子中的做法。

感谢您的帮助!

这里是我的示例matrix,它与维基百科示例相同:

 A = matrix([ [2,3,5], [-4,2,3] ]) 

方法( 在这里和这里 find ):

 import scipy from scipy import linalg, matrixr def null(A, eps=1e-15): u, s, vh = scipy.linalg.svd(A) null_mask = (s <= eps) null_space = scipy.compress(null_mask, vh, axis=0) return scipy.transpose(null_space) 

当我尝试它时,我得到一个空matrix:

 Python 2.6.6 (r266:84292, Sep 15 2010, 16:22:56) [GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import scipy >>> from scipy import linalg, matrix >>> def null(A, eps=1e-15): ... u, s, vh = scipy.linalg.svd(A) ... null_mask = (s <= eps) ... null_space = scipy.compress(null_mask, vh, axis=0) ... return scipy.transpose(null_space) ... >>> A = matrix([ ... [2,3,5], ... [-4,2,3] ... ]) >>> >>> null(A) array([], shape=(3, 0), dtype=float64) >>> 

这对我来说似乎是行得通的:

 A = matrix([[2,3,5],[-4,2,3],[0,0,0]]) A * null(A) >>> [[ 4.02455846e-16] >>> [ 1.94289029e-16] >>> [ 0.00000000e+00]] 

Sympy使这个直截了当。

 >>> from sympy import Matrix >>> A = [[2, 3, 5], [-4, 2, 3], [0, 0, 0]] >>> A = Matrix(A) >>> A * A.nullspace()[0] Matrix([ [0], [0], [0]]) >>> A.nullspace() [Matrix([ [-1/16], [-13/8], [ 1]])] 

你得到matrixA的SVD分解。 s是特征值的向量。 您对几乎为零的特征值感兴趣(参见$ A * x = \ lambda * x $,其中$ \ abs(\ lambda)<\ epsilon $),由逻辑值向量null_mask

然后,从列表中提取对应于几乎为零的特征值的特征向量,这正是您正在寻找的:跨越空间的一种方法。 基本上,你提取的行,然后转置的结果,让你得到一个matrix的特征向量作为列。

你的方法几乎是正确的。 问题是函数scipy.linalg.svd返回的s的形状是(K,),其中K = min(M,N)。 因此,在你的例子中,s只有两个入口(前两个奇异向量的奇异值)。 下面的你的空函数的修正应该允许它适用于任何大小的matrix。

 import scipy import numpy as np from scipy import linalg, matrix def null(A, eps=1e-12): ... u, s, vh = scipy.linalg.svd(A) ... padding = max(0,np.shape(A)[1]-np.shape(s)[0]) ... null_mask = np.concatenate(((s <= eps), np.ones((padding,),dtype=bool)),axis=0) ... null_space = scipy.compress(null_mask, vh, axis=0) ... return scipy.transpose(null_space) A = matrix([[2,3,5],[-4,2,3]]) print A*null(A) >>>[[ 4.44089210e-16] >>> [ 6.66133815e-16]] A = matrix([[1,0,1,0],[0,1,0,0],[0,0,0,0],[0,0,0,0]]) print null(A) >>>[[ 0. -0.70710678] >>> [ 0. 0. ] >>> [ 0. 0.70710678] >>> [ 1. 0. ]] print A*null(A) >>>[[ 0. 0.] >>> [ 0. 0.] >>> [ 0. 0.] >>> [ 0. 0.]] 

一个更快,但数量更less的稳定方法是使用排名揭示QR分解 ,如pivoting=True scipy.linalg.qr

 import numpy as np from scipy.linalg import qr def qr_null(A, tol=None): Q, R, P = qr(AT, mode='full', pivoting=True) tol = np.finfo(R.dtype).eps if tol is None else tol rnk = min(A.shape) - np.abs(np.diag(R))[::-1].searchsorted(tol) return Q[:, rnk:].conj() 

例如:

 A = np.array([[ 2, 3, 5], [-4, 2, 3], [ 0, 0, 0]]) Z = qr_null(A) print(A.dot(Z)) #[[ 4.44089210e-16] # [ 6.66133815e-16] # [ 0.00000000e+00]]