Author: celestin
Date: Sat Sep 24 05:13:53 2011
New Revision: 1175108
URL: http://svn.apache.org/viewvc?rev=1175108&view=rev
Log:
Merged SingularValueDecomposition and SingularValueDecompositionImpl (see MATH-662).
Added:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SingularValueDecomposition.java
- copied, changed from r1175099, commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SingularValueDecompositionImpl.java
commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueDecompositionTest.java
- copied, changed from r1175099, commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueDecompositionImplTest.java
Removed:
commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SingularValueDecompositionImpl.java
commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueDecompositionImplTest.java
Modified:
commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueSolverTest.java
Copied: commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SingularValueDecomposition.java
(from r1175099, commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SingularValueDecompositionImpl.java)
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SingularValueDecomposition.java?p2=commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SingularValueDecomposition.java&p1=commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SingularValueDecompositionImpl.java&r1=1175099&r2=1175108&rev=1175108&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SingularValueDecompositionImpl.java
(original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/linear/SingularValueDecomposition.java
Sat Sep 24 05:13:53 2011
@@ -31,10 +31,27 @@ import org.apache.commons.math.util.Math
* n orthogonal matrix (hence V<sup>T</sup> is also orthogonal) where
* p=min(m,n).
* </p>
+ * <p>This class is similar to the class with similar name from the
+ * <a href="http://math.nist.gov/javanumerics/jama/">JAMA</a> library, with the
+ * following changes:</p>
+ * <ul>
+ * <li>the {@code norm2} method which has been renamed as {@link #getNorm()
+ * getNorm},</li>
+ * <li>the {@code cond} method which has been renamed as {@link
+ * #getConditionNumber() getConditionNumber},</li>
+ * <li>the {@code rank} method which has been renamed as {@link #getRank()
+ * getRank},</li>
+ * <li>a {@link #getUT() getUT} method has been added,</li>
+ * <li>a {@link #getVT() getVT} method has been added,</li>
+ * <li>a {@link #getSolver() getSolver} method has been added,</li>
+ * <li>a {@link #getCovariance(double) getCovariance} method has been added.</li>
+ * </ul>
+ * @see <a href="http://mathworld.wolfram.com/SingularValueDecomposition.html">MathWorld</a>
+ * @see <a href="http://en.wikipedia.org/wiki/Singular_value_decomposition">Wikipedia</a>
* @version $Id$
- * @since 2.0
+ * @since 2.0 (changed to concrete class in 3.0)
*/
-public class SingularValueDecompositionImpl implements SingularValueDecomposition {
+public class SingularValueDecomposition {
/** Relative threshold for small singular values. */
private static final double EPS = 0x1.0p-52;
/** Absolute threshold for small singular values. */
@@ -68,7 +85,7 @@ public class SingularValueDecompositionI
*
* @param matrix Matrix to decompose.
*/
- public SingularValueDecompositionImpl(final RealMatrix matrix) {
+ public SingularValueDecomposition(final RealMatrix matrix) {
final double[][] A;
// "m" is always the largest dimension.
@@ -459,14 +476,24 @@ public class SingularValueDecompositionI
}
}
- /** {@inheritDoc} */
+ /**
+ * Returns the matrix U of the decomposition.
+ * <p>U is an orthogonal matrix, i.e. its transpose is also its inverse.</p>
+ * @return the U matrix
+ * @see #getUT()
+ */
public RealMatrix getU() {
// return the cached matrix
return cachedU;
}
- /** {@inheritDoc} */
+ /**
+ * Returns the transpose of the matrix U of the decomposition.
+ * <p>U is an orthogonal matrix, i.e. its transpose is also its inverse.</p>
+ * @return the U matrix (or null if decomposed matrix is singular)
+ * @see #getU()
+ */
public RealMatrix getUT() {
if (cachedUt == null) {
cachedUt = getU().transpose();
@@ -475,7 +502,12 @@ public class SingularValueDecompositionI
return cachedUt;
}
- /** {@inheritDoc} */
+ /**
+ * Returns the diagonal matrix Σ of the decomposition.
+ * <p>Σ is a diagonal matrix. The singular values are provided in
+ * non-increasing order, for compatibility with Jama.</p>
+ * @return the Σ matrix
+ */
public RealMatrix getS() {
if (cachedS == null) {
// cache the matrix for subsequent calls
@@ -484,18 +516,33 @@ public class SingularValueDecompositionI
return cachedS;
}
- /** {@inheritDoc} */
+ /**
+ * Returns the diagonal elements of the matrix Σ of the decomposition.
+ * <p>The singular values are provided in non-increasing order, for
+ * compatibility with Jama.</p>
+ * @return the diagonal elements of the Σ matrix
+ */
public double[] getSingularValues() {
return singularValues.clone();
}
- /** {@inheritDoc} */
+ /**
+ * Returns the matrix V of the decomposition.
+ * <p>V is an orthogonal matrix, i.e. its transpose is also its inverse.</p>
+ * @return the V matrix (or null if decomposed matrix is singular)
+ * @see #getVT()
+ */
public RealMatrix getV() {
// return the cached matrix
return cachedV;
}
- /** {@inheritDoc} */
+ /**
+ * Returns the transpose of the matrix V of the decomposition.
+ * <p>V is an orthogonal matrix, i.e. its transpose is also its inverse.</p>
+ * @return the V matrix (or null if decomposed matrix is singular)
+ * @see #getV()
+ */
public RealMatrix getVT() {
if (cachedVt == null) {
cachedVt = getV().transpose();
@@ -504,7 +551,17 @@ public class SingularValueDecompositionI
return cachedVt;
}
- /** {@inheritDoc} */
+ /**
+ * Returns the n × n covariance matrix.
+ * <p>The covariance matrix is V × J × V<sup>T</sup>
+ * where J is the diagonal matrix of the inverse of the squares of
+ * the singular values.</p>
+ * @param minSingularValue value below which singular values are ignored
+ * (a 0 or negative value implies all singular value will be used)
+ * @return covariance matrix
+ * @exception IllegalArgumentException if minSingularValue is larger than
+ * the largest singular value, meaning all singular values are ignored
+ */
public RealMatrix getCovariance(final double minSingularValue) {
// get the number of singular values to consider
final int p = singularValues.length;
@@ -533,12 +590,21 @@ public class SingularValueDecompositionI
return jv.transpose().multiply(jv);
}
- /** {@inheritDoc} */
+ /**
+ * Returns the L<sub>2</sub> norm of the matrix.
+ * <p>The L<sub>2</sub> norm is max(|A × u|<sub>2</sub>
/
+ * |u|<sub>2</sub>), where |.|<sub>2</sub> denotes the vectorial
2-norm
+ * (i.e. the traditional euclidian norm).</p>
+ * @return norm
+ */
public double getNorm() {
return singularValues[0];
}
- /** {@inheritDoc} */
+ /**
+ * Return the condition number of the matrix.
+ * @return condition number of the matrix
+ */
public double getConditionNumber() {
return singularValues[0] / singularValues[n - 1];
}
@@ -554,7 +620,14 @@ public class SingularValueDecompositionI
return singularValues[n - 1] / singularValues[0];
}
- /** {@inheritDoc} */
+ /**
+ * Return the effective numerical matrix rank.
+ * <p>The effective numerical rank is the number of non-negligible
+ * singular values. The threshold used to identify non-negligible
+ * terms is max(m,n) × ulp(s<sub>1</sub>) where ulp(s<sub>1</sub>)
+ * is the least significant bit of the largest singular value.</p>
+ * @return effective numerical matrix rank
+ */
public int getRank() {
int r = 0;
for (int i = 0; i < singularValues.length; i++) {
@@ -565,7 +638,10 @@ public class SingularValueDecompositionI
return r;
}
- /** {@inheritDoc} */
+ /**
+ * Get a solver for finding the A × X = B solution in least square sense.
+ * @return a solver
+ */
public DecompositionSolver getSolver() {
return new Solver(singularValues, getUT(), getV(), getRank() == m, tol);
}
Copied: commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueDecompositionTest.java
(from r1175099, commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueDecompositionImplTest.java)
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueDecompositionTest.java?p2=commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueDecompositionTest.java&p1=commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueDecompositionImplTest.java&r1=1175099&r2=1175108&rev=1175108&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueDecompositionImplTest.java
(original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueDecompositionTest.java
Sat Sep 24 05:13:53 2011
@@ -27,7 +27,7 @@ import org.junit.Assert;
import org.junit.Test;
-public class SingularValueDecompositionImplTest {
+public class SingularValueDecompositionTest {
private double[][] testSquare = {
{ 24.0 / 25.0, 43.0 / 25.0 },
@@ -50,7 +50,7 @@ public class SingularValueDecompositionI
final int columns = singularValues.length;
Random r = new Random(15338437322523l);
SingularValueDecomposition svd =
- new SingularValueDecompositionImpl(createTestMatrix(r, rows, columns, singularValues));
+ new SingularValueDecomposition(createTestMatrix(r, rows, columns, singularValues));
double[] computedSV = svd.getSingularValues();
Assert.assertEquals(singularValues.length, computedSV.length);
for (int i = 0; i < singularValues.length; ++i) {
@@ -65,7 +65,7 @@ public class SingularValueDecompositionI
final int columns = singularValues.length + 2;
Random r = new Random(732763225836210l);
SingularValueDecomposition svd =
- new SingularValueDecompositionImpl(createTestMatrix(r, rows, columns, singularValues));
+ new SingularValueDecomposition(createTestMatrix(r, rows, columns, singularValues));
double[] computedSV = svd.getSingularValues();
Assert.assertEquals(singularValues.length, computedSV.length);
for (int i = 0; i < singularValues.length; ++i) {
@@ -79,7 +79,7 @@ public class SingularValueDecompositionI
RealMatrix matrix = MatrixUtils.createRealMatrix(testSquare);
final int m = matrix.getRowDimension();
final int n = matrix.getColumnDimension();
- SingularValueDecomposition svd = new SingularValueDecompositionImpl(matrix);
+ SingularValueDecomposition svd = new SingularValueDecomposition(matrix);
Assert.assertEquals(m, svd.getU().getRowDimension());
Assert.assertEquals(m, svd.getU().getColumnDimension());
Assert.assertEquals(m, svd.getS().getColumnDimension());
@@ -98,7 +98,7 @@ public class SingularValueDecompositionI
{ 9.0 / 2.0, 3.0 / 2.0, 15.0 / 2.0, 5.0 / 2.0 },
{ 3.0 / 2.0, 9.0 / 2.0, 5.0 / 2.0, 15.0 / 2.0 }
}, false);
- SingularValueDecomposition svd = new SingularValueDecompositionImpl(matrix);
+ SingularValueDecomposition svd = new SingularValueDecomposition(matrix);
Assert.assertEquals(16.0, svd.getSingularValues()[0], 1.0e-14);
Assert.assertEquals( 8.0, svd.getSingularValues()[1], 1.0e-14);
Assert.assertEquals( 4.0, svd.getSingularValues()[2], 1.0e-14);
@@ -135,7 +135,7 @@ public class SingularValueDecompositionI
}
public void checkAEqualUSVt(final RealMatrix matrix) {
- SingularValueDecomposition svd = new SingularValueDecompositionImpl(matrix);
+ SingularValueDecomposition svd = new SingularValueDecomposition(matrix);
RealMatrix u = svd.getU();
RealMatrix s = svd.getS();
RealMatrix v = svd.getV();
@@ -147,17 +147,17 @@ public class SingularValueDecompositionI
/** test that U is orthogonal */
@Test
public void testUOrthogonal() {
- checkOrthogonal(new SingularValueDecompositionImpl(MatrixUtils.createRealMatrix(testSquare)).getU());
- checkOrthogonal(new SingularValueDecompositionImpl(MatrixUtils.createRealMatrix(testNonSquare)).getU());
- checkOrthogonal(new SingularValueDecompositionImpl(MatrixUtils.createRealMatrix(testNonSquare).transpose()).getU());
+ checkOrthogonal(new SingularValueDecomposition(MatrixUtils.createRealMatrix(testSquare)).getU());
+ checkOrthogonal(new SingularValueDecomposition(MatrixUtils.createRealMatrix(testNonSquare)).getU());
+ checkOrthogonal(new SingularValueDecomposition(MatrixUtils.createRealMatrix(testNonSquare).transpose()).getU());
}
/** test that V is orthogonal */
@Test
public void testVOrthogonal() {
- checkOrthogonal(new SingularValueDecompositionImpl(MatrixUtils.createRealMatrix(testSquare)).getV());
- checkOrthogonal(new SingularValueDecompositionImpl(MatrixUtils.createRealMatrix(testNonSquare)).getV());
- checkOrthogonal(new SingularValueDecompositionImpl(MatrixUtils.createRealMatrix(testNonSquare).transpose()).getV());
+ checkOrthogonal(new SingularValueDecomposition(MatrixUtils.createRealMatrix(testSquare)).getV());
+ checkOrthogonal(new SingularValueDecomposition(MatrixUtils.createRealMatrix(testNonSquare)).getV());
+ checkOrthogonal(new SingularValueDecomposition(MatrixUtils.createRealMatrix(testNonSquare).transpose()).getV());
}
public void checkOrthogonal(final RealMatrix m) {
@@ -171,7 +171,7 @@ public class SingularValueDecompositionI
// together, the actual triplet (U,S,V) is not uniquely defined.
public void testMatricesValues1() {
SingularValueDecomposition svd =
- new SingularValueDecompositionImpl(MatrixUtils.createRealMatrix(testSquare));
+ new SingularValueDecomposition(MatrixUtils.createRealMatrix(testSquare));
RealMatrix uRef = MatrixUtils.createRealMatrix(new double[][] {
{ 3.0 / 5.0, -4.0 / 5.0 },
{ 4.0 / 5.0, 3.0 / 5.0 }
@@ -224,7 +224,7 @@ public class SingularValueDecompositionI
// check values against known references
SingularValueDecomposition svd =
- new SingularValueDecompositionImpl(MatrixUtils.createRealMatrix(testNonSquare));
+ new SingularValueDecomposition(MatrixUtils.createRealMatrix(testNonSquare));
RealMatrix u = svd.getU();
Assert.assertEquals(0, u.subtract(uRef).getNorm(), normTolerance);
RealMatrix s = svd.getS();
@@ -244,34 +244,34 @@ public class SingularValueDecompositionI
public void testRank() {
double[][] d = { { 1, 1, 1 }, { 0, 0, 0 }, { 1, 2, 3 } };
RealMatrix m = new Array2DRowRealMatrix(d);
- SingularValueDecomposition svd = new SingularValueDecompositionImpl(m);
- Assert.assertEquals(2, svd.getRank());
+ SingularValueDecomposition svd = new SingularValueDecomposition(m);
+ Assert.assertEquals(2, svd.getRank());
}
-
+
/** test MATH-583 */
@Test
public void testStability1() {
RealMatrix m = new Array2DRowRealMatrix(201, 201);
loadRealMatrix(m,"matrix1.csv");
try {
- new SingularValueDecompositionImpl(m);
+ new SingularValueDecomposition(m);
} catch (Exception e) {
Assert.fail("Exception whilst constructing SVD");
- }
+ }
}
-
+
/** test MATH-327 */
@Test
public void testStability2() {
RealMatrix m = new Array2DRowRealMatrix(7, 168);
loadRealMatrix(m,"matrix2.csv");
try {
- new SingularValueDecompositionImpl(m);
+ new SingularValueDecomposition(m);
} catch (Throwable e) {
Assert.fail("Exception whilst constructing SVD");
- }
+ }
}
-
+
private void loadRealMatrix(RealMatrix m, String resourceName) {
try {
DataInputStream in = new DataInputStream(getClass().getResourceAsStream(resourceName));
@@ -286,25 +286,25 @@ public class SingularValueDecompositionI
row++;
}
in.close();
- } catch (IOException e) {}
+ } catch (IOException e) {}
}
-
+
/** test condition number */
@Test
public void testConditionNumber() {
- SingularValueDecompositionImpl svd =
- new SingularValueDecompositionImpl(MatrixUtils.createRealMatrix(testSquare));
+ SingularValueDecomposition svd =
+ new SingularValueDecomposition(MatrixUtils.createRealMatrix(testSquare));
// replace 1.0e-15 with 1.5e-15
Assert.assertEquals(3.0, svd.getConditionNumber(), 1.5e-15);
}
@Test
public void testInverseConditionNumber() {
- SingularValueDecompositionImpl svd =
- new SingularValueDecompositionImpl(MatrixUtils.createRealMatrix(testSquare));
+ SingularValueDecomposition svd =
+ new SingularValueDecomposition(MatrixUtils.createRealMatrix(testSquare));
Assert.assertEquals(1.0/3.0, svd.getInverseConditionNumber(), 1.5e-15);
}
-
+
private RealMatrix createTestMatrix(final Random r, final int rows, final int columns,
final double[] singularValues) {
final RealMatrix u =
Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueSolverTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueSolverTest.java?rev=1175108&r1=1175107&r2=1175108&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueSolverTest.java
(original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/linear/SingularValueSolverTest.java
Sat Sep 24 05:13:53 2011
@@ -35,7 +35,7 @@ public class SingularValueSolverTest {
@Test
public void testSolveDimensionErrors() {
DecompositionSolver solver =
- new SingularValueDecompositionImpl(MatrixUtils.createRealMatrix(testSquare)).getSolver();
+ new SingularValueDecomposition(MatrixUtils.createRealMatrix(testSquare)).getSolver();
RealMatrix b = MatrixUtils.createRealMatrix(new double[3][2]);
try {
solver.solve(b);
@@ -65,7 +65,7 @@ public class SingularValueSolverTest {
{ 1.0, 0.0 },
{ 0.0, 0.0 }
});
- DecompositionSolver solver = new SingularValueDecompositionImpl(m).getSolver();
+ DecompositionSolver solver = new SingularValueDecomposition(m).getSolver();
RealMatrix b = MatrixUtils.createRealMatrix(new double[][] {
{ 11, 12 }, { 21, 22 }
});
@@ -86,7 +86,7 @@ public class SingularValueSolverTest {
@Test
public void testSolve() {
DecompositionSolver solver =
- new SingularValueDecompositionImpl(MatrixUtils.createRealMatrix(testSquare)).getSolver();
+ new SingularValueDecomposition(MatrixUtils.createRealMatrix(testSquare)).getSolver();
RealMatrix b = MatrixUtils.createRealMatrix(new double[][] {
{ 1, 2, 3 }, { 0, -5, 1 }
});
@@ -119,8 +119,8 @@ public class SingularValueSolverTest {
/** test condition number */
@Test
public void testConditionNumber() {
- SingularValueDecompositionImpl svd =
- new SingularValueDecompositionImpl(MatrixUtils.createRealMatrix(testSquare));
+ SingularValueDecomposition svd =
+ new SingularValueDecomposition(MatrixUtils.createRealMatrix(testSquare));
// replace 1.0e-15 with 1.5e-15
Assert.assertEquals(3.0, svd.getConditionNumber(), 1.5e-15);
}
@@ -131,7 +131,7 @@ public class SingularValueSolverTest {
{ 1.0, 2.0 }, { 1.0, 2.0 }
});
SingularValueDecomposition svd =
- new SingularValueDecompositionImpl(rm);
+ new SingularValueDecomposition(rm);
RealMatrix recomposed = svd.getU().multiply(svd.getS()).multiply(svd.getVT());
Assert.assertEquals(0.0, recomposed.subtract(rm).getNorm(), 2.0e-15);
}
|