[ https://issues.apache.org/jira/browse/MATH-1617?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Ng Tsz Sum updated MATH-1617: ----------------------------- Description: >From >[https://stackoverflow.com/questions/68427448/how-to-find-the-inverse-of-a-matrix-using-apache-commons-math-library-in-java/68427869?noredirect=1#comment120932354_68427869] h3. Reproducible example {code:java} import org.apache.commons.math3.linear.FieldLUDecomposition; import org.apache.commons.math3.linear.FieldMatrix; import org.apache.commons.math3.linear.MatrixUtils; import org.apache.commons.math3.util.BigReal; public class REPREX { public static void main(String[] args) { 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(); // Exception in thread "main" 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) // at stackoverflow.math.matrix.REPREX.main(REPREX.java:18) } } {code} h3. Possible reason: In {{FieldLUDecomposition}} line 130-133 {code:java} if (lu[nonZero][col].equals(field.getZero())) { // try to select a better permutation choice ++nonZero; } {code} Which produce incorrect result when {{lu[nonZeror][col]}} the BigDecimal val has different scale to {{field.getZero()}} scale. as the {{BigReal#equals}} is comparing using {{BigDecimal#equals}} h3. Workaround I tried to copy class {{BigReal}} and {{BigRealField}} to {{FixBigReal}} and {{FixBigRealField}} and replace all {{BigReal}} to {{FixBigReal}} inside. Then override {{FixBIgReal#equals}} and {{FixBIgReal#hashcode }}as {code:java} @Override public boolean equals(Object other) { if (this == other) { return true; } if (other instanceof FixBigReal) { return d.compareTo(((FixBigReal) other).d) == 0; } return false; } ... @Override public int hashCode() { return Double.hashCode(d.doubleValue()); } {code} Then the below program will not throw error {code:java} import org.apache.commons.math3.linear.FieldLUDecomposition; import org.apache.commons.math3.linear.FieldMatrix; import org.apache.commons.math3.linear.MatrixUtils; import org.apache.commons.math3.util.BigReal; public class MVE { public static void main(String[] args) { FixBigReal[][] leftMatrixData = new FixBigReal[][]{ {new FixBigReal(1), new FixBigReal(0), new FixBigReal(0), new FixBigReal(0)}, {new FixBigReal(1), new FixBigReal(0), new FixBigReal(1), new FixBigReal(0)}, {new FixBigReal(1), new FixBigReal(1), new FixBigReal(0), new FixBigReal(0)}, {new FixBigReal(1), new FixBigReal(1), new FixBigReal(1), new FixBigReal(1)}, }; FieldMatrix<FixBigReal> leftMatrix = MatrixUtils.createFieldMatrix(leftMatrixData); FieldMatrix<FixBigReal> leftMatrixInverse = new FieldLUDecomposition<>(leftMatrix) .getSolver() .getInverse(); } } {code} was: >From >[https://stackoverflow.com/questions/68427448/how-to-find-the-inverse-of-a-matrix-using-apache-commons-math-library-in-java/68427869?noredirect=1#comment120932354_68427869] h3. Reproducible example {code:java} import org.apache.commons.math3.linear.FieldLUDecomposition; import org.apache.commons.math3.linear.FieldMatrix; import org.apache.commons.math3.linear.MatrixUtils; import org.apache.commons.math3.util.BigReal; public class REPREX { public static void main(String[] args) { 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(); // Exception in thread "main" 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) // at stackoverflow.math.matrix.REPREX.main(REPREX.java:18) } } {code} h3. Possible reason: In {{FieldLUDecomposition}} line 130-133 {code:java} if (lu[nonZero][col].equals(field.getZero())) { // try to select a better permutation choice ++nonZero; } {code} Which produce incorrect result when {{lu[nonZeror][col]}} the BigDecimal val has different scale to {{field.getZero()}} scale. as the {{BigReal#equals}} is comparing using {{BigDecimal#equals}} h3. Workaround I tried to copy class {{BigReal}} and {{BigRealField}} to {{FixBigReal}} and {{FixBigRealField}} and replace all {{BigReal}} to {{FixBigReal}} inside. Then override {{FixBIgReal#equals}} as {code:java} @Override public boolean equals(Object other) { if (this == other) { return true; } if (other instanceof FixBigReal) { return d.compareTo(((FixBigReal) other).d) == 0; } return false; } {code} Then the below program will not throw error {code:java} import org.apache.commons.math3.linear.FieldLUDecomposition; import org.apache.commons.math3.linear.FieldMatrix; import org.apache.commons.math3.linear.MatrixUtils; import org.apache.commons.math3.util.BigReal; public class MVE { public static void main(String[] args) { FixBigReal[][] leftMatrixData = new FixBigReal[][]{ {new FixBigReal(1), new FixBigReal(0), new FixBigReal(0), new FixBigReal(0)}, {new FixBigReal(1), new FixBigReal(0), new FixBigReal(1), new FixBigReal(0)}, {new FixBigReal(1), new FixBigReal(1), new FixBigReal(0), new FixBigReal(0)}, {new FixBigReal(1), new FixBigReal(1), new FixBigReal(1), new FixBigReal(1)}, }; FieldMatrix<FixBigReal> leftMatrix = MatrixUtils.createFieldMatrix(leftMatrixData); FieldMatrix<FixBigReal> leftMatrixInverse = new FieldLUDecomposition<>(leftMatrix) .getSolver() .getInverse(); } } {code} > FieldLUDecomposition with BigReal throw divide by zero error > ------------------------------------------------------------ > > Key: MATH-1617 > URL: https://issues.apache.org/jira/browse/MATH-1617 > Project: Commons Math > Issue Type: Bug > Affects Versions: 3.6.1 > Reporter: Ng Tsz Sum > Priority: Major > Fix For: 4.0 > > Attachments: MATH-1617.patch > > Time Spent: 10m > Remaining Estimate: 0h > > From > [https://stackoverflow.com/questions/68427448/how-to-find-the-inverse-of-a-matrix-using-apache-commons-math-library-in-java/68427869?noredirect=1#comment120932354_68427869] > h3. Reproducible example > {code:java} > import org.apache.commons.math3.linear.FieldLUDecomposition; > import org.apache.commons.math3.linear.FieldMatrix; > import org.apache.commons.math3.linear.MatrixUtils; > import org.apache.commons.math3.util.BigReal; > public class REPREX { > public static void main(String[] args) { > 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(); > // Exception in thread "main" > 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) > // at stackoverflow.math.matrix.REPREX.main(REPREX.java:18) > } > } > {code} > h3. Possible reason: > In {{FieldLUDecomposition}} line 130-133 > {code:java} > if (lu[nonZero][col].equals(field.getZero())) { > // try to select a better permutation choice > ++nonZero; > } > {code} > Which produce incorrect result when {{lu[nonZeror][col]}} the BigDecimal val > has different scale > to {{field.getZero()}} scale. as the {{BigReal#equals}} is comparing using > {{BigDecimal#equals}} > h3. Workaround > I tried to copy class {{BigReal}} and {{BigRealField}} to {{FixBigReal}} and > {{FixBigRealField}} and replace all {{BigReal}} to {{FixBigReal}} inside. > Then override {{FixBIgReal#equals}} and {{FixBIgReal#hashcode }}as > {code:java} > @Override > public boolean equals(Object other) { > if (this == other) { > return true; > } > if (other instanceof FixBigReal) { > return d.compareTo(((FixBigReal) other).d) == 0; > } > return false; > } > ... > @Override > public int hashCode() { > return Double.hashCode(d.doubleValue()); > } > {code} > Then the below program will not throw error > {code:java} > import org.apache.commons.math3.linear.FieldLUDecomposition; > import org.apache.commons.math3.linear.FieldMatrix; > import org.apache.commons.math3.linear.MatrixUtils; > import org.apache.commons.math3.util.BigReal; > public class MVE { > public static void main(String[] args) { > FixBigReal[][] leftMatrixData = new FixBigReal[][]{ > {new FixBigReal(1), new FixBigReal(0), new FixBigReal(0), new > FixBigReal(0)}, > {new FixBigReal(1), new FixBigReal(0), new FixBigReal(1), new > FixBigReal(0)}, > {new FixBigReal(1), new FixBigReal(1), new FixBigReal(0), new > FixBigReal(0)}, > {new FixBigReal(1), new FixBigReal(1), new FixBigReal(1), new > FixBigReal(1)}, > }; > FieldMatrix<FixBigReal> leftMatrix = > MatrixUtils.createFieldMatrix(leftMatrixData); > FieldMatrix<FixBigReal> leftMatrixInverse = new > FieldLUDecomposition<>(leftMatrix) > .getSolver() > .getInverse(); > } > } > {code} -- This message was sent by Atlassian Jira (v8.3.4#803005)