Author: luc Date: Sun Jan 4 10:08:50 2009 New Revision: 731308 URL: http://svn.apache.org/viewvc?rev=731308&view=rev Log: simplified tests added new tests
Modified: commons/proper/math/trunk/src/test/org/apache/commons/math/linear/QRDecompositionImplTest.java commons/proper/math/trunk/src/test/org/apache/commons/math/linear/QRSolverTest.java Modified: commons/proper/math/trunk/src/test/org/apache/commons/math/linear/QRDecompositionImplTest.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/org/apache/commons/math/linear/QRDecompositionImplTest.java?rev=731308&r1=731307&r2=731308&view=diff ============================================================================== --- commons/proper/math/trunk/src/test/org/apache/commons/math/linear/QRDecompositionImplTest.java (original) +++ commons/proper/math/trunk/src/test/org/apache/commons/math/linear/QRDecompositionImplTest.java Sun Jan 4 10:08:50 2009 @@ -17,6 +17,8 @@ package org.apache.commons.math.linear; +import java.util.Random; + import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; @@ -59,143 +61,152 @@ /** test dimensions */ public void testDimensions() { - RealMatrix matrix = MatrixUtils.createRealMatrix(testData3x3NonSingular); - QRDecomposition qr = new QRDecompositionImpl(matrix); - assertEquals("3x3 Q size", qr.getQ().getRowDimension(), 3); - assertEquals("3x3 Q size", qr.getQ().getColumnDimension(), 3); - assertEquals("3x3 R size", qr.getR().getRowDimension(), 3); - assertEquals("3x3 R size", qr.getR().getColumnDimension(), 3); + checkDimension(MatrixUtils.createRealMatrix(testData3x3NonSingular)); - matrix = MatrixUtils.createRealMatrix(testData4x3); - qr = new QRDecompositionImpl(matrix); - assertEquals("4x3 Q size", qr.getQ().getRowDimension(), 4); - assertEquals("4x3 Q size", qr.getQ().getColumnDimension(), 4); - assertEquals("4x3 R size", qr.getR().getRowDimension(), 4); - assertEquals("4x3 R size", qr.getR().getColumnDimension(), 3); + checkDimension(MatrixUtils.createRealMatrix(testData4x3)); - matrix = MatrixUtils.createRealMatrix(testData3x4); - qr = new QRDecompositionImpl(matrix); - assertEquals("3x4 Q size", qr.getQ().getRowDimension(), 3); - assertEquals("3x4 Q size", qr.getQ().getColumnDimension(), 3); - assertEquals("3x4 R size", qr.getR().getRowDimension(), 3); - assertEquals("3x4 R size", qr.getR().getColumnDimension(), 4); + checkDimension(MatrixUtils.createRealMatrix(testData3x4)); + + Random r = new Random(643895747384642l); + int p = (5 * DenseRealMatrix.BLOCK_SIZE) / 4; + int q = (7 * DenseRealMatrix.BLOCK_SIZE) / 4; + checkDimension(createTestMatrix(r, p, q)); + checkDimension(createTestMatrix(r, q, p)); + + } + + private void checkDimension(RealMatrix m) { + int rows = m.getRowDimension(); + int columns = m.getColumnDimension(); + QRDecomposition qr = new QRDecompositionImpl(m); + assertEquals(rows, qr.getQ().getRowDimension()); + assertEquals(rows, qr.getQ().getColumnDimension()); + assertEquals(rows, qr.getR().getRowDimension()); + assertEquals(columns, qr.getR().getColumnDimension()); } /** test A = QR */ public void testAEqualQR() { - RealMatrix A = MatrixUtils.createRealMatrix(testData3x3NonSingular); - QRDecomposition qr = new QRDecompositionImpl(A); - RealMatrix Q = qr.getQ(); - RealMatrix R = qr.getR(); - double norm = Q.multiply(R).subtract(A).getNorm(); - assertEquals("3x3 nonsingular A = QR", 0, norm, normTolerance); - - RealMatrix matrix = MatrixUtils.createRealMatrix(testData3x3Singular); - qr = new QRDecompositionImpl(matrix); - norm = qr.getQ().multiply(qr.getR()).subtract(matrix).getNorm(); - assertEquals("3x3 singular A = QR", 0, norm, normTolerance); + checkAEqualQR(MatrixUtils.createRealMatrix(testData3x3NonSingular)); - matrix = MatrixUtils.createRealMatrix(testData3x4); - qr = new QRDecompositionImpl(matrix); - norm = qr.getQ().multiply(qr.getR()).subtract(matrix).getNorm(); - assertEquals("3x4 A = QR", 0, norm, normTolerance); + checkAEqualQR(MatrixUtils.createRealMatrix(testData3x3Singular)); + + checkAEqualQR(MatrixUtils.createRealMatrix(testData3x4)); + + checkAEqualQR(MatrixUtils.createRealMatrix(testData4x3)); + + Random r = new Random(643895747384642l); + int p = (5 * DenseRealMatrix.BLOCK_SIZE) / 4; + int q = (7 * DenseRealMatrix.BLOCK_SIZE) / 4; + checkAEqualQR(createTestMatrix(r, p, q)); + + checkAEqualQR(createTestMatrix(r, q, p)); - matrix = MatrixUtils.createRealMatrix(testData4x3); - qr = new QRDecompositionImpl(matrix); - norm = qr.getQ().multiply(qr.getR()).subtract(matrix).getNorm(); - assertEquals("4x3 A = QR", 0, norm, normTolerance); + } + + private void checkAEqualQR(RealMatrix m) { + QRDecomposition qr = new QRDecompositionImpl(m); + double norm = qr.getQ().multiply(qr.getR()).subtract(m).getNorm(); + assertEquals(0, norm, normTolerance); } /** test the orthogonality of Q */ public void testQOrthogonal() { - RealMatrix matrix = MatrixUtils.createRealMatrix(testData3x3NonSingular); - RealMatrix q = new QRDecompositionImpl(matrix).getQ(); - RealMatrix qT = new QRDecompositionImpl(matrix).getQT(); - RealMatrix eye = MatrixUtils.createRealIdentityMatrix(3); - double norm = qT.multiply(q).subtract(eye).getNorm(); - assertEquals("3x3 nonsingular Q'Q = I", 0, norm, normTolerance); + checkQOrthogonal(MatrixUtils.createRealMatrix(testData3x3NonSingular)); - matrix = MatrixUtils.createRealMatrix(testData3x3Singular); - q = new QRDecompositionImpl(matrix).getQ(); - qT = new QRDecompositionImpl(matrix).getQT(); - eye = MatrixUtils.createRealIdentityMatrix(3); - norm = qT.multiply(q).subtract(eye).getNorm(); - assertEquals("3x3 singular Q'Q = I", 0, norm, normTolerance); + checkQOrthogonal(MatrixUtils.createRealMatrix(testData3x3Singular)); - matrix = MatrixUtils.createRealMatrix(testData3x4); - q = new QRDecompositionImpl(matrix).getQ(); - qT = new QRDecompositionImpl(matrix).getQT(); - eye = MatrixUtils.createRealIdentityMatrix(3); - norm = qT.multiply(q).subtract(eye).getNorm(); - assertEquals("3x4 Q'Q = I", 0, norm, normTolerance); + checkQOrthogonal(MatrixUtils.createRealMatrix(testData3x4)); + + checkQOrthogonal(MatrixUtils.createRealMatrix(testData4x3)); + + Random r = new Random(643895747384642l); + int p = (5 * DenseRealMatrix.BLOCK_SIZE) / 4; + int q = (7 * DenseRealMatrix.BLOCK_SIZE) / 4; + checkQOrthogonal(createTestMatrix(r, p, q)); + + checkQOrthogonal(createTestMatrix(r, q, p)); - matrix = MatrixUtils.createRealMatrix(testData4x3); - q = new QRDecompositionImpl(matrix).getQ(); - qT = new QRDecompositionImpl(matrix).getQT(); - eye = MatrixUtils.createRealIdentityMatrix(4); - norm = qT.multiply(q).subtract(eye).getNorm(); - assertEquals("4x3 Q'Q = I", 0, norm, normTolerance); + } + + private void checkQOrthogonal(RealMatrix m) { + QRDecomposition qr = new QRDecompositionImpl(m); + RealMatrix eye = MatrixUtils.createRealIdentityMatrix(m.getRowDimension()); + double norm = qr.getQT().multiply(qr.getQ()).subtract(eye).getNorm(); + assertEquals(0, norm, normTolerance); } /** test that R is upper triangular */ public void testRUpperTriangular() { RealMatrix matrix = MatrixUtils.createRealMatrix(testData3x3NonSingular); - RealMatrix 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); + checkUpperTriangular(new QRDecompositionImpl(matrix).getR()); matrix = MatrixUtils.createRealMatrix(testData3x3Singular); - 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); + checkUpperTriangular(new QRDecompositionImpl(matrix).getR()); matrix = MatrixUtils.createRealMatrix(testData3x4); - 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); + checkUpperTriangular(new QRDecompositionImpl(matrix).getR()); matrix = MatrixUtils.createRealMatrix(testData4x3); - 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); + checkUpperTriangular(new QRDecompositionImpl(matrix).getR()); + + Random r = new Random(643895747384642l); + int p = (5 * DenseRealMatrix.BLOCK_SIZE) / 4; + int q = (7 * DenseRealMatrix.BLOCK_SIZE) / 4; + matrix = createTestMatrix(r, p, q); + checkUpperTriangular(new QRDecompositionImpl(matrix).getR()); + + matrix = createTestMatrix(r, p, q); + checkUpperTriangular(new QRDecompositionImpl(matrix).getR()); + + } + + private void checkUpperTriangular(RealMatrix m) { + m.walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() { + private static final long serialVersionUID = -7685630069569815930L; + public void visit(int row, int column, double value) { + if (column < row) { + assertEquals(0.0, value, entryTolerance); + } + } + }); } /** test that H is trapezoidal */ public void testHTrapezoidal() { RealMatrix matrix = MatrixUtils.createRealMatrix(testData3x3NonSingular); - 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); + checkTrapezoidal(new QRDecompositionImpl(matrix).getH()); matrix = MatrixUtils.createRealMatrix(testData3x3Singular); - 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); + checkTrapezoidal(new QRDecompositionImpl(matrix).getH()); matrix = MatrixUtils.createRealMatrix(testData3x4); - 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); + checkTrapezoidal(new QRDecompositionImpl(matrix).getH()); matrix = MatrixUtils.createRealMatrix(testData4x3); - 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); + checkTrapezoidal(new QRDecompositionImpl(matrix).getH()); + + Random r = new Random(643895747384642l); + int p = (5 * DenseRealMatrix.BLOCK_SIZE) / 4; + int q = (7 * DenseRealMatrix.BLOCK_SIZE) / 4; + matrix = createTestMatrix(r, p, q); + checkTrapezoidal(new QRDecompositionImpl(matrix).getH()); + + matrix = createTestMatrix(r, p, q); + checkTrapezoidal(new QRDecompositionImpl(matrix).getH()); } + private void checkTrapezoidal(RealMatrix m) { + m.walkInOptimizedOrder(new DefaultRealMatrixPreservingVisitor() { + private static final long serialVersionUID = -43649044361860701L; + public void visit(int row, int column, double value) { + if (column > row) { + assertEquals(0.0, value, entryTolerance); + } + } + }); + } /** test matrices values */ public void testMatricesValues() { QRDecomposition qr = @@ -233,4 +244,16 @@ } + private RealMatrix createTestMatrix(final Random r, final int rows, final int columns) { + RealMatrix m = MatrixUtils.createRealMatrix(rows, columns); + m.walkInOptimizedOrder(new DefaultRealMatrixChangingVisitor(){ + private static final long serialVersionUID = -556118291433400034L; + public double visit(int row, int column, double value) + throws MatrixVisitorException { + return 2.0 * r.nextDouble() - 1.0; + } + }); + return m; + } + } Modified: commons/proper/math/trunk/src/test/org/apache/commons/math/linear/QRSolverTest.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/org/apache/commons/math/linear/QRSolverTest.java?rev=731308&r1=731307&r2=731308&view=diff ============================================================================== --- commons/proper/math/trunk/src/test/org/apache/commons/math/linear/QRSolverTest.java (original) +++ commons/proper/math/trunk/src/test/org/apache/commons/math/linear/QRSolverTest.java Sun Jan 4 10:08:50 2009 @@ -17,31 +17,37 @@ package org.apache.commons.math.linear; +import java.util.Random; + import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; public class QRSolverTest extends TestCase { double[][] testData3x3NonSingular = { - { 12, -51, 4 }, - { 6, 167, -68 }, - { -4, 24, -41 }, }; + { 12, -51, 4 }, + { 6, 167, -68 }, + { -4, 24, -41 } + }; double[][] testData3x3Singular = { - { 1, 4, 7, }, - { 2, 5, 8, }, - { 3, 6, 9, }, }; + { 1, 2, 2 }, + { 2, 4, 6 }, + { 4, 8, 12 } + }; double[][] testData3x4 = { - { 12, -51, 4, 1 }, - { 6, 167, -68, 2 }, - { -4, 24, -41, 3 }, }; + { 12, -51, 4, 1 }, + { 6, 167, -68, 2 }, + { -4, 24, -41, 3 } + }; double[][] testData4x3 = { - { 12, -51, 4, }, - { 6, 167, -68, }, - { -4, 24, -41, }, - { -5, 34, 7, }, }; + { 12, -51, 4 }, + { 6, 167, -68 }, + { -4, 24, -41 }, + { -5, 34, 7 } + }; public QRSolverTest(String name) { super(name); @@ -55,25 +61,25 @@ /** test rank */ public void testRank() { - QRSolver solver = - new QRSolver(new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData3x3NonSingular))); + DecompositionSolver solver = + new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData3x3NonSingular)).getSolver(); assertTrue(solver.isNonSingular()); - solver = new QRSolver(new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData3x3Singular))); + solver = new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData3x3Singular)).getSolver(); assertFalse(solver.isNonSingular()); - solver = new QRSolver(new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData3x4))); - assertFalse(solver.isNonSingular()); + solver = new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData3x4)).getSolver(); + assertTrue(solver.isNonSingular()); - solver = new QRSolver(new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData4x3))); + solver = new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData4x3)).getSolver(); assertTrue(solver.isNonSingular()); } /** test solve dimension errors */ public void testSolveDimensionErrors() { - QRSolver solver = - new QRSolver(new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData3x3NonSingular))); + DecompositionSolver solver = + new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData3x3NonSingular)).getSolver(); RealMatrix b = MatrixUtils.createRealMatrix(new double[2][2]); try { solver.solve(b); @@ -103,8 +109,8 @@ /** test solve rank errors */ public void testSolveRankErrors() { - QRSolver solver = - new QRSolver(new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData3x3Singular))); + DecompositionSolver solver = + new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData3x3Singular)).getSolver(); RealMatrix b = MatrixUtils.createRealMatrix(new double[3][2]); try { solver.solve(b); @@ -134,8 +140,9 @@ /** test solve */ public void testSolve() { - QRSolver solver = - new QRSolver(new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData3x3NonSingular))); + QRDecomposition decomposition = + new QRDecompositionImpl(MatrixUtils.createRealMatrix(testData3x3NonSingular)); + DecompositionSolver solver = decomposition.getSolver(); RealMatrix b = MatrixUtils.createRealMatrix(new double[][] { { -102, 12250 }, { 544, 24500 }, { 167, -36750 } }); @@ -144,31 +151,82 @@ }); // using RealMatrix - assertEquals(0, solver.solve(b).subtract(xRef).getNorm(), 1.0e-13); + assertEquals(0, solver.solve(b).subtract(xRef).getNorm(), 2.0e-16 * xRef.getNorm()); // using double[] for (int i = 0; i < b.getColumnDimension(); ++i) { - assertEquals(0, - new RealVectorImpl(solver.solve(b.getColumn(i))).subtract(xRef.getColumnVector(i)).getNorm(), - 1.0e-13); + final double[] x = solver.solve(b.getColumn(i)); + final double error = new RealVectorImpl(x).subtract(xRef.getColumnVector(i)).getNorm(); + assertEquals(0, error, 3.0e-16 * xRef.getColumnVector(i).getNorm()); } // using RealVectorImpl for (int i = 0; i < b.getColumnDimension(); ++i) { - assertEquals(0, - solver.solve(b.getColumnVector(i)).subtract(xRef.getColumnVector(i)).getNorm(), - 1.0e-13); + final RealVector x = solver.solve(b.getColumnVector(i)); + final double error = x.subtract(xRef.getColumnVector(i)).getNorm(); + assertEquals(0, error, 3.0e-16 * xRef.getColumnVector(i).getNorm()); } // 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, - solver.solve(v).subtract(xRef.getColumnVector(i)).getNorm(), - 1.0e-13); + final RealVector x = solver.solve(v); + final double error = x.subtract(xRef.getColumnVector(i)).getNorm(); + assertEquals(0, error, 3.0e-16 * xRef.getColumnVector(i).getNorm()); } } + public void testOverdetermined() { + final Random r = new Random(5559252868205245l); + int p = (7 * DenseRealMatrix.BLOCK_SIZE) / 4; + int q = (5 * DenseRealMatrix.BLOCK_SIZE) / 4; + RealMatrix a = createTestMatrix(r, p, q); + RealMatrix xRef = createTestMatrix(r, q, DenseRealMatrix.BLOCK_SIZE + 3); + + // build a perturbed system: A.X + noise = B + RealMatrix b = a.multiply(xRef); + final double noise = 0.001; + b.walkInOptimizedOrder(new DefaultRealMatrixChangingVisitor() { + private static final long serialVersionUID = 3533849820776962636L; + public double visit(int row, int column, double value) { + return value * (1.0 + noise * (2 * r.nextDouble() - 1)); + } + }); + + // despite perturbation, the least square solution should be pretty good + RealMatrix x = new QRDecompositionImpl(a).getSolver().solve(b); + assertEquals(0, x.subtract(xRef).getNorm(), 0.01 * noise * p * q); + + } + + public void testUnderdetermined() { + final Random r = new Random(42185006424567123l); + int p = (5 * DenseRealMatrix.BLOCK_SIZE) / 4; + int q = (7 * DenseRealMatrix.BLOCK_SIZE) / 4; + RealMatrix a = createTestMatrix(r, p, q); + RealMatrix xRef = createTestMatrix(r, q, DenseRealMatrix.BLOCK_SIZE + 3); + RealMatrix b = a.multiply(xRef); + RealMatrix x = new QRDecompositionImpl(a).getSolver().solve(b); + + // too many equations, the system cannot be solved at all + assertTrue(x.subtract(xRef).getNorm() / (p * q) > 0.01); + + // the last unknown should have been set to 0 + assertEquals(0.0, x.getSubMatrix(p, q - 1, 0, x.getColumnDimension() - 1).getNorm()); + + } + + private RealMatrix createTestMatrix(final Random r, final int rows, final int columns) { + RealMatrix m = MatrixUtils.createRealMatrix(rows, columns); + m.walkInOptimizedOrder(new DefaultRealMatrixChangingVisitor(){ + private static final long serialVersionUID = -556118291433400034L; + public double visit(int row, int column, double value) + throws MatrixVisitorException { + return 2.0 * r.nextDouble() - 1.0; + } + }); + return m; + } }