Skip to content
Advertisement

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

I’m trying to find the inverse of a matrix using the Apache Commons Math Library.

Below is my attempt at doing just that:

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

When I run this, I get the following error:

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)

When I go to line 160 of FieldLUDecomposition.java per the above error message, I see that the library thinks this matrix is Singular i.e. it thinks it has no inverse:

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

However, doing a quick check on WolframAlpha shows that this matrix has a non-zero determinant and indeed has an inverse:

enter image description here

So the question is – what am I doing wrong and how do I find the inverse of my matrix? Am I using the wrong solver?

Advertisement

Answer

Below is based on apache common math 3.6.1

A ticket is raised concerning this issue, I submitted a patch to fix the problem and the fix version will be 4.0 (not yet released as of 2021-07-19)

The reason of issue is equals method in BigReal

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

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

where d is BigDecimal, the backing value of BigReal. This cause equals comparison return undesired result when two BigReal has d with same value but different scale, and cause error when initializing FieldLUDecomposition. For BigDecimal we should check

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

instead.

Solution:

  1. Check if workaround section(Copy BigReal as local class and change equals) helps.
  2. Wait for version 4.0 release.
  3. If double value matrix is acceptable, Use RealMatrix instead, and MatrixUtils provide handy inverse method
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);
    }
}
Advertisement