Author: luc
Date: Tue Aug 19 14:41:17 2008
New Revision: 687167
URL: http://svn.apache.org/viewvc?rev=687167&view=rev
Log:
Started work on JAMA-like interfaces.
This first step is an enhancement of the existing QR-decomposition interface
and associated implementation in JAMA-style, i.e with added getH() method and
most importantly various solve methods for least-squares solution of the A * X
= B equation.
JIRA: MATH-220
Added:
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/DecompositionSolver.java
(with props)
Modified:
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/QRDecomposition.java
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/QRDecompositionImpl.java
commons/proper/math/branches/MATH_2_0/src/site/xdoc/changes.xml
commons/proper/math/branches/MATH_2_0/src/test/org/apache/commons/math/linear/QRDecompositionImplTest.java
commons/proper/math/branches/MATH_2_0/src/test/org/apache/commons/math/linear/RealVectorImplTest.java
Added:
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/DecompositionSolver.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/DecompositionSolver.java?rev=687167&view=auto
==============================================================================
---
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/DecompositionSolver.java
(added)
+++
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/DecompositionSolver.java
Tue Aug 19 14:41:17 2008
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math.linear;
+
+import java.io.Serializable;
+
+/**
+ * A base interface to decomposition algorithms that can solve A × X = B.
+ * <p>This interface is the common base of decomposition algorithms like
+ * [EMAIL PROTECTED] QRDecomposition} or [EMAIL PROTECTED] LUDecomposition}.
All these algorithms
+ * decompose an A matrix has a product of several specific matrices from
+ * which they can solve A × X = B.</p>
+ * <p>Depending on the solver, the solution is either an exact linear solution
+ * or a least squares solution. When an exact linear solution exist, both the
+ * linear and the least squares solution are equal. When no exact linear
solution
+ * exist, a least square solution gives an X which such that A × X is the
+ * closest possible to B.</p>
+ *
+ * @version $Revision$ $Date$
+ * @since 2.0
+ */
+public interface DecompositionSolver extends Serializable {
+
+ /** Solve the linear equation A × X = B.
+ * <p>The A matrix is implicit here. It is </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
+ * @throws IllegalArgumentException if matrices dimensions don't match
+ * @throws InvalidMatrixException if decomposed matrix is singular
+ */
+ double[] solve(double[] b)
+ throws IllegalArgumentException, InvalidMatrixException;
+
+ /** Solve the linear equation A × X = B.
+ * <p>The A matrix is implicit here. It is </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
+ * @throws IllegalArgumentException if matrices dimensions don't match
+ * @throws InvalidMatrixException if decomposed matrix is singular
+ */
+ RealVector solve(RealVector b)
+ throws IllegalArgumentException, InvalidMatrixException;
+
+ /** Solve the linear equation A × X = B.
+ * <p>The A matrix is implicit here. It is </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
+ * @throws IllegalArgumentException if matrices dimensions don't match
+ * @throws InvalidMatrixException if decomposed matrix is singular
+ */
+ RealMatrix solve(RealMatrix b)
+ throws IllegalArgumentException, InvalidMatrixException;
+
+}
Propchange:
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/DecompositionSolver.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/DecompositionSolver.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Modified:
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/QRDecomposition.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/QRDecomposition.java?rev=687167&r1=687166&r2=687167&view=diff
==============================================================================
---
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/QRDecomposition.java
(original)
+++
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/QRDecomposition.java
Tue Aug 19 14:41:17 2008
@@ -20,25 +20,43 @@
/**
* An interface to classes that implement a algorithm to calculate the
* QR-decomposition of a real matrix.
+ * <p>This interface is similar to the class with similar name from the now
defunct
+ * <a href="http://math.nist.gov/javanumerics/jama/">JAMA</a> library.</p>
*
* @see <a
href="http://mathworld.wolfram.com/QRDecomposition.html">MathWorld</a>
* @see <a href="http://en.wikipedia.org/wiki/QR_decomposition">Wikipedia</a>
* @version $Revision$ $Date$
* @since 1.2
*/
-public interface QRDecomposition {
+public interface QRDecomposition extends DecompositionSolver {
/**
* Returns the matrix R of the decomposition.
- *
+ * <p>R is an upper-triangular matrix</p>
* @return the R matrix
*/
- public abstract RealMatrix getR();
+ RealMatrix getR();
/**
* Returns the matrix Q of the decomposition.
- *
+ * <p>Q is an orthogonal matrix</p>
* @return the Q matrix
*/
- public abstract RealMatrix getQ();
+ RealMatrix getQ();
+
+ /**
+ * Returns the Householder reflector vectors.
+ * <p>H is a lower trapezoidal matrix whose columns represent
+ * each successive Householder reflector vector. This matrix is used
+ * to compute Q.</p>
+ * @return a matrix containing the Householder reflector vectors
+ */
+ RealMatrix getH();
+
+ /**
+ * Check if the decomposed matrix is full rank.
+ * @return true if the decomposed matrix is full rank
+ */
+ boolean isFullRank();
+
}
Modified:
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/QRDecompositionImpl.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/QRDecompositionImpl.java?rev=687167&r1=687166&r2=687167&view=diff
==============================================================================
---
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/QRDecompositionImpl.java
(original)
+++
commons/proper/math/branches/MATH_2_0/src/java/org/apache/commons/math/linear/QRDecompositionImpl.java
Tue Aug 19 14:41:17 2008
@@ -33,29 +33,41 @@
*/
public class QRDecompositionImpl implements QRDecomposition {
+ /** Serializable version identifier. */
+ private static final long serialVersionUID = 3965943878043764074L;
+
/**
* A packed representation of the QR decomposition. The elements above the
* diagonal are the elements of R, and the columns of the lower triangle
* are the Householder reflector vectors of which an explicit form of Q can
* be calculated.
*/
- private double[][] qr;
+ private final double[][] qr;
/**
* The diagonal elements of R.
*/
- private double[] rDiag;
+ private final double[] rDiag;
+
+ /** Cached value of Q. */
+ private RealMatrix cachedQ;
+
+ /** Cached value of R. */
+ private RealMatrix cachedR;
+
+ /** Cached value of H. */
+ private RealMatrix cachedH;
/**
* The row dimension of the given matrix. The size of Q will be m x m, the
* size of R will be m x n.
*/
- private int m;
+ private final int m;
/**
* The column dimension of the given matrix. The size of R will be m x n.
*/
- private int n;
+ private final int n;
/**
* Calculates the QR decomposition of the given matrix.
@@ -67,6 +79,9 @@
n = matrix.getColumnDimension();
qr = matrix.getData();
rDiag = new double[n];
+ cachedQ = null;
+ cachedR = null;
+ cachedH = null;
/*
* The QR decomposition of a matrix A is calculated using Householder
@@ -83,10 +98,10 @@
*/
double xNormSqr = 0;
for (int row = minor; row < m; row++) {
- xNormSqr += qr[row][minor]*qr[row][minor];
+ final double c = qr[row][minor];
+ xNormSqr += c * c;
}
- double a = Math.sqrt(xNormSqr);
- if (qr[minor][minor] > 0) a = -a;
+ final double a = (qr[minor][minor] > 0) ? -Math.sqrt(xNormSqr) :
Math.sqrt(xNormSqr);
rDiag[minor] = a;
if (a != 0.0) {
@@ -113,80 +128,240 @@
* |v|^2 = -2a*(qr[minor][minor]), so
* alpha = -<x,v>/(a*qr[minor][minor])
*/
- for (int col = minor+1; col < n; col++) {
+ for (int col = minor + 1; col < n; col++) {
double alpha = 0;
for (int row = minor; row < m; row++) {
- alpha -= qr[row][col]*qr[row][minor];
+ final double[] qrRow = qr[row];
+ alpha -= qrRow[col] * qrRow[minor];
}
- alpha /= a*qr[minor][minor];
+ alpha /= a * qr[minor][minor];
// Subtract the column vector alpha*v from x.
for (int row = minor; row < m; row++) {
- qr[row][col] -= alpha*qr[row][minor];
+ final double[] qrRow = qr[row];
+ qrRow[col] -= alpha * qrRow[minor];
}
}
}
}
}
- /**
- * Returns the matrix R of the QR-decomposition.
- *
- * @return the R matrix
- */
- public RealMatrix getR()
- {
- // R is supposed to be m x n
- RealMatrixImpl ret = new RealMatrixImpl(m,n);
- double[][] r = ret.getDataRef();
-
- // copy the diagonal from rDiag and the upper triangle of qr
- for (int row = Math.min(m,n)-1; row >= 0; row--) {
- r[row][row] = rDiag[row];
- for (int col = row+1; col < n; col++) {
- r[row][col] = qr[row][col];
+ /** [EMAIL PROTECTED] */
+ public RealMatrix getR() {
+
+ if (cachedR == null) {
+
+ // R is supposed to be m x n
+ double[][] r = new double[m][n];
+
+ // copy the diagonal from rDiag and the upper triangle of qr
+ for (int row = Math.min(m,n)-1; row >= 0; row--) {
+ final double[] rRow = r[row];
+ rRow[row] = rDiag[row];
+ System.arraycopy(qr[row], row + 1, rRow, row + 1, n - row - 1);
}
+
+ // cache the matrix for subsequent calls
+ cachedR = new RealMatrixImpl(r, false);
+
}
- return ret;
+
+ // return the cached matrix
+ return cachedR;
+
}
- /**
- * Returns the matrix Q of the QR-decomposition.
- *
- * @return the Q matrix
- */
- public RealMatrix getQ()
- {
- // Q is supposed to be m x m
- RealMatrixImpl ret = new RealMatrixImpl(m,m);
- double[][] Q = ret.getDataRef();
-
- /*
- * Q = Q1 Q2 ... Q_m, so Q is formed by first constructing Q_m and
then
- * applying the Householder transformations Q_(m-1),Q_(m-2),...,Q1 in
- * succession to the result
- */
- for (int minor = m-1; minor >= Math.min(m,n); minor--) {
- Q[minor][minor]=1;
- }
-
- for (int minor = Math.min(m,n)-1; minor >= 0; minor--){
- Q[minor][minor] = 1;
- if (qr[minor][minor] != 0.0) {
- for (int col = minor; col < m; col++) {
- double alpha = 0;
- for (int row = minor; row < m; row++) {
- alpha -= Q[row][col] * qr[row][minor];
- }
- alpha /= rDiag[minor]*qr[minor][minor];
+ /** [EMAIL PROTECTED] */
+ public RealMatrix getQ() {
- for (int row = minor; row < m; row++) {
- Q[row][col] -= alpha*qr[row][minor];
+ if (cachedQ == null) {
+
+ // Q is supposed to be m x m
+ double[][] Q = new double[m][m];
+
+ /*
+ * Q = Q1 Q2 ... Q_m, so Q is formed by first constructing Q_m and
then
+ * applying the Householder transformations Q_(m-1),Q_(m-2),...,Q1
in
+ * succession to the result
+ */
+ for (int minor = m-1; minor >= Math.min(m,n); minor--) {
+ Q[minor][minor]=1;
+ }
+
+ for (int minor = Math.min(m,n)-1; minor >= 0; minor--){
+ Q[minor][minor] = 1;
+ if (qr[minor][minor] != 0.0) {
+ for (int col = minor; col < m; col++) {
+ double alpha = 0;
+ for (int row = minor; row < m; row++) {
+ alpha -= Q[row][col] * qr[row][minor];
+ }
+ alpha /= rDiag[minor]*qr[minor][minor];
+
+ for (int row = minor; row < m; row++) {
+ Q[row][col] -= alpha*qr[row][minor];
+ }
}
}
}
+
+ // cache the matrix for subsequent calls
+ cachedQ = new RealMatrixImpl(Q, false);
+
}
- return ret;
+ // return the cached matrix
+ return cachedQ;
+
}
+
+ /** [EMAIL PROTECTED] */
+ public RealMatrix getH() {
+ if (cachedH == null) {
+
+ double[][] hData = new double[m][n];
+ for (int i = 0; i < m; ++i) {
+ for (int j = 0; j < Math.min(i + 1, n); ++j) {
+ hData[i][j] = qr[i][j] / -rDiag[j];
+ }
+ }
+
+ // cache the matrix for subsequent calls
+ cachedH = new RealMatrixImpl(hData, false);
+
+ }
+
+ // return the cached matrix
+ return cachedH;
+
+ }
+
+ /** [EMAIL PROTECTED] */
+ public boolean isFullRank() {
+ for (double diag : rDiag) {
+ if (diag == 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** [EMAIL PROTECTED] */
+ public double[] solve(double[] b)
+ throws IllegalArgumentException, InvalidMatrixException {
+
+ if (b.length != m) {
+ throw new IllegalArgumentException("Incorrect row dimension");
+ }
+ if (!isFullRank()) {
+ throw new InvalidMatrixException("Matrix is rank-deficient");
+ }
+
+ final double[] x = new double[n];
+ final double[] y = b.clone();
+
+ // apply Householder transforms to solve Q.y = b
+ for (int minor = 0; minor < Math.min(m, n); minor++) {
+
+ double dotProduct = 0;
+ for (int row = minor; row < m; row++) {
+ dotProduct += y[row] * qr[row][minor];
+ }
+ dotProduct /= rDiag[minor] * qr[minor][minor];
+
+ for (int row = minor; row < m; row++) {
+ y[row] += dotProduct * qr[row][minor];
+ }
+
+ }
+
+ // solve triangular system R.x = y
+ for (int row = n - 1; row >= 0; --row) {
+ y[row] /= rDiag[row];
+ final double yRow = y[row];
+ x[row] = yRow;
+ for (int i = 0; i < row; i++) {
+ y[i] -= yRow * qr[i][row];
+ }
+ }
+
+ return x;
+
+ }
+
+ /** [EMAIL PROTECTED] */
+ public RealVector solve(RealVector b)
+ throws IllegalArgumentException, InvalidMatrixException {
+ try {
+ return solve((RealVectorImpl) b);
+ } catch (ClassCastException cce) {
+ return new RealVectorImpl(solve(b.getData()), false);
+ }
+ }
+
+ /** Solve the linear equation A × X = B.
+ * <p>The A matrix is implicit here. It is </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
+ * @throws IllegalArgumentException if matrices dimensions don't match
+ * @throws InvalidMatrixException if decomposed matrix is singular
+ */
+ public RealVectorImpl solve(RealVectorImpl b)
+ throws IllegalArgumentException, InvalidMatrixException {
+ return new RealVectorImpl(solve(b.getDataRef()), false);
+ }
+
+ /** [EMAIL PROTECTED] */
+ public RealMatrix solve(RealMatrix b)
+ throws IllegalArgumentException, InvalidMatrixException {
+
+ if (b.getRowDimension() != m) {
+ throw new IllegalArgumentException("Incorrect row dimension");
+ }
+ if (!isFullRank()) {
+ throw new InvalidMatrixException("Matrix is rank-deficient");
+ }
+
+ final int cols = b.getColumnDimension();
+ final double[][] xData = new double[n][cols];
+ final double[] y = new double[b.getRowDimension()];
+
+ for (int k = 0; k < cols; ++k) {
+
+ // get the right hand side vector
+ for (int j = 0; j < y.length; ++j) {
+ y[j] = b.getEntry(j, k);
+ }
+
+ // apply Householder transforms to solve Q.y = b
+ for (int minor = 0; minor < Math.min(m, n); minor++) {
+
+ double dotProduct = 0;
+ for (int row = minor; row < m; row++) {
+ dotProduct += y[row] * qr[row][minor];
+ }
+ dotProduct /= rDiag[minor] * qr[minor][minor];
+
+ for (int row = minor; row < m; row++) {
+ y[row] += dotProduct * qr[row][minor];
+ }
+
+ }
+
+ // solve triangular system R.x = y
+ for (int row = n - 1; row >= 0; --row) {
+ y[row] /= rDiag[row];
+ final double yRow = y[row];
+ xData[row][k] = yRow;
+ for (int i = 0; i < row; i++) {
+ y[i] -= yRow * qr[i][row];
+ }
+ }
+
+ }
+
+ return new RealMatrixImpl(xData, false);
+
+ }
+
}
Modified: commons/proper/math/branches/MATH_2_0/src/site/xdoc/changes.xml
URL:
http://svn.apache.org/viewvc/commons/proper/math/branches/MATH_2_0/src/site/xdoc/changes.xml?rev=687167&r1=687166&r2=687167&view=diff
==============================================================================
--- commons/proper/math/branches/MATH_2_0/src/site/xdoc/changes.xml (original)
+++ commons/proper/math/branches/MATH_2_0/src/site/xdoc/changes.xml Tue Aug 19
14:41:17 2008
@@ -39,6 +39,13 @@
</properties>
<body>
<release version="2.0" date="TBD" description="TBD">
+ <action dev="luc" type="add" issue="MATH-220" >
+ Added JAMA-like interfaces for decomposition algorithms. These
interfaces
+ decompose a matrix as a product of several other matrices with
predefined
+ properties and shapes depending on the algorithm. These algorithms
allow to
+ solve the equation A * X = B, either for an exact linear solution
+ (LU-decomposition) or an exact or least-squares solution
(QR-decomposition).
+ </action>
<action dev="luc" type="add" issue="MATH-219" due-to="Andrew Berry">
Added removeData methods for the SimpleRegression class. This allows
to support regression calculations across a sliding window of
(time-based)
Modified:
commons/proper/math/branches/MATH_2_0/src/test/org/apache/commons/math/linear/QRDecompositionImplTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/branches/MATH_2_0/src/test/org/apache/commons/math/linear/QRDecompositionImplTest.java?rev=687167&r1=687166&r2=687167&view=diff
==============================================================================
---
commons/proper/math/branches/MATH_2_0/src/test/org/apache/commons/math/linear/QRDecompositionImplTest.java
(original)
+++
commons/proper/math/branches/MATH_2_0/src/test/org/apache/commons/math/linear/QRDecompositionImplTest.java
Tue Aug 19 14:41:17 2008
@@ -146,6 +146,13 @@
assertEquals("R lower triangle", R.getEntry(i, j), 0,
entryTolerance);
+ matrix = new RealMatrixImpl(testData3x3Singular, false);
+ R = new QRDecompositionImpl(matrix).getR();
+ for (int i = 0; i < R.getRowDimension(); i++)
+ for (int j = 0; j < i; j++)
+ assertEquals("R lower triangle", R.getEntry(i, j), 0,
+ entryTolerance);
+
matrix = new RealMatrixImpl(testData3x4, false);
R = new QRDecompositionImpl(matrix).getR();
for (int i = 0; i < R.getRowDimension(); i++)
@@ -160,4 +167,186 @@
assertEquals("R lower triangle", R.getEntry(i, j), 0,
entryTolerance);
}
+
+ /** test that H is trapezoidal */
+ public void testHTrapezoidal() {
+ RealMatrixImpl matrix = new RealMatrixImpl(testData3x3NonSingular,
false);
+ RealMatrix H = new QRDecompositionImpl(matrix).getH();
+ for (int i = 0; i < H.getRowDimension(); i++)
+ for (int j = i + 1; j < H.getColumnDimension(); j++)
+ assertEquals(H.getEntry(i, j), 0, entryTolerance);
+
+ matrix = new RealMatrixImpl(testData3x3Singular, false);
+ H = new QRDecompositionImpl(matrix).getH();
+ for (int i = 0; i < H.getRowDimension(); i++)
+ for (int j = i + 1; j < H.getColumnDimension(); j++)
+ assertEquals(H.getEntry(i, j), 0, entryTolerance);
+
+ matrix = new RealMatrixImpl(testData3x4, false);
+ H = new QRDecompositionImpl(matrix).getH();
+ for (int i = 0; i < H.getRowDimension(); i++)
+ for (int j = i + 1; j < H.getColumnDimension(); j++)
+ assertEquals(H.getEntry(i, j), 0, entryTolerance);
+
+ matrix = new RealMatrixImpl(testData4x3, false);
+ H = new QRDecompositionImpl(matrix).getH();
+ for (int i = 0; i < H.getRowDimension(); i++)
+ for (int j = i + 1; j < H.getColumnDimension(); j++)
+ assertEquals(H.getEntry(i, j), 0, entryTolerance);
+
+ }
+
+ /** test rank */
+ public void testRank() {
+ QRDecomposition qr =
+ new QRDecompositionImpl(new RealMatrixImpl(testData3x3NonSingular,
false));
+ assertTrue(qr.isFullRank());
+
+ qr = new QRDecompositionImpl(new RealMatrixImpl(testData3x3Singular,
false));
+ assertFalse(qr.isFullRank());
+
+ qr = new QRDecompositionImpl(new RealMatrixImpl(testData3x4, false));
+ assertFalse(qr.isFullRank());
+
+ qr = new QRDecompositionImpl(new RealMatrixImpl(testData4x3, false));
+ assertTrue(qr.isFullRank());
+
+ }
+
+ /** test solve dimension errors */
+ public void testSolveDimensionErrors() {
+ QRDecomposition qr =
+ new QRDecompositionImpl(new RealMatrixImpl(testData3x3NonSingular,
false));
+ RealMatrix b = new RealMatrixImpl(new double[2][2]);
+ try {
+ qr.solve(b);
+ fail("an exception should have been thrown");
+ } catch (IllegalArgumentException iae) {
+ // expected behavior
+ } catch (Exception e) {
+ fail("wrong exception caught");
+ }
+ try {
+ qr.solve(b.getColumn(0));
+ fail("an exception should have been thrown");
+ } catch (IllegalArgumentException iae) {
+ // expected behavior
+ } catch (Exception e) {
+ fail("wrong exception caught");
+ }
+ try {
+ qr.solve(b.getColumnVector(0));
+ fail("an exception should have been thrown");
+ } catch (IllegalArgumentException iae) {
+ // expected behavior
+ } catch (Exception e) {
+ fail("wrong exception caught");
+ }
+ }
+
+ /** test solve rank errors */
+ public void testSolveRankErrors() {
+ QRDecomposition qr =
+ new QRDecompositionImpl(new RealMatrixImpl(testData3x3Singular,
false));
+ RealMatrix b = new RealMatrixImpl(new double[3][2]);
+ try {
+ qr.solve(b);
+ fail("an exception should have been thrown");
+ } catch (InvalidMatrixException iae) {
+ // expected behavior
+ } catch (Exception e) {
+ fail("wrong exception caught");
+ }
+ try {
+ qr.solve(b.getColumn(0));
+ fail("an exception should have been thrown");
+ } catch (InvalidMatrixException iae) {
+ // expected behavior
+ } catch (Exception e) {
+ fail("wrong exception caught");
+ }
+ try {
+ qr.solve(b.getColumnVector(0));
+ fail("an exception should have been thrown");
+ } catch (InvalidMatrixException iae) {
+ // expected behavior
+ } catch (Exception e) {
+ fail("wrong exception caught");
+ }
+ }
+
+ /** test solve */
+ public void testSolve() {
+ QRDecomposition qr =
+ new QRDecompositionImpl(new RealMatrixImpl(testData3x3NonSingular,
false));
+ RealMatrix b = new RealMatrixImpl(new double[][] {
+ { -102, 12250 }, { 544, 24500 }, { 167, -36750 }
+ });
+ RealMatrix xRef = new RealMatrixImpl(new double[][] {
+ { 1, 2515 }, { 2, 422 }, { -3, 898 }
+ });
+
+ // using RealMatrix
+ assertEquals(0, qr.solve(b).subtract(xRef).getNorm(), 1.0e-13);
+
+ // using double[]
+ for (int i = 0; i < b.getColumnDimension(); ++i) {
+ assertEquals(0,
+ new
RealVectorImpl(qr.solve(b.getColumn(i))).subtract(xRef.getColumnVector(i)).getNorm(),
+ 1.0e-13);
+ }
+
+ // using RealVectorImpl
+ for (int i = 0; i < b.getColumnDimension(); ++i) {
+ assertEquals(0,
+
qr.solve(b.getColumnVector(i)).subtract(xRef.getColumnVector(i)).getNorm(),
+ 1.0e-13);
+ }
+
+ // using RealVector with an alternate implementation
+ for (int i = 0; i < b.getColumnDimension(); ++i) {
+ RealVectorImplTest.RealVectorTestImpl v =
+ new RealVectorImplTest.RealVectorTestImpl(b.getColumn(i));
+ assertEquals(0,
+
qr.solve(v).subtract(xRef.getColumnVector(i)).getNorm(),
+ 1.0e-13);
+ }
+
+ }
+
+ /** test matrices values */
+ public void testMatricesValues() {
+ QRDecomposition qr =
+ new QRDecompositionImpl(new RealMatrixImpl(testData3x3NonSingular,
false));
+ RealMatrix qRef = new RealMatrixImpl(new double[][] {
+ { -12.0 / 14.0, 69.0 / 175.0, -58.0 / 175.0 },
+ { -6.0 / 14.0, -158.0 / 175.0, 6.0 / 175.0 },
+ { 4.0 / 14.0, -30.0 / 175.0, -165.0 / 175.0 }
+ });
+ RealMatrix rRef = new RealMatrixImpl(new double[][] {
+ { -14.0, -21.0, 14.0 },
+ { 0.0, -175.0, 70.0 },
+ { 0.0, 0.0, 35.0 }
+ });
+ RealMatrix hRef = new RealMatrixImpl(new double[][] {
+ { 26.0 / 14.0, 0.0, 0.0 },
+ { 6.0 / 14.0, 648.0 / 325.0, 0.0 },
+ { -4.0 / 14.0, 36.0 / 325.0, 2.0 }
+ });
+
+ // check values against known references
+ RealMatrix q = qr.getQ();
+ assertEquals(0, q.subtract(qRef).getNorm(), 1.0e-13);
+ RealMatrix r = qr.getR();
+ assertEquals(0, r.subtract(rRef).getNorm(), 1.0e-13);
+ RealMatrix h = qr.getH();
+ assertEquals(0, h.subtract(hRef).getNorm(), 1.0e-13);
+
+ // check the same cached instance is returned the second time
+ assertTrue(q == qr.getQ());
+ assertTrue(r == qr.getR());
+ assertTrue(h == qr.getH());
+
+ }
+
}
Modified:
commons/proper/math/branches/MATH_2_0/src/test/org/apache/commons/math/linear/RealVectorImplTest.java
URL:
http://svn.apache.org/viewvc/commons/proper/math/branches/MATH_2_0/src/test/org/apache/commons/math/linear/RealVectorImplTest.java?rev=687167&r1=687166&r2=687167&view=diff
==============================================================================
---
commons/proper/math/branches/MATH_2_0/src/test/org/apache/commons/math/linear/RealVectorImplTest.java
(original)
+++
commons/proper/math/branches/MATH_2_0/src/test/org/apache/commons/math/linear/RealVectorImplTest.java
Tue Aug 19 14:41:17 2008
@@ -44,7 +44,7 @@
// Testclass to test the RealVector interface
// only with enough content to support the test
- public class RealVectorTestImpl implements RealVector, Serializable {
+ public static class RealVectorTestImpl implements RealVector, Serializable
{
/** Serializable version identifier. */
private static final long serialVersionUID = 8731816072271374422L;
@@ -309,7 +309,7 @@
}
public double[] getData() {
- throw unsupported();
+ return data.clone();
}
public double dotProduct(RealVector v) throws IllegalArgumentException
{