Python(NumPy,SciPy),找到矩阵的零空间

时间:2011-05-04 19:56:17

标签: numpy matrix scipy linear-algebra svd

我正在尝试找到给定矩阵的零空间(Ax = 0的解空间)。我找到了两个例子,但我似乎无法工作。而且,我无法理解他们为实现目标所做的工作,所以我无法调试。我希望有人能够指引我完成这件事。

文档页面(numpy.linalg.svdnumpy.compress)对我来说是不透明的。我通过创建矩阵C = [A|0],找到减少的行梯形形式并按行求解变量来学习。我似乎无法遵循这些例子中的做法。

感谢您的帮助!

这是我的样本矩阵,与wikipedia example

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

方法(found herehere):

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)

当我尝试时,我得到一个空矩阵:

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)
>>> 

6 个答案:

答案 0 :(得分:17)

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]])]

答案 1 :(得分:9)

您获得矩阵A的SVD分解。 s是特征值的向量。您对几乎为零的特征值感兴趣(参见$ A * x = \ lambda * x $,其中$ \ abs(\ lambda)&lt; \ epsilon $),它由逻辑值null_mask的向量给出。 / p>

然后,从列表vh中提取对应于几乎为零的特征值的特征向量,这正是您要寻找的:一种跨越零空间的方法。基本上,您提取行然后转置结果,以便获得具有特征向量作为列的矩阵。

答案 2 :(得分:5)

它似乎对我有用:

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

答案 3 :(得分:3)

更快但数值更少的稳定方法是使用a rank-revealing QR decomposition,例如scipy.linalg.qrpivoting=True

import numpy as np
from scipy.linalg import qr

def qr_null(A, tol=None):
    Q, R, P = qr(A.T, 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]]

答案 4 :(得分:2)

你的方法几乎是正确的。问题是函数scipy.linalg.svd返回的s的形状是(K,)其中K = min(M,N)。因此,在您的示例中,s只有两个条目(前两个奇异向量的奇异值)。对null函数的以下更正应该允许它适用于任何大小的矩阵。

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.]]

答案 5 :(得分:2)

截至去年(2017年),scipy现在在null_space模块(docs)中具有内置的scipy.linalg方法。

implementation遵循规范的SVD分解,如果您使用的是scipy的较旧版本,并且需要自己实现,则它很小。但是,如果您是最新的,它就在您身边。

def null_space(A, rcond=None):
    u, s, vh = svd(A, full_matrices=True)
    M, N = u.shape[0], vh.shape[1]
    if rcond is None:
        rcond = numpy.finfo(s.dtype).eps * max(M, N)
    tol = numpy.amax(s) * rcond
    num = numpy.sum(s > tol, dtype=int)
    Q = vh[num:,:].T.conj()
    return Q