You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by tn...@apache.org on 2013/10/18 23:19:18 UTC

svn commit: r1533638 - in /commons/proper/math/trunk/src: changes/ main/java/org/apache/commons/math3/linear/ test/java/org/apache/commons/math3/linear/

Author: tn
Date: Fri Oct 18 21:19:18 2013
New Revision: 1533638

URL: http://svn.apache.org/r1533638
Log:
[MATH-1004] Added new methods to compute the inverse of a matrix to DiagonalMatrix and MatrixUtils.

Modified:
    commons/proper/math/trunk/src/changes/changes.xml
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/linear/DiagonalMatrix.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/linear/MatrixUtils.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/linear/DiagonalMatrixTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/linear/MatrixUtilsTest.java

Modified: commons/proper/math/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/changes/changes.xml?rev=1533638&r1=1533637&r2=1533638&view=diff
==============================================================================
--- commons/proper/math/trunk/src/changes/changes.xml (original)
+++ commons/proper/math/trunk/src/changes/changes.xml Fri Oct 18 21:19:18 2013
@@ -51,6 +51,10 @@ If the output is not quite correct, chec
   </properties>
   <body>
     <release version="x.y" date="TBD" description="TBD">
+      <action dev="tn" type="add" issue="MATH-1004" due-to="Ajo Fod">
+        Added new methods to compute the inverse of a matrix to "DiagonalMatrix"
+        and "MatrixUtils".
+      </action>
       <action dev="tn" type="fix" issue="MATH-1029">
         The "BigFraction" constructor will throw a "FractionConversionException"
         also in case negative values are provided which exceed the allowed range

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/linear/DiagonalMatrix.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/linear/DiagonalMatrix.java?rev=1533638&r1=1533637&r2=1533638&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/linear/DiagonalMatrix.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/linear/DiagonalMatrix.java Fri Oct 18 21:19:18 2013
@@ -319,4 +319,53 @@ public class DiagonalMatrix extends Abst
         }
     }
 
+    /**
+     * Computes the inverse of this diagonal matrix.
+     * <p>
+     * Note: this method will use a singularity threshold of 0,
+     * use {@link #inverse(double)} if a different threshold is needed.
+     *
+     * @return the inverse of {@code m}
+     * @throws SingularMatrixException if the matrix is singular
+     * @since 3.3
+     */
+    public DiagonalMatrix inverse() throws SingularMatrixException {
+        return inverse(0);
+    }
+
+    /**
+     * Computes the inverse of this diagonal matrix.
+     *
+     * @param threshold Singularity threshold.
+     * @return the inverse of {@code m}
+     * @throws SingularMatrixException if the matrix is singular
+     * @since 3.3
+     */
+    public DiagonalMatrix inverse(double threshold) throws SingularMatrixException {
+        if (isSingular(threshold)) {
+            throw new SingularMatrixException();
+        }
+
+        final double[] result = new double[data.length];
+        for (int i = 0; i < data.length; i++) {
+            result[i] = 1.0 / data[i];
+        }
+        return new DiagonalMatrix(result, false);
+    }
+
+    /** Returns whether this diagonal matrix is singular, i.e. any diagonal entry
+     * is equal to {@code 0} within the given threshold.
+     *
+     * @param threshold Singularity threshold.
+     * @return {@code true} if the matrix is singular, {@code false} otherwise
+     * @since 3.3
+     */
+    public boolean isSingular(double threshold) {
+        for (int i = 0; i < data.length; i++) {
+            if (Precision.equals(data[i], 0.0, threshold)) {
+                return true;
+            }
+        }
+        return false;
+    }
 }

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/linear/MatrixUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/linear/MatrixUtils.java?rev=1533638&r1=1533637&r2=1533638&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/linear/MatrixUtils.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/linear/MatrixUtils.java Fri Oct 18 21:19:18 2013
@@ -36,6 +36,7 @@ import org.apache.commons.math3.fraction
 import org.apache.commons.math3.fraction.Fraction;
 import org.apache.commons.math3.util.FastMath;
 import org.apache.commons.math3.util.MathArrays;
+import org.apache.commons.math3.util.MathUtils;
 import org.apache.commons.math3.util.Precision;
 
 /**
@@ -1063,4 +1064,57 @@ public class MatrixUtils {
 
         return result;
     }
+
+    /**
+     * Computes the inverse of the given matrix.
+     * <p>
+     * By default, the inverse of the matrix is computed using the QR-decomposition,
+     * unless a more efficient method can be determined for the input matrix.
+     * <p>
+     * Note: this method will use a singularity threshold of 0,
+     * use {@link #inverse(RealMatrix, double)} if a different threshold is needed.
+     *
+     * @param matrix Matrix whose inverse shall be computed
+     * @return the inverse of {@code matrix}
+     * @throws NullArgumentException if {@code matrix} is {@code null}
+     * @throws SingularMatrixException if m is singular
+     * @throws NonSquareMatrixException if matrix is not square
+     * @since 3.3
+     */
+    public static RealMatrix inverse(RealMatrix matrix)
+            throws NullArgumentException, SingularMatrixException, NonSquareMatrixException {
+        return inverse(matrix, 0);
+    }
+
+    /**
+     * Computes the inverse of the given matrix.
+     * <p>
+     * By default, the inverse of the matrix is computed using the QR-decomposition,
+     * unless a more efficient method can be determined for the input matrix.
+     *
+     * @param matrix Matrix whose inverse shall be computed
+     * @param threshold Singularity threshold
+     * @return the inverse of {@code m}
+     * @throws NullArgumentException if {@code matrix} is {@code null}
+     * @throws SingularMatrixException if matrix is singular
+     * @throws NonSquareMatrixException if matrix is not square
+     * @since 3.3
+     */
+    public static RealMatrix inverse(RealMatrix matrix, double threshold)
+            throws NullArgumentException, SingularMatrixException, NonSquareMatrixException {
+
+        MathUtils.checkNotNull(matrix);
+
+        if (!matrix.isSquare()) {
+            throw new NonSquareMatrixException(matrix.getRowDimension(),
+                                               matrix.getColumnDimension());
+        }
+
+        if (matrix instanceof DiagonalMatrix) {
+            return ((DiagonalMatrix) matrix).inverse(threshold);
+        } else {
+            QRDecomposition decomposition = new QRDecomposition(matrix, threshold);
+            return decomposition.getSolver().getInverse();
+        }
+    }
 }

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/linear/DiagonalMatrixTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/linear/DiagonalMatrixTest.java?rev=1533638&r1=1533637&r2=1533638&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/linear/DiagonalMatrixTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/linear/DiagonalMatrixTest.java Fri Oct 18 21:19:18 2013
@@ -340,4 +340,29 @@ public class DiagonalMatrixTest {
         Assert.assertEquals( 6.0, diag.getEntry(2, 2), 1.0e-20);
     }
 
+    @Test(expected=SingularMatrixException.class)
+    public void testInverseError() {
+        final double[] data = { 1, 2, 0 };
+        final DiagonalMatrix diag = new DiagonalMatrix(data);
+        diag.inverse();
+    }
+
+    @Test(expected=SingularMatrixException.class)
+    public void testInverseError2() {
+        final double[] data = { 1, 2, 1e-6 };
+        final DiagonalMatrix diag = new DiagonalMatrix(data);
+        diag.inverse(1e-5);
+    }
+
+    @Test
+    public void testInverse() {
+        final double[] data = { 1, 2, 3 };
+        final DiagonalMatrix m = new DiagonalMatrix(data);
+        final DiagonalMatrix inverse = m.inverse();
+
+        final DiagonalMatrix result = m.multiply(inverse);
+        TestUtils.assertEquals("DiagonalMatrix.inverse() returns wrong result",
+                MatrixUtils.createRealIdentityMatrix(data.length), result, Math.ulp(1d));
+    }
+
 }

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/linear/MatrixUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/linear/MatrixUtilsTest.java?rev=1533638&r1=1533637&r2=1533638&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/linear/MatrixUtilsTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/linear/MatrixUtilsTest.java Fri Oct 18 21:19:18 2013
@@ -17,6 +17,7 @@
 package org.apache.commons.math3.linear;
 
 import java.math.BigDecimal;
+
 import org.apache.commons.math3.TestUtils;
 import org.apache.commons.math3.fraction.BigFraction;
 import org.apache.commons.math3.fraction.Fraction;
@@ -37,6 +38,8 @@ import org.junit.Test;
 public final class MatrixUtilsTest {
 
     protected double[][] testData = { {1d,2d,3d}, {2d,5d,3d}, {1d,0d,8d} };
+    protected double[][] testData3x3Singular = { { 1, 4, 7, }, { 2, 5, 8, }, { 3, 6, 9, } };
+    protected double[][] testData3x4 = { { 12, -51, 4, 1 }, { 6, 167, -68, 2 }, { -4, 24, -41, 3 } };
     protected double[][] nullMatrix = null;
     protected double[] row = {1,2,3};
     protected BigDecimal[] bigRow =
@@ -445,4 +448,38 @@ public final class MatrixUtilsTest {
         };
         MatrixUtils.checkSymmetric(MatrixUtils.createRealMatrix(dataNonSym), Math.ulp(1d));
     }
+    
+    @Test(expected=SingularMatrixException.class)
+    public void testInverseSingular() {
+        RealMatrix m = MatrixUtils.createRealMatrix(testData3x3Singular);
+        MatrixUtils.inverse(m);
+    }
+    
+    @Test(expected=NonSquareMatrixException.class)
+    public void testInverseNonSquare() {
+        RealMatrix m = MatrixUtils.createRealMatrix(testData3x4);
+        MatrixUtils.inverse(m);
+    }
+    
+    @Test
+    public void testInverseDiagonalMatrix() {
+        final double[] data = { 1, 2, 3 };
+        final RealMatrix m = new DiagonalMatrix(data);
+        final RealMatrix inverse = MatrixUtils.inverse(m);
+
+        final RealMatrix result = m.multiply(inverse);
+        TestUtils.assertEquals("MatrixUtils.inverse() returns wrong result",
+                MatrixUtils.createRealIdentityMatrix(data.length), result, Math.ulp(1d));
+    }
+
+    @Test
+    public void testInverseRealMatrix() {
+        RealMatrix m = MatrixUtils.createRealMatrix(testData);
+        final RealMatrix inverse = MatrixUtils.inverse(m);
+
+        final RealMatrix result = m.multiply(inverse);
+        TestUtils.assertEquals("MatrixUtils.inverse() returns wrong result",
+                MatrixUtils.createRealIdentityMatrix(testData.length), result, 1e-12);
+    }
+
 }