You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2013/10/03 23:11:11 UTC

svn commit: r1529004 - in /sis/branches/JDK7/core: sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/ sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/ sis-referencing/src/test/java/org/apache/sis/test/s...

Author: desruisseaux
Date: Thu Oct  3 21:11:10 2013
New Revision: 1529004

URL: http://svn.apache.org/r1529004
Log:
Fix the seed of random number generators for ensuring stable builds.

Modified:
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrix1.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix1Test.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix2Test.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/SolverTest.java
    sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/TestUtilities.java

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java?rev=1529004&r1=1529003&r2=1529004&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java [UTF-8] Thu Oct  3 21:11:10 2013
@@ -98,11 +98,10 @@ class GeneralMatrix extends MatrixSIS {
      */
     GeneralMatrix(final int numRow, final int numCol, final double[] elements) {
         ensureValidSize(numRow, numCol);
-        final int length = numRow * numCol;
-        ensureLengthMatch(length, elements);
+        ensureLengthMatch(numRow * numCol, elements);
         this.numRow = (short) numRow;
         this.numCol = (short) numCol;
-        this.elements = Arrays.copyOf(elements, length);
+        this.elements = elements.clone();
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrix1.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrix1.java?rev=1529004&r1=1529003&r2=1529004&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrix1.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrix1.java [UTF-8] Thu Oct  3 21:11:10 2013
@@ -241,17 +241,6 @@ public final class Matrix1 extends Matri
      * {@inheritDoc}
      */
     @Override
-    public MatrixSIS inverse() throws NoninvertibleMatrixException {
-        if (m00 == 0) {
-            throw new NoninvertibleMatrixException();
-        }
-        return new Matrix1(1 / m00);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
     public MatrixSIS solve(final Matrix matrix) throws MismatchedMatrixSizeException, NoninvertibleMatrixException {
         final int nc = matrix.getNumCol();
         ensureNumRowMatch(SIZE, matrix, nc);

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java?rev=1529004&r1=1529003&r2=1529004&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java [UTF-8] Thu Oct  3 21:11:10 2013
@@ -16,7 +16,8 @@
  */
 package org.apache.sis.referencing.operation.matrix;
 
-import org.apache.sis.test.DependsOn;
+import java.util.Random;
+import org.junit.Test;
 
 import static org.junit.Assert.*;
 
@@ -30,17 +31,19 @@ import static org.junit.Assert.*;
  * @version 0.4
  * @module
  */
-@DependsOn(SolverTest.class)
 public final strictfp class GeneralMatrixTest extends MatrixTestCase {
     /**
      * Number of rows and columns.
      */
-    private final int size;
+    private int size;
 
     /**
-     * Creates a test with a random size for the square matrix.
+     * Computes a random size for the next matrix to create.
+     *
+     * @param random The random number generator to use.
      */
-    public GeneralMatrixTest() {
+    @Override
+    void prepareNewMatrixSize(final Random random) {
         size = 5 + random.nextInt(8); // Matrix sizes from 5 to 12 inclusive.
     }
 
@@ -55,4 +58,39 @@ public final strictfp class GeneralMatri
         super.validate(matrix);
         assertEquals(GeneralMatrix.class, matrix.getClass());
     }
+
+    /**
+     * Tests {@link GeneralMatrix#getExtendedElements(Matrix, int, int, boolean)}.
+     * This test verifies that {@code getExtendedElements} can infer default error
+     * terms for some well known values.
+     *
+     * @see Matrix2Test#testGetExtendedElements()
+     */
+    @Test
+    public void testGetExtendedElements() {
+        testGetExtendedElements(new GeneralMatrix(2, 2, new double[] {
+                StrictMath.PI / 180, // Degrees to radians
+                180 / StrictMath.PI, // Radians to degrees
+                0.9,                 // Gradians to degrees
+                0.1234567}));        // Random value with no special meaning.
+    }
+
+    /**
+     * Implementation of {@link #testGetExtendedElements()} shared by {@link Matrix2Test}.
+     */
+    static void testGetExtendedElements(final MatrixSIS matrix) {
+        final double[] elements = GeneralMatrix.getExtendedElements(matrix, Matrix2.SIZE, Matrix2.SIZE, false);
+        assertArrayEquals(new double[] {
+                // Same values than in the above matrix.
+                StrictMath.PI / 180,
+                180 / StrictMath.PI,
+                0.9,
+                0.1234567,
+
+                // Values below this point are error terms copied from DoubleDouble.ERRORS.
+                 2.9486522708701687E-19,
+                -1.9878495670576283E-15,
+                -2.2204460492503132E-17,
+                 0}, elements, STRICT);
+    }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix1Test.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix1Test.java?rev=1529004&r1=1529003&r2=1529004&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix1Test.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix1Test.java [UTF-8] Thu Oct  3 21:11:10 2013
@@ -55,6 +55,7 @@ public final strictfp class Matrix1Test 
      */
     @Test
     public void testConstructor() {
+        initialize(415870088589607716L);
         final double[] elements = createRandomPositiveValues(SIZE * SIZE);
         final Matrix1 matrix = new Matrix1(
                 elements[0]);

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix2Test.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix2Test.java?rev=1529004&r1=1529003&r2=1529004&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix2Test.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix2Test.java [UTF-8] Thu Oct  3 21:11:10 2013
@@ -55,6 +55,7 @@ public final strictfp class Matrix2Test 
      */
     @Test
     public void testConstructor() {
+        initialize(-8453835559080304420L);
         final double[] elements = createRandomPositiveValues(SIZE * SIZE);
         final Matrix2 matrix = new Matrix2(
                 elements[0],
@@ -64,4 +65,18 @@ public final strictfp class Matrix2Test 
         validate(matrix);
         assertArrayEquals(elements, matrix.getElements(), STRICT);
     }
+
+    /**
+     * Tests {@link GeneralMatrix#getExtendedElements(Matrix, int, int, boolean)}.
+     * This test is a copy of {@link GeneralMatrixTest#testGetExtendedElements()},
+     * but on a {@link Matrix2} instance instead of {@link GeneralMatrix}.
+     */
+    @Test
+    public void testGetExtendedElements() {
+        GeneralMatrixTest.testGetExtendedElements(new Matrix2(
+                StrictMath.PI / 180, // Degrees to radians
+                180 / StrictMath.PI, // Radians to degrees
+                0.9,                 // Gradians to degrees
+                0.1234567));         // Random value with no special meaning.
+    }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java?rev=1529004&r1=1529003&r2=1529004&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java [UTF-8] Thu Oct  3 21:11:10 2013
@@ -56,6 +56,7 @@ public final strictfp class Matrix3Test 
      */
     @Test
     public void testConstructor() {
+        initialize(-2078758443421995879L);
         final double[] elements = createRandomPositiveValues(SIZE * SIZE);
         final Matrix3 matrix = new Matrix3(
                 elements[0],

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java?rev=1529004&r1=1529003&r2=1529004&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java [UTF-8] Thu Oct  3 21:11:10 2013
@@ -56,6 +56,7 @@ public final strictfp class Matrix4Test 
      */
     @Test
     public void testConstructor() {
+        initialize(-7053945420932915425L);
         final double[] elements = createRandomPositiveValues(SIZE * SIZE);
         final Matrix4 matrix = new Matrix4(
                 elements[ 0],
@@ -77,4 +78,49 @@ public final strictfp class Matrix4Test 
         validate(matrix);
         assertArrayEquals(elements, matrix.getElements(), STRICT);
     }
+
+    /**
+     * Tests the accuracy of a chain of matrix operations.
+     *
+     * @throws NoninvertibleMatrixException Should never happen.
+     */
+    @Test
+    public void testAccuracy() throws NoninvertibleMatrixException {
+        final double parisMeridian = 2 + (20 + 13.82/60)/60;  // Paris meridian: 2°20'13.82"
+        final double toRadians = StrictMath.PI / 180;
+        /*
+         * Gradians to degrees with a Prime Meridian shift
+         * and a random conversion factor for z values.
+         */
+        final Matrix4 step1 = new Matrix4(
+                0.9,    0,   0, parisMeridian,
+                0, 0.9, 0,   0,
+                0, 0,   0.8, 0, // Random conversion factor for z values.
+                0, 0,   0,   1);
+        /*
+         * Degrees to radians with swapping of (longitude, latitude) axes
+         * and a conversion factor of z values from feet to metres.
+         */
+        final Matrix4 step2 = new Matrix4(
+                0, toRadians, 0, 0,
+                toRadians, 0, 0, 0,
+                0, 0, 0.3048, 0,
+                0, 0, 0, 1);
+        /*
+         * Converse of the above operations.
+         */
+        final MatrixSIS step3 = step2.multiply(step1).inverse();
+        /*
+         * Concatenate everything, which should go back to the identity transform.
+         * We have a slight residu in the longitude translation term because of the
+         * prime meridian shift - we will set this residu to zero for this test.
+         *
+         * Note that the 'isIdentity(0)' test fail if the double-double arithmetic is
+         * disabled, because some scale factors will be 0.9999999999999999 instead of 1.
+         */
+        final MatrixSIS result = step3.multiply(step2).multiply(step1);
+        assertEquals("translateX", 0, result.getElement(0,3), 1E-32);
+        result.setElement(0,3, 0);
+        assertTrue("isIdentity(0)", Matrices.isIdentity(result, 0));
+    }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java?rev=1529004&r1=1529003&r2=1529004&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java [UTF-8] Thu Oct  3 21:11:10 2013
@@ -18,6 +18,7 @@ package org.apache.sis.referencing.opera
 
 import java.util.Random;
 import Jama.Matrix;
+import org.apache.sis.math.Statistics;
 import org.apache.sis.internal.util.DoubleDouble;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.test.TestUtilities;
@@ -49,22 +50,47 @@ import static org.apache.sis.test.Assert
  */
 public abstract strictfp class MatrixTestCase extends TestCase {
     /**
+     * {@code true} for reusing the same sequences of random numbers in every execution of test cases, or
+     * {@code false} for "truly" random sequences of random numbers. This flag can be set to {@code false}
+     * for testing purpose, but should be set to {@code true} otherwise for avoiding random test failure.
+     * This is needed because we want to set {@link #TOLERANCE} to a small value, but it is very difficult
+     * to guaranteed that a random sequence of numbers will not cause a larger discrepancy.
+     *
+     * <p>Note that this flag is set to {@code false} if double-double arithmetic is disabled because in such
+     * case, the results should be identical to the JAMA results (i.e. equal using a {@link #TOLERANCE} of zero)
+     * for any sequence of numbers.</p>
+     */
+    protected static final boolean DETERMINIST = !DoubleDouble.DISABLED;
+
+    /**
      * A constant for any test in this class or a subclass which expect
      * a floating point value to be strictly equals to an other value.
      */
     static final double STRICT = 0;
 
     /**
-     * Tolerance factor for comparisons of floating point numbers.
-     * The matrix elements used in this class varies between 0 and 100,
+     * Tolerance factor for comparisons of floating point numbers between SIS and JAMA implementation,
+     * which is {@value}. Note that the matrix element values used in this class vary between 0 and 100,
      * and the {@code Math.ulp(100.0)} value is approximatively 1.4E-14.
+     *
+     * {@section How this value is determined}
+     * Experience (by looking at {@link #statistics}) shows that the differences are usually smaller than 1E-12.
+     * However when using non-determinist sequence of random values ({@link #DETERMINIST} sets to {@code false}),
+     * we do have from time-to-time a difference around 1E-9.
+     *
+     * Those differences exist because SIS uses double-double arithmetic, while JAMA uses ordinary double.
+     * To remove that ambiguity, one can temporarily set {@link DoubleDouble#DISABLED} to {@code true},
+     * in which case the SIS results should be strictly identical to the JAMA ones.
+     *
+     * @see SolverTest#TOLERANCE
+     * @see NonSquareMatrixTest#printStatistics()
      */
-    static final double TOLERANCE = DoubleDouble.DISABLED ? STRICT : 1E-8;
+    protected static final double TOLERANCE = DoubleDouble.DISABLED ? STRICT : 1E-12;
 
     /**
      * Number of random matrices to try in arithmetic operation tests.
      */
-    static final int NUMBER_OF_REPETITIONS = 10;
+    static final int NUMBER_OF_REPETITIONS = 100;
 
     /**
      * The threshold in matrix determinant for attempting to compute the inverse.
@@ -73,15 +99,45 @@ public abstract strictfp class MatrixTes
     private static final double DETERMINANT_THRESHOLD = 0.001;
 
     /**
-     * Random number generator, created by {@link #initialize(String, boolean)} when first needed.
+     * Statistics about the different between the JAMA and SIS matrix elements, or {@code null}
+     * if those statistics do not need to be collected. This is used during the test development
+     * phase for tuning the tolerance threshold.
+     *
+     * @see NonSquareMatrixTest#printStatistics()
      */
-    final Random random;
+    static final Statistics statistics = verbose ? new Statistics("|SIS - JAMA|") : null;
+
+    /**
+     * Random number generator, created by {@link #initialize(long)} as the first operation of
+     * any test method which will use random numbers. This random number generator will use a
+     * fixed seed if {@link #DETERMINIST} is {@code true}, which is the normal case.
+     */
+    private Random random;
 
     /**
      * For subclasses only.
      */
     MatrixTestCase() {
-        random = TestUtilities.createRandomNumberGenerator();
+    }
+
+    /**
+     * Initializes the random number generator to the given seed. If {@link #DETERMINIST} is {@code false}
+     * (which happen only when performing some more extensive tests), then the given seed will be replaced
+     * by a random one.
+     *
+     * @param seed The initial seed.
+     */
+    final void initialize(final long seed) {
+        random = DETERMINIST ? new Random(seed) : TestUtilities.createRandomNumberGenerator();
+    }
+
+    /**
+     * Computes a random size for the next matrix to create. This method is overridden
+     * only by subclasses that test matrix implementations supporting arbitrary sizes.
+     *
+     * @param random The random number generator to use for computing a random matrix size.
+     */
+    void prepareNewMatrixSize(final Random random) {
     }
 
     /** Returns the number of rows of the matrix being tested.    */ abstract int getNumRow();
@@ -99,6 +155,10 @@ public abstract strictfp class MatrixTes
 
     /**
      * Verifies that the SIS matrix is equals to the JAMA one, up to the given tolerance value.
+     *
+     * @param expected  The JAMA matrix used as a reference implementation.
+     * @param actual    The SIS matrix to compare to JAMA.
+     * @param tolerance The tolerance threshold, usually either {@link #STRICT} or {@link #TOLERANCE}.
      */
     static void assertMatrixEquals(final Matrix expected, final MatrixSIS actual, final double tolerance) {
         final int numRow = actual.getNumRow();
@@ -108,7 +168,14 @@ public abstract strictfp class MatrixTes
         final String name = actual.getClass().getSimpleName();
         for (int j=0; j<numRow; j++) {
             for (int i=0; i<numCol; i++) {
-                assertEquals(name, expected.get(j,i), actual.getElement(j,i), tolerance);
+                final double e = expected.get(j,i);
+                final double a = actual.getElement(j,i);
+                assertEquals(name, e, a, tolerance);
+                if (tolerance != STRICT && statistics != null) {
+                    synchronized (statistics) {
+                        statistics.accept(StrictMath.abs(e - a));
+                    }
+                }
             }
         }
     }
@@ -136,6 +203,8 @@ public abstract strictfp class MatrixTes
      */
     @Test
     public void testGetElements() {
+        initialize(3812872376135347328L);
+        prepareNewMatrixSize(random);
         final int numRow = getNumRow();
         final int numCol = getNumCol();
         final double[] elements = createRandomPositiveValues(numRow * numCol);
@@ -157,6 +226,8 @@ public abstract strictfp class MatrixTes
     @Test
     @DependsOnMethod("testGetElements")
     public void testSetElement() {
+        initialize(-8079924100564483073L);
+        prepareNewMatrixSize(random);
         final int numRow = getNumRow();
         final int numCol = getNumCol();
         final MatrixSIS matrix = Matrices.createZero(numRow, numCol);
@@ -186,6 +257,8 @@ public abstract strictfp class MatrixTes
     @Test
     @DependsOnMethod("testSetElement")
     public void testIsIdentity() {
+        initialize(6173145457052452823L);
+        prepareNewMatrixSize(random);
         final int numRow = getNumRow();
         final int numCol = getNumCol();
         final MatrixSIS matrix = Matrices.createDiagonal(numRow, numCol);
@@ -215,6 +288,8 @@ public abstract strictfp class MatrixTes
     @Test
     @DependsOnMethod("testSetElement")
     public void testCloneEquals() {
+        initialize(-4572234104840706847L);
+        prepareNewMatrixSize(random);
         final int numRow = getNumRow();
         final int numCol = getNumCol();
         final double[] elements = createRandomPositiveValues(numRow * numCol);
@@ -243,6 +318,8 @@ public abstract strictfp class MatrixTes
     @Test
     @DependsOnMethod("testGetElements")
     public void testTranspose() {
+        initialize(585037875560696050L);
+        prepareNewMatrixSize(random);
         final int numRow = getNumRow();
         final int numCol = getNumCol();
         final double[] elements = createRandomPositiveValues(numRow * numCol);
@@ -262,6 +339,8 @@ public abstract strictfp class MatrixTes
     @Test
     @DependsOnMethod("testGetElements")
     public void testNormalizeColumns() {
+        initialize(1549772118153010333L);
+        prepareNewMatrixSize(random);
         final int numRow = getNumRow();
         final int numCol = getNumCol();
         final double[] elements = createRandomPositiveValues(numRow * numCol);
@@ -285,9 +364,11 @@ public abstract strictfp class MatrixTes
     @Test
     @DependsOnMethod("testGetElements")
     public void testMultiply() {
-        final int numRow = getNumRow();
-        final int numCol = getNumCol();
+        initialize(2478887638739725150L);
         for (int n=0; n<NUMBER_OF_REPETITIONS; n++) {
+            prepareNewMatrixSize(random);
+            final int numRow = getNumRow();
+            final int numCol = getNumCol();
             double[] elements = createRandomPositiveValues(numRow * numCol);
             final MatrixSIS matrix = Matrices.create(numRow, numCol, elements);
             final Matrix reference = new Matrix(elements, numCol).transpose();
@@ -320,12 +401,14 @@ public abstract strictfp class MatrixTes
     @Test
     @DependsOnMethod("testMultiply")
     public void testSolve() throws NoninvertibleMatrixException {
-        final int numRow = getNumRow();
-        final int numCol = getNumCol();
+        initialize(2108474073121762244L);
+        for (int n=0; n<NUMBER_OF_REPETITIONS; n++) {
+            prepareNewMatrixSize(random);
+            final int numRow = getNumRow();
+            final int numCol = getNumCol();
 
-        if (numRow != 1 || numCol != 1) return; // Temporary limitation.
+            if (numRow != 1 || numCol != 1) return; // Temporary limitation.
 
-        for (int n=0; n<NUMBER_OF_REPETITIONS; n++) {
             double[] elements = createRandomPositiveValues(numRow * numCol);
             final Matrix reference = new Matrix(elements, numCol).transpose();
             if (!(reference.det() >= DETERMINANT_THRESHOLD)) {
@@ -362,9 +445,11 @@ public abstract strictfp class MatrixTes
     @Test
     @DependsOnMethod("testSolve")
     public void testInverse() throws NoninvertibleMatrixException {
-        final int numRow = getNumRow();
-        final int numCol = getNumCol();
+        initialize(-9063921123024549789L);
         for (int n=0; n<NUMBER_OF_REPETITIONS; n++) {
+            prepareNewMatrixSize(random);
+            final int numRow = getNumRow();
+            final int numCol = getNumCol();
             final double[] elements = createRandomPositiveValues(numRow * numCol);
             final Matrix reference = new Matrix(elements, numCol).transpose();
             if (!(reference.det() >= DETERMINANT_THRESHOLD)) {
@@ -380,6 +465,8 @@ public abstract strictfp class MatrixTes
      */
     @Test
     public void testSerialization() {
+        initialize(-3232759118744327281L);
+        prepareNewMatrixSize(random);
         final int numRow = getNumRow();
         final int numCol = getNumCol();
         final MatrixSIS matrix = Matrices.create(numRow, numCol, createRandomPositiveValues(numRow * numCol));

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java?rev=1529004&r1=1529003&r2=1529004&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java [UTF-8] Thu Oct  3 21:11:10 2013
@@ -16,7 +16,10 @@
  */
 package org.apache.sis.referencing.operation.matrix;
 
+import java.util.Random;
 import org.apache.sis.test.DependsOn;
+import org.apache.sis.test.TestUtilities;
+import org.junit.AfterClass;
 
 import static org.junit.Assert.*;
 
@@ -25,22 +28,31 @@ import static org.junit.Assert.*;
  * Tests the {@link NonSquareMatrix} implementation.
  * This class inherits all tests defined in {@link MatrixTestCase}.
  *
+ * <p>This class is expected to be the last {@code MatrixTestCase} subclass to be executed,
+ * because it sends the {@link #statistics} to {@link #out}. This condition is ensured if
+ * the tests are executed by {@link org.apache.sis.test.suite.ReferencingTestSuite}.
+ * However it is not a big deal if this condition is broken, as the only consequence
+ * is that reported statistics will be incomplete.</p>
+ *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
  * @version 0.4
  * @module
  */
-@DependsOn(GeneralMatrixTest.class)
+@DependsOn(SolverTest.class)
 public final strictfp class NonSquareMatrixTest extends MatrixTestCase {
     /**
      * Number of rows and columns, initialized by {@link #initialize(String, boolean)}.
      */
-    private final int numRow, numCol;
+    private int numRow, numCol;
 
     /**
-     * Creates a test with a random size for the matrix and ensure that the matrix is not square.
+     * Computes a random size for the next matrix to create.
+     *
+     * @param random The random number generator to use.
      */
-    public NonSquareMatrixTest() {
+    @Override
+    void prepareNewMatrixSize(final Random random) {
         numRow = 5 + random.nextInt(8); // Matrix sizes from 5 to 12 inclusive.
         int n;
         do n = 5 + random.nextInt(8);
@@ -67,4 +79,19 @@ public final strictfp class NonSquareMat
     @org.junit.Ignore
     public void testInverse() throws NoninvertibleMatrixException {
     }
+
+    /**
+     * Prints the statistics about the differences between JAMA and SIS matrix elements.
+     * Those statistics will be visible only if {@link #verbose} is {@code true}.
+     */
+    @AfterClass
+    public static void printStatistics() {
+        if (statistics != null) {
+            TestUtilities.printSeparator("Overall statistics on agreement of matrix arithmetic");
+            synchronized (statistics) {
+                out.println(statistics);
+            }
+            TestUtilities.forceFlushOutput();
+        }
+    }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/SolverTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/SolverTest.java?rev=1529004&r1=1529003&r2=1529004&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/SolverTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/SolverTest.java [UTF-8] Thu Oct  3 21:11:10 2013
@@ -18,6 +18,7 @@ package org.apache.sis.referencing.opera
 
 import java.util.Random;
 import Jama.Matrix;
+import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestUtilities;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
@@ -27,13 +28,36 @@ import org.junit.Test;
  * Tests the {@link Solver} class using <a href="http://math.nist.gov/javanumerics/jama">JAMA</a>
  * as the reference implementation.
  *
+ * {@section Cyclic dependency}
+ * There is a cyclic test dependency since {@link GeneralMatrix} needs {@link Solver} for some operations,
+ * and conversely. To be more specific the dependency order is:
+ *
+ * <ol>
+ *   <li>Simple {@link GeneralMatrix} methods (construction, get/set elements)</li>
+ *   <li>{@link Solver}</li>
+ *   <li>More complex {@code GeneralMatrix} methods (matrix inversion, solve)</li>
+ * </ol>
+ *
+ * We test {@code GeneralMatrix} before {@code Solver} since nothing could be done without
+ * the above-cited simple operations anyway.
+ *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
  * @version 0.4
  * @module
  */
+@DependsOn(GeneralMatrixTest.class) // See class javadoc
 public final strictfp class SolverTest extends TestCase {
     /**
+     * The tolerance threshold for this test case, which is {@value}. This value needs to be higher then the
+     * {@link MatrixTestCase#TOLERANCE} one because of the increased complexity of {@link Solver} operations.
+     *
+     * @see MatrixTestCase#TOLERANCE
+     * @see NonSquareMatrixTest#printStatistics()
+     */
+    protected static final double TOLERANCE = 100 * MatrixTestCase.TOLERANCE;
+
+    /**
      * The matrix to test.
      */
     private MatrixSIS matrix;
@@ -66,7 +90,12 @@ public final strictfp class SolverTest e
      */
     @Test
     public void testSolve() throws NoninvertibleMatrixException {
-        final Random random = TestUtilities.createRandomNumberGenerator();
+        final Random random;
+        if (MatrixTestCase.DETERMINIST) {
+            random = new Random(7671901444622173417L);
+        } else {
+            random = TestUtilities.createRandomNumberGenerator();
+        }
         for (int k=0; k<MatrixTestCase.NUMBER_OF_REPETITIONS; k++) {
             final int size = random.nextInt(16) + 1;
             createMatrices(size, random.nextInt(16) + 1, random);
@@ -81,7 +110,7 @@ public final strictfp class SolverTest e
                 continue;
             }
             final MatrixSIS U = Solver.solve(matrix, matrixArg, matrixArg.getNumRow(), matrixArg.getNumCol());
-            MatrixTestCase.assertMatrixEquals(jama, U, MatrixTestCase.TOLERANCE);
+            MatrixTestCase.assertMatrixEquals(jama, U, TOLERANCE);
         }
     }
 }

Modified: sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1529004&r1=1529003&r2=1529004&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] Thu Oct  3 21:11:10 2013
@@ -31,13 +31,13 @@ import org.junit.BeforeClass;
  */
 @Suite.SuiteClasses({
     // Test matrix first because they may be used in about every SIS corners.
+    org.apache.sis.referencing.operation.matrix.GeneralMatrixTest.class,
     org.apache.sis.referencing.operation.matrix.SolverTest.class,
     org.apache.sis.referencing.operation.matrix.Matrix1Test.class,
     org.apache.sis.referencing.operation.matrix.Matrix2Test.class,
     org.apache.sis.referencing.operation.matrix.Matrix3Test.class,
     org.apache.sis.referencing.operation.matrix.Matrix4Test.class,
-    org.apache.sis.referencing.operation.matrix.GeneralMatrixTest.class,
-    org.apache.sis.referencing.operation.matrix.NonSquareMatrixTest.class,
+    org.apache.sis.referencing.operation.matrix.NonSquareMatrixTest.class, // Expected to be last MatrixTestCase - see javadoc.
     org.apache.sis.referencing.operation.matrix.MatricesTest.class,
     org.apache.sis.referencing.operation.matrix.AffineTransforms2DTest.class,
 

Modified: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/TestUtilities.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/TestUtilities.java?rev=1529004&r1=1529003&r2=1529004&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/TestUtilities.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/TestUtilities.java [UTF-8] Thu Oct  3 21:11:10 2013
@@ -44,7 +44,7 @@ import static org.junit.Assert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-3.16)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 public final strictfp class TestUtilities extends Static {
@@ -90,6 +90,17 @@ public final strictfp class TestUtilitie
     }
 
     /**
+     * Prints and clear the current content of {@link TestCase#out}, regardless of whether
+     * {@link TestCase#verbose} is {@code true} or {@code false}. This method should rarely
+     * be needed.
+     *
+     * @since 0.4
+     */
+    public static void forceFlushOutput() {
+        TestCase.flushOutput();
+    }
+
+    /**
      * If verbose output are enabled, prints the given title to {@link TestCase#out} in a box.
      * This method is invoked for writing a clear visual separator between the verbose output
      * of different test cases. This method does nothing if verbose output is not enabled,