零行列式的N乘N矩阵的(伪)逆

6
我想要对一个nxn矩阵取逆来在我的GraphSlam中使用。
我遇到的问题是: 有人成功实现了一个允许负数、零值和零行列式的n x n矩阵求逆代码吗?有任何好的库(C++)推荐吗?
我试图在GraphSlam中计算以下omega: http://www.acastano.com/others/udacity/cs_373_autonomous_car.html

简单示例:

[ 1 -1  0 0 ]
[ -1 2 -1 0 ]
[ 0 -1  1 0 ]
[ 0  0  0 0 ]

真实的例子可能是170x170大小的矩阵,包含0、负值和更大的正值。给定的简单示例用于调试代码。


我可以在Matlab中计算这个(Moore-Penrose伪逆),但出于某些原因,我无法在C++中编程。

A = [1 -1 0 0; -1 2 -1 0; 0 -1 1 0; 0 0 0 0]
B = pinv(A)
B=
[0.56   -0.12  -0.44  0]
[-0.12  0.22   -0.11  0]
[-0.44  -0.11   0.56  0]
[0  0  0   0]

对于我的应用程序,我可以(暂时)去掉零维度。
因此,我将删除第4列和第4行。
我也可以对我的170x170矩阵进行操作,4x4只是一个示例。
[ 1 -1  0 ]
[ -1 2 -1 ]
[ 0 -1  1 ]

如果删除第四列和第四行,行列式不会为零。但是如果我的矩阵如上所示,仍然可能有零行列式。当每行或每列的总和为零时就会出现这种情况(在GraphSlam中我经常会遇到这种情况)

如果行列式不为零,则基于Moore-Penrose伪逆的LAPACK解决方案可行(使用Computing the inverse of a matrix using lapack in C的示例代码)。但是如果行列式为零,则作为“伪逆”失败。


解决方案:(所有功劳归功于Frank Reininghaus),使用奇异值分解(SVD)
http://sourceware.org/ml/gsl-discuss/2008-q2/msg00013.html

适用于:

  • 零值(甚至完全为0的行和列)
  • 负值
  • 行列式为零

A^-1:

[0.56   -0.12  -0.44]
[-0.12  0.22   -0.11]
[-0.44  -0.11   0.56]

高斯消元有什么问题吗? - Kerrek SB
你能否提供一个小矩阵的具体示例,这些方法都无法求逆?(我假设该矩阵是非奇异的。) - NPE
高斯消元法仍有可能在结果中出现负数和0值,对吗? - Toon
4
你给出的矩阵行列式为零,因此这不是一个可逆矩阵。我希望你不要尝试在这个矩阵上进行操作! - ritter
你能让这个标题变得有意义吗?行列式为零的矩阵没有逆矩阵。 - djechlin
4个回答

7

如果您只想解决形如Ax=B的问题(或等价地计算A^-1 * b的乘积),那么我建议您不要计算矩阵A的逆矩阵或伪逆矩阵,而是直接使用适当的排名揭示求解器求解Ax=b。例如,使用Eigen:

x = A.colPivHouseholderQr().solve(b);
x = A.jacobiSvd(ComputeThinU|ComputeThinV).solve(b);

5
您的Matlab命令不能计算逆矩阵,因为该矩阵的行列式为零。 pinv 命令计算 Moore-Penrose 伪逆矩阵pinv(A) 具有 inv(A) 的一些属性,但不是全部。

所以你在C++和Matlab中做的事情并不相同!

之前的内容

如我在评论中所述。 现在作为答案。 您必须确保反转可逆矩阵。 这意味着

det A != 0

您的示例矩阵的行列式等于零。 这不是一个可逆矩阵。 我希望您不要在此上尝试!

例如,如果存在全零条目的完整行或列,则给定矩阵的行列式为零。


我的错误。对于我的应用程序(GraphSlam),每行上所有值的总和将等于零。但在他们的代码中,他们仍然能够翻转那个omega矩阵。 - Toon
如果每行的总和为零,那并不能说明它的行列式是零。至少我没有很快看出来;-) - ritter
你正在尝试解决线性方程X=AY。你可以要求A的逆来获得问题的一般解,这需要满足det A!=0。然而,即使A的行列式为零,线性方程仍然是可解的。此时,解空间的维数大于0,因此有一个整个子向量空间作为可能的解。我建议先测试行列式,然后再决定如何解决线性方程:求逆、高斯消元等。 - ritter
好的,问题现在更加清晰了,我将开始研究C++中的Moore-Penrose伪逆。我之前并不确定问题出在哪里,但现在我知道不能使用正常的反转操作,而必须使用伪逆。Matlab使用Moore-Penrose伪逆,能够得到不错的结果。 - Toon
没错,在你的C++程序中,你要计算的不是伪逆。 - ritter

2
你确定是因为零/负值,而不是矩阵不可逆吗?
只有当矩阵的行列式非零时才具有逆矩阵(参见mathworld link),你在问题中发布的矩阵示例行列式为零,因此它没有逆矩阵。
这应该解释了为什么那些库不允许您对给定矩阵求逆,但我无法确定同样的推理是否适用于您的完整大小为170x170的矩阵。

0
如果您的矩阵是协方差或权重矩阵,您可以使用“广义Cholesky分解”代替SVD。这样得到的结果更适合实际应用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接