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 × 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 × X = B for symmetric matrices A.
+ * <p>This method only find exact linear solutions, i.e. solutions for
+ * which ||A × X - B|| is exactly 0.</p>
+ * @param b right-hand side of the equation A × X = B
+ * @return a vector X that minimizes the two norm of A × 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 × X = B for symmetric matrices A.
+ * <p>This method only find exact linear solutions, i.e. solutions for
+ * which ||A × X - B|| is exactly 0.</p>
+ * @param b right-hand side of the equation A × X = B
+ * @return a vector X that minimizes the two norm of A × 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 × X = B for symmetric matrices A.
+ * <p>This method only find exact linear solutions, i.e. solutions for
+ * which ||A × X - B|| is exactly 0.</p>
+ * @param b right-hand side of the equation A × X = B
+ * @return a matrix X that minimizes the two norm of A × 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 × 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 × 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 × 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();
}
}