3

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?

ptk
  • 6,835
  • 14
  • 45
  • 91

1 Answers1

3

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);
    }
}
samabcde
  • 6,988
  • 2
  • 25
  • 41
  • Thanks for the suggestion! Unfortunately, I would really like to keep things in BigDecimal for my use case in my code. I just simplified my example to 1s and 0s to show that I'm struggling to find inverses when I use a matrix consisting of BigDecimals and I don't know why. I think it might be a bug but I'm not sure since I'm new to using the Apache Commons Math library. – ptk Jul 18 '21 at 09:47
  • 1
    After some debugging, I think there is some issue in the library, I raised a ticket for the issue and updated the answer. – samabcde Jul 18 '21 at 11:56