如何在Python中计算稀疏矩阵的零空间/内核(x:M·x = 0)?

时间:2015-10-29 09:19:23

标签: python numpy scipy linear-algebra sparse-matrix

我在网上找到了一些示例,说明如何在Python中找到常规矩阵的零空间,但我找不到稀疏矩阵的任何示例(scipy.sparse.csr_matrix)。

通过空格我是指 x ,使 M·x = 0 ,其中' ·'是矩阵乘法。有人知道怎么做这个吗?

此外,在我的情况下,我知道零空间将由单个向量组成。这些信息可以用来提高方法的效率吗?

2 个答案:

答案 0 :(得分:1)

这还不是一个完整的答案,但希望它将成为一个完整的答案。您应该能够使用基于SVD的方法计算空间空间,该方法针对密集矩阵显示in this question

import numpy as np
from scipy import sparse
import scipy.sparse.linalg


def rand_rank_k(n, k, **kwargs):
    "generate a random (n, n) sparse matrix of rank <= k"
    a = sparse.rand(n, k, **kwargs)
    b = sparse.rand(k, n, **kwargs)
    return a.dot(b)

# I couldn't think of a simple way to generate a random sparse matrix with known
# rank, so I'm currently using a dense matrix for proof of concept
n = 100
M = rand_rank_k(n, n - 1, density=1)

# # this seems like it ought to work, but it doesn't
# u, s, vh = sparse.linalg.svds(M, k=1, which='SM')

# this works OK, but obviously converting your matrix to dense and computing all
# of the singular values/vectors is probably not feasible for large sparse matrices
u, s, vh = np.linalg.svd(M.todense(), full_matrices=False)

tol = np.finfo(M.dtype).eps * M.nnz
null_space = vh.compress(s <= tol, axis=0).conj().T

print(null_space.shape)
# (100, 1)
print(np.allclose(M.dot(null_space), 0))
# True

如果您知道 x 是单行向量,那么原则上您只需要计算 M 的最小奇异值/向量。应该可以使用scipy.sparse.linalg.svds,即:

来做到这一点
u, s, vh = sparse.linalg.svds(M, k=1, which='SM')
null_space = vh.conj().ravel()

不幸的是,scipy的svds seems to be badly behaved在找到奇异或近似奇异矩阵的小奇异值时,通常会返回NaN或抛出ArpackNoConvergence错误。

我目前还没有意识到使用Python绑定的截断SVD的替代实现,它可以在稀疏矩阵上工作,并且可以有选择地找到最小的奇异值 - 也许其他人知道一个?

修改

作为旁注,第二种方法似乎使用MATLAB或Octave的svds函数合理地工作:

>> M = rand(100, 99) * rand(99, 100);
% svds converges much more reliably if you set sigma to something small but nonzero
>> [U, S, V] = svds(M, 1, 1E-9);
>> max(abs(M * V))
ans =    1.5293e-10

答案 1 :(得分:1)

我一直在寻找解决同一问题的方法。对于较小的奇异值,使用Scipy的svds函数会提供不可靠的结果。因此,我一直在使用QR分解。 sparseqr https://github.com/yig/PySPQR为Matlabs SuiteSparseQR方法提供了包装,并且运行良好。使用该值,可以将空空间计算为:

    from sparseqr import qr
    Q, _, _,r = qr( M.transpose() )
    N = Q.tocsr()[:,r:]