Java:使用 EJML 的矩阵求逆未按预期工作
Java: Inverse of a matrix using EJML not working as expected
在我开发的 java 项目中,我需要计算矩阵的逆。为了与其他项目和其他开发人员保持一致,我正在使用高效 Java 矩阵库 (orj.ejml)。
为了反转矩阵,我使用了来自 org.ejml.ops.CommonOps 的反转,并且我一直工作得很好,直到现在我得到了一个意想不到的结果
我已经隔离出不起作用的情况是:
DenseMatrix64F X = new DenseMatrix64F(3, 3);
X.setData(new double[]{77.44000335693366,-24.64000011444091,-8.800000190734865, -24.640000114440916,7.839999732971196,2.799999952316285, -8.800000190734865,2.799999952316285,1.0000000000000004});
DenseMatrix64F invX = new DenseMatrix64F(3, 3);
boolean completed = CommonOps.invert(X, invX);
System.out.println(X);
System.out.println(invX);
System.out.println(completed);
我从这个测试中得到的输出是:
Type = dense , numRows = 3 , numCols = 3
77.440 -24.640 -8.800
-24.640 7.840 2.800
-8.800 2.800 1.000
Type = dense , numRows = 3 , numCols = 3
NaN -Infinity Infinity
NaN Infinity -Infinity
NaN -Infinity Infinity
true
我的第一个想法是它可能是一个奇异矩阵,因此不可逆,但在用不同的计算工具测试同一个矩阵后,我发现它不是奇异的。
所以我返回到 EJML 文档并找到了有关此特定功能的以下信息。
If the algorithm could not invert the matrix then false is returned. If it returns true that just means the algorithm finished. The results could still be bad because the matrix is singular or nearly singular.
并且,在这种特殊情况下,矩阵不是奇异的,但我们可以说它接近奇异。
我唯一能想到的解决办法是在计算后在倒矩阵中搜索 NaN 或 Infinites,如果我发现其中有什么有趣的东西,我就用原始矩阵替换倒矩阵,尽管它并没有似乎是一种非常干净的做法,它会产生合理的结果。
我的问题是:
对于这种情况,你能想出什么解决办法吗?比仅使用原始矩阵作为自己的逆矩阵更聪明、更明智的方法。
万一没有办法解决,您是否知道任何其他 Java 矩阵库可以解决这种情况,我不希望引入新的库,但如果这成为一个真正的问题,它可能是唯一的解决方案。
问候并感谢您的投入!
如果你必须有逆,你应该尝试使用 SVD。也可以考虑伪逆。基本上任何使用 LU 分解的库都会有严重的问题。这是 Octave 的输出。请注意其中两个奇异值几乎为零。 Octave 会给你一个实数的反函数,但它很差...
octave:7> cond(B)
ans = 8.5768e+17
octave:8> svd(B)
ans =
8.6280e+01
3.7146e-15
1.0060e-16
inv(B)*B
warning: inverse: matrix singular to machine precision, rcond = 4.97813e-19
ans =
0.62500 0.06250 0.03125
0.00000 0.00000 0.00000
0.00000 0.00000 4.00000
在我开发的 java 项目中,我需要计算矩阵的逆。为了与其他项目和其他开发人员保持一致,我正在使用高效 Java 矩阵库 (orj.ejml)。
为了反转矩阵,我使用了来自 org.ejml.ops.CommonOps 的反转,并且我一直工作得很好,直到现在我得到了一个意想不到的结果
我已经隔离出不起作用的情况是:
DenseMatrix64F X = new DenseMatrix64F(3, 3);
X.setData(new double[]{77.44000335693366,-24.64000011444091,-8.800000190734865, -24.640000114440916,7.839999732971196,2.799999952316285, -8.800000190734865,2.799999952316285,1.0000000000000004});
DenseMatrix64F invX = new DenseMatrix64F(3, 3);
boolean completed = CommonOps.invert(X, invX);
System.out.println(X);
System.out.println(invX);
System.out.println(completed);
我从这个测试中得到的输出是:
Type = dense , numRows = 3 , numCols = 3
77.440 -24.640 -8.800
-24.640 7.840 2.800
-8.800 2.800 1.000Type = dense , numRows = 3 , numCols = 3
NaN -Infinity Infinity
NaN Infinity -Infinity
NaN -Infinity Infinitytrue
我的第一个想法是它可能是一个奇异矩阵,因此不可逆,但在用不同的计算工具测试同一个矩阵后,我发现它不是奇异的。
所以我返回到 EJML 文档并找到了有关此特定功能的以下信息。
If the algorithm could not invert the matrix then false is returned. If it returns true that just means the algorithm finished. The results could still be bad because the matrix is singular or nearly singular.
并且,在这种特殊情况下,矩阵不是奇异的,但我们可以说它接近奇异。
我唯一能想到的解决办法是在计算后在倒矩阵中搜索 NaN 或 Infinites,如果我发现其中有什么有趣的东西,我就用原始矩阵替换倒矩阵,尽管它并没有似乎是一种非常干净的做法,它会产生合理的结果。
我的问题是:
对于这种情况,你能想出什么解决办法吗?比仅使用原始矩阵作为自己的逆矩阵更聪明、更明智的方法。
万一没有办法解决,您是否知道任何其他 Java 矩阵库可以解决这种情况,我不希望引入新的库,但如果这成为一个真正的问题,它可能是唯一的解决方案。
问候并感谢您的投入!
如果你必须有逆,你应该尝试使用 SVD。也可以考虑伪逆。基本上任何使用 LU 分解的库都会有严重的问题。这是 Octave 的输出。请注意其中两个奇异值几乎为零。 Octave 会给你一个实数的反函数,但它很差...
octave:7> cond(B)
ans = 8.5768e+17
octave:8> svd(B)
ans =
8.6280e+01
3.7146e-15
1.0060e-16
inv(B)*B
warning: inverse: matrix singular to machine precision, rcond = 4.97813e-19
ans =
0.62500 0.06250 0.03125
0.00000 0.00000 0.00000
0.00000 0.00000 4.00000