You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by lu...@apache.org on 2008/12/22 14:30:10 UTC

svn commit: r728686 - in /commons/proper/math/trunk/src/java/org/apache/commons/math/linear: EigenDecomposition.java EigenDecompositionImpl.java EigenSolver.java

Author: luc
Date: Mon Dec 22 05:30:10 2008
New Revision: 728686

URL: http://svn.apache.org/viewvc?rev=728686&view=rev
Log:
implemented solver as an internal class to avoid building decomposed matrices

Modified:
    commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenDecomposition.java
    commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenDecompositionImpl.java
    commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenSolver.java

Modified: commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenDecomposition.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenDecomposition.java?rev=728686&r1=728685&r2=728686&view=diff
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenDecomposition.java (original)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenDecomposition.java Mon Dec 22 05:30:10 2008
@@ -37,6 +37,8 @@
  *   <li>the <code>getRealEigenvalues</code> method has been renamed as {@link
  *   #getEigenValues() getEigenValues},</li>
  *   <li>the <code>getImagEigenvalues</code> method has been removed</li>
+ *   <li>a {@link #getDeterminant() getDeterminant} method has been added.</li>
+ *   <li>a {@link #getSolver() getSolver} method has been added.</li>
  * </ul>
  * @see <a href="http://mathworld.wolfram.com/EigenDecomposition.html">MathWorld</a>
  * @see <a href="http://en.wikipedia.org/wiki/Eigendecomposition_of_a_matrix">Wikipedia</a>
@@ -93,4 +95,16 @@
      */
     RealVector getEigenvector(int i);
 
+    /**
+     * Return the determinant of the matrix
+     * @return determinant of the matrix
+     */
+    double getDeterminant();
+
+    /**
+     * Get a solver for A &times; X = B.
+     * @return a solver
+     */
+    DecompositionSolver getSolver();
+
 }

Modified: commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenDecompositionImpl.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenDecompositionImpl.java?rev=728686&r1=728685&r2=728686&view=diff
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenDecompositionImpl.java (original)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenDecompositionImpl.java Mon Dec 22 05:30:10 2008
@@ -55,7 +55,7 @@
 public class EigenDecompositionImpl implements EigenDecomposition {
 
     /** Serializable version identifier. */
-    private static final long serialVersionUID = 3125911889630623276L;
+    private static final long serialVersionUID = 1625101476333719659L;
 
     /** Tolerance. */
     private static final double TOLERANCE = 100 * MathUtils.EPSILON;
@@ -301,6 +301,202 @@
     }
 
     /**
+     * Return the determinant of the matrix
+     * @return determinant of the matrix
+     * @see #isNonSingular()
+     */
+    public double getDeterminant() {
+        double determinant = 1;
+        for (double lambda : eigenvalues) {
+            determinant *= lambda;
+        }
+        return determinant;
+    }
+
+    /** {@inheritDoc} */
+    public DecompositionSolver getSolver() {
+        if (eigenvectors == null) {
+            findEigenVectors();
+        }
+        return new Solver(eigenvalues, eigenvectors);
+    }
+
+    /** Specialized solver. */
+    private static class Solver implements DecompositionSolver {
+
+        /** Serializable version identifier. */
+        private static final long serialVersionUID = -8965845906036558410L;
+
+        /** Eigenvalues. */
+        private final double[] eigenvalues;
+
+        /** Eigenvectors. */
+        private final RealVectorImpl[] eigenvectors;
+
+        /**
+         * Build a solver from decomposed matrix.
+         * @param eigenvalues eigenvalues
+         * @param eigenvectors eigenvectors
+         */
+        private Solver(final double[] eigenvalues, final RealVectorImpl[] eigenvectors) {
+            this.eigenvalues  = eigenvalues;
+            this.eigenvectors = eigenvectors; 
+        }
+
+        /** Solve the linear equation A &times; X = B for symmetric matrices A.
+         * <p>This method only find exact linear solutions, i.e. solutions for
+         * which ||A &times; X - B|| is exactly 0.</p>
+         * @param b right-hand side of the equation A &times; X = B
+         * @return a vector X that minimizes the two norm of A &times; X - B
+         * @exception IllegalArgumentException if matrices dimensions don't match
+         * @exception InvalidMatrixException if decomposed matrix is singular
+         */
+        public double[] solve(final double[] b)
+            throws IllegalArgumentException, InvalidMatrixException {
+
+            if (!isNonSingular()) {
+                throw new SingularMatrixException();
+            }
+
+            final int m = eigenvalues.length;
+            if (b.length != m) {
+                throw new IllegalArgumentException("constant vector has wrong length");
+            }
+
+            final double[] bp = new double[m];
+            for (int i = 0; i < m; ++i) {
+                final RealVectorImpl v = eigenvectors[i];
+                final double[] vData = v.getDataRef();
+                final double s = v.dotProduct(b) / eigenvalues[i];
+                for (int j = 0; j < m; ++j) {
+                    bp[j] += s * vData[j];
+                }
+            }
+
+            return bp;
+
+        }
+
+        /** Solve the linear equation A &times; X = B for symmetric matrices A.
+         * <p>This method only find exact linear solutions, i.e. solutions for
+         * which ||A &times; X - B|| is exactly 0.</p>
+         * @param b right-hand side of the equation A &times; X = B
+         * @return a vector X that minimizes the two norm of A &times; X - B
+         * @exception IllegalArgumentException if matrices dimensions don't match
+         * @exception InvalidMatrixException if decomposed matrix is singular
+         */
+        public RealVector solve(final RealVector b)
+            throws IllegalArgumentException, InvalidMatrixException {
+
+            if (!isNonSingular()) {
+                throw new SingularMatrixException();
+            }
+
+            final int m = eigenvalues.length;
+            if (b.getDimension() != m) {
+                throw new IllegalArgumentException("constant vector has wrong length");
+            }
+
+            final double[] bp = new double[m];
+            for (int i = 0; i < m; ++i) {
+                final RealVectorImpl v = eigenvectors[i];
+                final double[] vData = v.getDataRef();
+                final double s = v.dotProduct(b) / eigenvalues[i];
+                for (int j = 0; j < m; ++j) {
+                    bp[j] += s * vData[j];
+                }
+            }
+
+            return new RealVectorImpl(bp, false);
+
+        }
+
+        /** Solve the linear equation A &times; X = B for symmetric matrices A.
+         * <p>This method only find exact linear solutions, i.e. solutions for
+         * which ||A &times; X - B|| is exactly 0.</p>
+         * @param b right-hand side of the equation A &times; X = B
+         * @return a matrix X that minimizes the two norm of A &times; X - B
+         * @exception IllegalArgumentException if matrices dimensions don't match
+         * @exception InvalidMatrixException if decomposed matrix is singular
+         */
+        public RealMatrix solve(final RealMatrix b)
+            throws IllegalArgumentException, InvalidMatrixException {
+
+            if (!isNonSingular()) {
+                throw new SingularMatrixException();
+            }
+
+            final int m = eigenvalues.length;
+            if (b.getRowDimension() != m) {
+                throw new IllegalArgumentException("Incorrect row dimension");
+            }
+
+            final int nColB = b.getColumnDimension();
+            final double[][] bp = new double[m][nColB];
+            for (int k = 0; k < nColB; ++k) {
+                for (int i = 0; i < m; ++i) {
+                    final RealVectorImpl v = eigenvectors[i];
+                    final double[] vData = v.getDataRef();
+                    double s = 0;
+                    for (int j = 0; j < m; ++j) {
+                        s += v.getEntry(j) * b.getEntry(j, k);
+                    }
+                    s /= eigenvalues[i];
+                    for (int j = 0; j < m; ++j) {
+                        bp[j][k] += s * vData[j];
+                    }
+                }
+            }
+
+            return MatrixUtils.createRealMatrix(bp);
+
+        }
+
+        /**
+         * Check if the decomposed matrix is non-singular.
+         * @return true if the decomposed matrix is non-singular
+         */
+        public boolean isNonSingular() {
+            for (double lambda : eigenvalues) {
+                if (lambda == 0) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /** Get the inverse of the decomposed matrix.
+         * @return inverse matrix
+         * @throws InvalidMatrixException if decomposed matrix is singular
+         */
+        public RealMatrix getInverse()
+            throws InvalidMatrixException {
+
+            if (!isNonSingular()) {
+                throw new SingularMatrixException();
+            }
+
+            final int m = eigenvalues.length;
+            final double[][] invData = new double[m][m];
+
+            for (int i = 0; i < m; ++i) {
+                final double[] invI = invData[i];
+                for (int j = 0; j < m; ++j) {
+                    double invIJ = 0;
+                    for (int k = 0; k < m; ++k) {
+                        final double[] vK = eigenvectors[k].getDataRef();
+                        invIJ += vK[i] * vK[j] / eigenvalues[k];
+                    }
+                    invI[j] = invIJ;
+                }
+            }
+            return MatrixUtils.createRealMatrix(invData);
+
+        }
+
+    }
+
+    /**
      * Transform matrix to tridiagonal.
      * @param matrix matrix to transform
      */

Modified: commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenSolver.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenSolver.java?rev=728686&r1=728685&r2=728686&view=diff
==============================================================================
--- commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenSolver.java (original)
+++ commons/proper/math/trunk/src/java/org/apache/commons/math/linear/EigenSolver.java Mon Dec 22 05:30:10 2008
@@ -29,17 +29,21 @@
 public class EigenSolver implements DecompositionSolver {
 
     /** Serializable version identifier. */
-    private static final long serialVersionUID = 4339008311386325953L;
+    private static final long serialVersionUID = -74798755223915020L;
 
-    /** Underlying decomposition. */
-    private final EigenDecomposition decomposition;
+    /** Underlying solver. */
+    private final DecompositionSolver solver;
+
+    /** Determinant. */
+    private final double determinant;
 
     /**
      * Simple constructor.
      * @param decomposition decomposition to use
      */
     public EigenSolver(final EigenDecomposition decomposition) {
-        this.decomposition = decomposition;
+        this.solver      = decomposition.getSolver();
+        this.determinant = decomposition.getDeterminant();
     }
 
     /** Solve the linear equation A &times; X = B for symmetric matrices A.
@@ -52,28 +56,7 @@
      */
     public double[] solve(final double[] b)
         throws IllegalArgumentException, InvalidMatrixException {
-
-        if (!isNonSingular()) {
-            throw new SingularMatrixException();
-        }
-
-        final double[] eigenvalues = decomposition.getEigenvalues();
-        final int m = eigenvalues.length;
-        if (b.length != m) {
-            throw new IllegalArgumentException("constant vector has wrong length");
-        }
-
-        final double[] bp = new double[m];
-        for (int i = 0; i < m; ++i) {
-            final RealVector v = decomposition.getEigenvector(i);
-            final double s = v.dotProduct(b) / eigenvalues[i];
-            for (int j = 0; j < m; ++j) {
-                bp[j] += s * v.getEntry(j);
-            }
-        }
-
-        return bp;
-
+        return solver.solve(b);
     }
 
     /** Solve the linear equation A &times; X = B for symmetric matrices A.
@@ -86,28 +69,7 @@
      */
     public RealVector solve(final RealVector b)
         throws IllegalArgumentException, InvalidMatrixException {
-
-        if (!isNonSingular()) {
-            throw new SingularMatrixException();
-        }
-
-        final double[] eigenvalues = decomposition.getEigenvalues();
-        final int m = eigenvalues.length;
-        if (b.getDimension() != m) {
-            throw new IllegalArgumentException("constant vector has wrong length");
-        }
-
-        final double[] bp = new double[m];
-        for (int i = 0; i < m; ++i) {
-            final RealVector v = decomposition.getEigenvector(i);
-            final double s = v.dotProduct(b) / eigenvalues[i];
-            for (int j = 0; j < m; ++j) {
-                bp[j] += s * v.getEntry(j);
-            }
-        }
-
-        return new RealVectorImpl(bp, false);
-
+        return solver.solve(b);
     }
 
     /** Solve the linear equation A &times; X = B for symmetric matrices A.
@@ -120,35 +82,7 @@
      */
     public RealMatrix solve(final RealMatrix b)
         throws IllegalArgumentException, InvalidMatrixException {
-
-        if (!isNonSingular()) {
-            throw new SingularMatrixException();
-        }
-
-        final double[] eigenvalues = decomposition.getEigenvalues();
-        final int m = eigenvalues.length;
-        if (b.getRowDimension() != m) {
-            throw new IllegalArgumentException("Incorrect row dimension");
-        }
-
-        final int nColB = b.getColumnDimension();
-        final double[][] bp = new double[m][nColB];
-        for (int k = 0; k < nColB; ++k) {
-            for (int i = 0; i < m; ++i) {
-                final RealVector v = decomposition.getEigenvector(i);
-                double s = 0;
-                for (int j = 0; j < m; ++j) {
-                    s += v.getEntry(j) * b.getEntry(j, k);
-                }
-                s /= eigenvalues[i];
-                for (int j = 0; j < m; ++j) {
-                    bp[j][k] += s * v.getEntry(j);
-                }
-            }
-        }
-
-        return MatrixUtils.createRealMatrix(bp);
-
+        return solver.solve(b);
     }
 
     /**
@@ -157,10 +91,6 @@
      * @see #isNonSingular()
      */
     public double getDeterminant() {
-        double determinant = 1;
-        for (double lambda : decomposition.getEigenvalues()) {
-            determinant *= lambda;
-        }
         return determinant;
     }
 
@@ -169,12 +99,7 @@
      * @return true if the decomposed matrix is non-singular
      */
     public boolean isNonSingular() {
-        for (double lambda : decomposition.getEigenvalues()) {
-            if (lambda == 0) {
-                return false;
-            }
-        }
-        return true;
+        return solver.isNonSingular();
     }
 
     /** Get the inverse of the decomposed matrix.
@@ -183,28 +108,7 @@
      */
     public RealMatrix getInverse()
         throws InvalidMatrixException {
-
-        if (!isNonSingular()) {
-            throw new SingularMatrixException();
-        }
-
-        final double[] eigenvalues = decomposition.getEigenvalues();
-        final int m = eigenvalues.length;
-        final double[][] invData = new double[m][m];
-
-        for (int i = 0; i < m; ++i) {
-            final double[] invI = invData[i];
-            for (int j = 0; j < m; ++j) {
-                double invIJ = 0;
-                for (int k = 0; k < m; ++k) {
-                    final RealVector vK = decomposition.getEigenvector(k);
-                    invIJ += vK.getEntry(i) * vK.getEntry(j) / eigenvalues[k];
-                }
-                invI[j] = invIJ;
-            }
-        }
-        return MatrixUtils.createRealMatrix(invData);
-
+        return solver.getInverse();
     }
 
 }