如何在 Java 中使用 Apache Commons 数学库求逆矩阵?

How to find the inverse of a matrix using Apache Commons Math library in Java?

我正在尝试使用 Apache Commons 数学库求逆矩阵。

下面是我的尝试:

BigReal[][] leftMatrixData = new BigReal[][] {
    { new BigReal(1), new BigReal(0), new BigReal(0), new BigReal(0) },
    { new BigReal(1), new BigReal(0), new BigReal(1), new BigReal(0) },
    { new BigReal(1), new BigReal(1), new BigReal(0), new BigReal(0) },
    { new BigReal(1), new BigReal(1), new BigReal(1), new BigReal(1) },
};

FieldMatrix<BigReal> leftMatrix = MatrixUtils.createFieldMatrix(leftMatrixData);
FieldMatrix<BigReal> leftMatrixInverse = new FieldLUDecomposition<>(leftMatrix)
    .getSolver()
    .getInverse();

当我运行这个时,我得到以下错误:

org.apache.commons.math3.exception.MathArithmeticException: zero not allowed here

    at org.apache.commons.math3.util.BigReal.divide(BigReal.java:255)
    at org.apache.commons.math3.util.BigReal.divide(BigReal.java:39)
    at org.apache.commons.math3.linear.FieldLUDecomposition.<init>(FieldLUDecomposition.java:160)

当我根据上述错误消息转到 FieldLUDecomposition.java 的第 160 行时,我看到库认为这个矩阵是奇异矩阵,即它认为它没有逆矩阵:

public T getDeterminant() {
    if (this.singular) { <---- this is line 160
        return (FieldElement)this.field.getZero();
    } else {
        int m = this.pivot.length;
        T determinant = this.even ? (FieldElement)this.field.getOne() : (FieldElement)((FieldElement)this.field.getZero()).subtract(this.field.getOne());

但是,对 WolframAlpha 进行快速检查表明该矩阵具有非零行列式并且确实具有逆矩阵:

所以问题是 - 我做错了什么以及如何找到矩阵的逆矩阵?我使用了错误的求解器吗?

以下是基于apache common math 3.6.1

关于这个问题有人提出ticket,我提交了一个补丁来修复这个问题,修复版本为4.0(截至2021-07-19尚未发布)

问题的原因是 BigReal

中的 equals 方法
    @Override
    public boolean equals(Object other) {
        if (this == other){
            return true;
        }

        if (other instanceof BigReal){
            return d.equals(((BigReal) other).d);
        }
        return false;
    }

其中 d 是 BigDecimalBigReal 的支持值。当两个BigRealdwith same value but different scale时,这个原因等于比较return不想要的结果,并在初始化FieldLUDecomposition时导致错误。对于 BigDecimal 我们应该检查

    return d.compareTo((BigReal) other) == 0;

相反。

解决方案:

  1. 检查 workaround section(将 BigReal 复制为本地 class 并更改 equals)是否有帮助。
  2. 等待4.0版本发布。
  3. 如果可以接受双值矩阵, 使用RealMatrix instead, and MatrixUtils provide handy inverse方法
import org.apache.commons.math3.linear.MatrixUtils;
import org.apache.commons.math3.linear.RealMatrix;

public class CalculateInverse {
    public static void main(String[] args) {
        double[][] matrixData = new double[][]{
                {1, 0, 0, 0},
                {1, 0, 1, 0},
                {1, 1, 0, 0},
                {1, 1, 1, 1}
        };
        RealMatrix matrix = MatrixUtils.createRealMatrix(matrixData);
        RealMatrix inverse = MatrixUtils.inverse(matrix);
        System.out.println(inverse);
    }
}