sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1530584 - in /sis/trunk: ./ application/ application/sis-console/src/test/java/org/apache/sis/test/suite/ core/sis-metadata/src/test/java/org/apache/sis/test/suite/ core/sis-referencing/src/main/java/org/apache/sis/referencing/ core/sis-re...
Date Wed, 09 Oct 2013 12:37:04 GMT
Author: desruisseaux
Date: Wed Oct  9 12:37:03 2013
New Revision: 1530584

URL: http://svn.apache.org/r1530584
Log:
Merge from the JDK6 branch.

Added:
    sis/trunk/profiles/sis-french-profile/src/test/java/org/apache/sis/test/suite/FrenchProfileTestSuite.java
      - copied unchanged from r1530581, sis/branches/JDK6/profiles/sis-french-profile/src/test/java/org/apache/sis/test/suite/FrenchProfileTestSuite.java
    sis/trunk/storage/sis-shapefile/src/test/java/org/apache/sis/test/
      - copied from r1530581, sis/branches/JDK6/storage/sis-shapefile/src/test/java/org/apache/sis/test/
Removed:
    sis/trunk/profiles/sis-french-profile/src/test/java/org/apache/sis/test/suite/FrenchProfileSuite.java
Modified:
    sis/trunk/   (props changed)
    sis/trunk/application/pom.xml
    sis/trunk/application/sis-console/src/test/java/org/apache/sis/test/suite/ConsoleTestSuite.java
    sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrix.java
    sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Solver.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatricesTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/SolverTest.java
    sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/collection/CacheTest.java
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/collection/WeakValueHashMapTest.java
    sis/trunk/core/sis-utility/src/test/java/org/apache/sis/xml/OGCNamespacePrefixMapperTest.java
    sis/trunk/pom.xml
    sis/trunk/storage/sis-netcdf/src/test/java/org/apache/sis/test/suite/NetcdfTestSuite.java
    sis/trunk/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/CmdLineDriverTest.java
    sis/trunk/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/ShapeFileTest.java
    sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/storage/ProbeResult.java
    sis/trunk/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java

Propchange: sis/trunk/
------------------------------------------------------------------------------
  Merged /sis/branches/JDK7:r1529258-1530579
  Merged /sis/branches/JDK6:r1529262-1530581

Modified: sis/trunk/application/pom.xml
URL: http://svn.apache.org/viewvc/sis/trunk/application/pom.xml?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/application/pom.xml (original)
+++ sis/trunk/application/pom.xml Wed Oct  9 12:37:03 2013
@@ -97,6 +97,10 @@
 
     <!-- Test dependencies -->
     <dependency>
+      <groupId>org.opengis</groupId>
+      <artifactId>geoapi-conformance</artifactId>
+    </dependency>
+    <dependency>
       <groupId>org.apache.sis.core</groupId>
       <artifactId>sis-utility</artifactId>
       <version>${project.version}</version>

Modified: sis/trunk/application/sis-console/src/test/java/org/apache/sis/test/suite/ConsoleTestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/test/java/org/apache/sis/test/suite/ConsoleTestSuite.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/application/sis-console/src/test/java/org/apache/sis/test/suite/ConsoleTestSuite.java [UTF-8] (original)
+++ sis/trunk/application/sis-console/src/test/java/org/apache/sis/test/suite/ConsoleTestSuite.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -43,6 +43,7 @@ public final strictfp class ConsoleTestS
      */
     @BeforeClass
     public static void verifyTestList() {
-        verifyTestList(ConsoleTestSuite.class, BASE_TEST_CLASSES);
+        assertNoMissingTest(ConsoleTestSuite.class);
+        verifyTestList(ConsoleTestSuite.class);
     }
 }

Modified: sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java [UTF-8] (original)
+++ sis/trunk/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -78,6 +78,7 @@ public final strictfp class MetadataTest
      */
     @BeforeClass
     public static void verifyTestList() {
-        verifyTestList(MetadataTestSuite.class, BASE_TEST_CLASSES);
+        assertNoMissingTest(MetadataTestSuite.class);
+        verifyTestList(MetadataTestSuite.class);
     }
 }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -386,9 +386,9 @@ public final class IdentifiedObjects ext
      *   <li>Otherwise returns the {@linkplain Identifier#getCode() identifier code}.</li>
      * </ul>
      *
-     * This method is provided because the {@link GenericName#toString()} behavior is specified
-     * by its javadoc, while {@link ReferenceIdentifier} has no such contract. For example the
-     * {@link DefaultIdentifier} implementation provides a WKT-like string representation.
+     * This method is provided because the {@link GenericName#toString()} behavior is specified by its javadoc,
+     * while {@link ReferenceIdentifier} has no such contract. For example like most ISO 19115 objects in SIS,
+     * the {@link org.apache.sis.metadata.iso.DefaultIdentifier} implementation is formatted as a tree.
      * This static method can be used when a "name-like" representation is needed for any implementation.
      *
      * @param  identifier The identifier, or {@code null}.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/GeneralMatrix.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -169,7 +169,7 @@ class GeneralMatrix extends MatrixSIS {
      * intend was to specify the {@link Math#PI} value, in which case this method will infer that we would
      * need to add 1.2246467991473532E-16 in order to get a value closer to π.
      */
-    private static void inferErrors(final double[] elements) {
+    static void inferErrors(final double[] elements) {
         final int length = elements.length / 2;
         for (int i=length; i<elements.length; i++) {
             elements[i] = DoubleDouble.errorForWellKnownValue(elements[i - length]);

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -904,6 +904,7 @@ public final class Matrices extends Stat
                         // NaN or Infinity.
                         element = element.replace("Infinity", "∞");
                         width = spacing + element.length();
+                        widthBeforeFraction[i] = Math.max(widthBeforeFraction[i], width);
                     }
                 }
                 columnWidth[i] = Math.max(columnWidth[i], width);

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/MatrixSIS.java Wed Oct  9 12:37:03 2013
@@ -250,7 +250,7 @@ public abstract class MatrixSIS implemen
      * @see java.awt.geom.AffineTransform#createInverse()
      */
     public MatrixSIS inverse() throws NoninvertibleMatrixException {
-        return Solver.inverse(this);
+        return Solver.inverse(this, true);
     }
 
     /**

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrix.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrix.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrix.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrix.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -17,6 +17,7 @@
 package org.apache.sis.referencing.operation.matrix;
 
 import org.opengis.referencing.operation.Matrix;
+import org.apache.sis.util.resources.Errors;
 
 
 /**
@@ -27,7 +28,7 @@ import org.opengis.referencing.operation
  * @version 0.4
  * @module
  *
- * @see Matrices#create(int, int)
+ * @see Matrices#createDiagonal(int, int)
  */
 final class NonSquareMatrix extends GeneralMatrix {
     /**
@@ -105,11 +106,223 @@ final class NonSquareMatrix extends Gene
 
     /**
      * {@inheritDoc}
+     *
+     * <p>This method delegates the work to {@code inverse().multiply(matrix)} in order to leverage
+     * the special handling done by {@code inverse()} for non-square matrices.</p>
+     */
+    @Override
+    public MatrixSIS solve(final Matrix matrix) throws MismatchedMatrixSizeException, NoninvertibleMatrixException {
+        MatrixSIS result = inverse();
+        if (!matrix.isIdentity()) {
+            result = result.multiply(matrix);
+        }
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This method performs a special check for non-square matrices in an attempt to invert them anyway.
+     * If this matrix has more columns than rows, then this method can invert that matrix if and only if
+     * some columns contain only 0 elements. In such case, the dimensions corresponding to those columns are
+     * considered independent of all other dimensions. This happen typically with the dimension of <var>z</var>
+     * and <var>t</var> ordinate values.</p>
+     *
+     * <p><b>Example:</b> in a conversion from (x₁,y₁,z,t) to (x₂,y₂), if the (x,y) dimensions are independent
+     * of z and t dimensions, then we do not need those (z,t) dimensions for calculating the inverse of (x₁,y₁)
+     * to (x₂,y₂). We can omit the (z,t) dimensions in order to have a square matrix, perform the inversion,
+     * then insert NaN in place of the omitted dimensions. In the matrix below, we can see that (x,y) are
+     * independent of (z,t) because the 3th and 4th columns contains only 0 elements:</p>
+     *
+     * {@preformat math
+     *   ┌               ┐ -1        ┌                  ┐
+     *   │ 2  0  0  0  8 │           │ 0.5  0     -4.00 │
+     *   │ 0  4  0  0  5 │     =     │ 0    0.25  -1.25 │
+     *   │ 0  0  0  0  1 │           │ 0    0       NaN │
+     *   └               ┘           │ 0    0       NaN │
+     *                               │ 0    0      1    │
+     *                               └                  ┘
+     * }
+     *
+     * There is an issue about whether the full row shall contains NaN, or only the last element (the translation
+     * term) as in the above example.  The current implementation inserts a NaN value in the translation term and
+     * sets all other values to 0 on the assumption that if (x₂,y₂) do not depend on (z,t), then conversely (z,t)
+     * do not depend on (x₂,y₂) neither. Setting the scale factor to zero expresses that fact, while setting them
+     * to NaN would mean "don't know".
+     *
+     * <p>Note that the above strategy assumes that the matrix is used for an affine transform, which is not always
+     * true (it could be the matrix of a map projection derivative for instance). If the matrix is not for an affine
+     * transform, then the last column has no special meaning and the above strategy is somewhat asymmetric.
+     * However it will still produce NaN for the full row in matrix multiplications.</p>
+     *
+     * <p>Conversely, if the matrix has more rows than columns (in a system of linear equations, the system would
+     * be <cite>overdetermined</cite>), then we omit the rows containing only zero or NaN values. After the matrix
+     * inversion, we insert columns having only zero values for the dimensions associated to those rows.
+     * Semantically, the inverse matrix is a (x₁,y₁,z,t) → (x₂,y₂) transform that just discards the ordinate values
+     * at the dimensions corresponding to those rows.</p>
      */
     @Override
     public MatrixSIS inverse() throws NoninvertibleMatrixException {
-        // TODO: This is where we will need a special treatment different than what JAMA do (because different needs).
-        throw new UnsupportedOperationException();
+        if (numRow < numCol) {
+            return inverseDimensionReduction();
+        } else {
+            return inverseDimensionIncrease();
+        }
+    }
+
+    /**
+     * Inverses a matrix for a transform where target points have fewer ordinates than source points.
+     * If a column contains only zero values, then this means that the ordinate at the corresponding
+     * column is simply deleted. We can omit that column. We check the last columns before the first
+     * columns on the assumption that last dimensions are more likely to be independent dimensions
+     * like time.
+     */
+    private MatrixSIS inverseDimensionReduction() throws NoninvertibleMatrixException {
+        final int numRow = this.numRow; // Protection against accidental changes.
+        final int numCol = this.numCol;
+        final int length = numRow * numCol;
+        int i  = numCol;
+        int oi = numCol - numRow; // Initialized to the maximal amount of columns that we may omit.
+        final int[] omitted = new int[oi];
+next:   do {
+            if (--i < 0) {
+                throw nonInvertible(); // Not enough columns that we can omit.
+            }
+            for (int j=length + i; (j -= numCol) >= 0;) {
+                if (elements[j] != 0) {
+                    continue next;
+                }
+            }
+            omitted[--oi] = i; // Found a column which contains only 0 elements.
+        } while (oi != 0);
+        /*
+         * Found enough columns containing only zero elements. Create a square matrix omitting those columns,
+         * and invert that matrix. Note that we also need to either copy the error terms, or to infer them.
+         */
+        GeneralMatrix squareMatrix = new GeneralMatrix(numRow, numRow, false, 2);
+        int j = 0;
+        for (i=0; i<numCol; i++) {
+            if (oi != omitted.length && i == omitted[oi]) oi++;
+            else copyColumn(this, i, squareMatrix, j++); // Copy only if not skipped.
+        }
+        // If the source matrix does not use double-double arithmetic, infer the error terms.
+        if (indexOfErrors(numRow, numCol, elements) == 0) {
+            inferErrors(squareMatrix.elements);
+        }
+        squareMatrix = (GeneralMatrix) Solver.inverse(squareMatrix, false);
+        /*
+         * Create a new matrix with new rows added for the omitted ordinates.
+         * From this point, the meaning of 'numCol' and 'numRow' are interchanged.
+         */
+        final NonSquareMatrix inverse = new NonSquareMatrix(numCol, numRow, false, 2);
+        for (oi=0, j=0, i=0; i<numCol; i++) {
+            if (oi != omitted.length && i == omitted[oi]) {
+                inverse.setElement(i, numRow-1, Double.NaN); // Translation term to NaN, remaining to 0.
+                oi++;
+            } else {
+                copyRow(squareMatrix, j++, inverse, i);
+            }
+        }
+        return inverse;
+    }
+
+    /**
+     * Inverse a matrix for a transform where target points has more ordinates than source points.
+     * In other words, the target matrices will be a transform that discard some ordinate values.
+     * We will discard the ones for which the row contains only 0 or NaN elements.
+     */
+    private MatrixSIS inverseDimensionIncrease() throws NoninvertibleMatrixException {
+        final int numRow = this.numRow; // Protection against accidental changes.
+        final int numCol = this.numCol;
+        int j  = numRow;
+        int oi = numRow - numCol; // Initialized to the maximal amount of rows that we may discard.
+        final int[] omitted = new int[oi];
+next:   do {
+            if (--j < 0) {
+                throw nonInvertible(); // Not enough rows that we can omit.
+            }
+            final int offset = j * numCol;
+            for (int i=offset + numCol; --i >= offset;) {
+                final double element = elements[i];
+                if (element != 0 && !Double.isNaN(element)) {
+                    continue next;
+                }
+            }
+            omitted[--oi] = j; // Found a row which contains only 0 or NaN elements.
+        } while (oi != 0);
+        /*
+         * Found enough rows containing only zero elements. Create a square matrix omitting those rows,
+         * and invert that matrix. Note that we also need to either copy the error terms, or to infer them.
+         */
+        GeneralMatrix squareMatrix = new GeneralMatrix(numCol, numCol, false, 2);
+        int i = 0;
+        for (j=0; j<numRow; j++) {
+            if (oi != omitted.length && j == omitted[oi]) oi++;
+            else copyRow(this, j, squareMatrix, i++); // Copy only if not skipped.
+        }
+        if (indexOfErrors(numRow, numCol, elements) == 0) {
+            inferErrors(squareMatrix.elements);
+        }
+        squareMatrix = (GeneralMatrix) Solver.inverse(squareMatrix, false);
+        /*
+         * Create a new matrix with new columns added for the omitted rows.
+         * From this point, the meaning of 'numCol' and 'numRow' are interchanged.
+         */
+        final NonSquareMatrix inverse = new NonSquareMatrix(numCol, numRow, false, 2);
+        for (oi=0, i=0, j=0; j<numRow; j++) {
+            if (oi != omitted.length && j == omitted[oi]) oi++;
+            else copyColumn(squareMatrix, i++, inverse, j);
+        }
+        return inverse;
+    }
+
+    /**
+     * Copies a column between two matrices, including the double-double arithmetic error terms if any.
+     * The target matrix must have the same number of rows than the source matrix, and must have enough
+     * room for error terms (this is not verified).
+     *
+     * @param source    The matrix from which to copy a column.
+     * @param srcIndex  Index of the column to copy from the source matrix.
+     * @param target    The matrix where to copy the column.
+     * @param dstIndex  Index of the column where to copy in the target matrix.
+     */
+    private static void copyColumn(final GeneralMatrix source, int srcIndex, final GeneralMatrix target, int dstIndex) {
+        assert target.numRow == source.numRow;
+        while (srcIndex < source.elements.length) {
+            target.elements[dstIndex] = source.elements[srcIndex];
+            srcIndex += source.numCol;
+            dstIndex += target.numCol;
+        }
+    }
+
+    /**
+     * Copies a row between two matrices, including the double-double arithmetic error terms if any.
+     * The target matrix must have the same number of columns than the source matrix, and must have
+     * enough room for error terms (this is not verified).
+     *
+     * @param source    The matrix from which to copy a row.
+     * @param srcIndex  Index of the row to copy from the source matrix.
+     * @param target    The matrix where to copy the row.
+     * @param dstIndex  Index of the row where to copy in the target matrix.
+     */
+    private static void copyRow(final GeneralMatrix source, int srcIndex, final GeneralMatrix target, int dstIndex) {
+        final int numCol = target.numCol;
+        assert numCol == source.numCol;
+        srcIndex *= numCol;
+        dstIndex *= numCol;
+        System.arraycopy(source.elements, srcIndex, target.elements, dstIndex, numCol);
+        srcIndex += numCol * source.numRow;
+        if (srcIndex < source.elements.length) {
+            dstIndex += numCol * target.numRow;
+            System.arraycopy(source.elements, srcIndex, target.elements, dstIndex, numCol);
+        }
+    }
+
+    /**
+     * Returns the exception for a non-invertible transform.
+     */
+    private NoninvertibleMatrixException nonInvertible() {
+        return new NoninvertibleMatrixException(Errors.format(Errors.Keys.NonInvertibleMatrix_2, numRow, numCol));
     }
 
     /**

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Solver.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Solver.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Solver.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Solver.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -31,12 +31,20 @@ import org.apache.sis.util.ArraysExt;
  * <p>This class implements the {@link Matrix} interface as an implementation convenience.
  * This implementation details can be ignored.</p>
  *
+ * @author  JAMA team
+ * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
  * @version 0.4
  * @module
  */
 final class Solver implements Matrix {
     /**
+     * The size of the (i, j, s) tuples used internally by {@link #solve(MatrixSIS, Matrix, double[], int, int)}
+     * for storing information about the NaN values.
+     */
+    private static final int TUPLE_SIZE = 3;
+
+    /**
      * A immutable identity matrix without defined size.
      * This is used only for computing the inverse.
      */
@@ -100,15 +108,17 @@ final class Solver implements Matrix {
     /**
      * Computes the inverse of the given matrix. This method shall be invoked only for square matrices.
      *
+     * @param  X        The matrix to invert, which must be square.
+     * @param  noChange If {@code true}, do not allow modifications to the {@code X} matrix.
      * @throws NoninvertibleMatrixException If the {@code X} matrix is not square or singular.
      */
-    static MatrixSIS inverse(final MatrixSIS X) throws NoninvertibleMatrixException {
+    static MatrixSIS inverse(final MatrixSIS X, final boolean noChange) throws NoninvertibleMatrixException {
         final int size = X.getNumRow();
         final int numCol = X.getNumCol();
         if (numCol != size) {
             throw new NoninvertibleMatrixException(Errors.format(Errors.Keys.NonInvertibleMatrix_2, size, numCol));
         }
-        return solve(X, IDENTITY, null, size, size);
+        return solve(X, IDENTITY, null, size, size, noChange);
     }
 
     /**
@@ -134,12 +144,16 @@ final class Solver implements Matrix {
                 eltY = null; // Matrix does not contains error terms.
             }
         }
-        return solve(X, Y, eltY, size, innerSize);
+        return solve(X, Y, eltY, size, innerSize, true);
     }
 
     /**
-     * Implementation of {@code solve} and {@code inverse} methods.
-     * Use a "left-looking", dot-product, Crout/Doolittle algorithm.
+     * Implementation of {@code solve} and {@code inverse} methods, with filtering of NaN values.
+     * This method searches for NaN values before to attempt solving or inverting the matrix.
+     * If some NaN values are found but the matrix is written in such a way that each NaN value
+     * is used for exactly one ordinate value (i.e. a matrix row is used for a one-dimensional
+     * conversion which is independent of all other dimensions), then we will edit the matrix in
+     * such a way that this NaN value does not prevent the inverse matrix to be computed.
      *
      * <p>This method does <strong>not</strong> checks the matrix size.
      * Check for matrix size shall be performed by the caller like below:</p>
@@ -154,21 +168,154 @@ final class Solver implements Matrix {
      *     }
      * }
      *
-     * @param  X         The matrix to invert.
+     * @param  X         The matrix to invert, which must be square.
      * @param  Y         The desired result of {@code X} × <var>U</var>.
      * @param  eltY      Elements and error terms of the {@code Y} matrix, or {@code null} if not available.
      * @param  size      The value of {@code X.getNumRow()}, {@code X.getNumCol()} and {@code Y.getNumRow()}.
      * @param  innerSize The value of {@code Y.getNumCol()}.
+     * @param  noChange  If {@code true}, do not allow modifications to the {@code X} matrix.
      * @throws NoninvertibleMatrixException If the {@code X} matrix is not square or singular.
      */
     private static MatrixSIS solve(final MatrixSIS X, final Matrix Y, final double[] eltY,
-            final int size, final int innerSize) throws NoninvertibleMatrixException
+            final int size, final int innerSize, final boolean noChange) throws NoninvertibleMatrixException
     {
         assert (X.getNumRow() == size && X.getNumCol() == size) : size;
         assert (Y.getNumRow() == size && Y.getNumCol() == innerSize) || (Y instanceof Solver);
+        final double[] LU = GeneralMatrix.getExtendedElements(X, size, size, noChange);
+        final int lastRowOrColumn = size - 1;
+        /*
+         * indexOfNaN array will be created only if at least one NaN value is found, and those NaN meet
+         * the conditions documented in the code below. In such case, the array will contain a sequence
+         * of (i,j,s) where (i,j) are the indices where the NaN value has been found and s is the column
+         * of the scale factor.
+         */
+        int[] indexOfNaN = null;
+        int   indexCount = 0;
+        if (X.isAffine()) {
+            /*
+             * Conservatively search for NaN values only if the matrix looks like an affine transform.
+             * If the matrix is affine, then we will assume that we can interpret the last column as
+             * translation terms and other columns as scale factors.
+             *
+             * Note: the iteration below skips the last row, since it is (0, 0, ..., 1).
+             */
+searchNaN:  for (int flatIndex = (size - 1) * size; --flatIndex >= 0;) {
+                if (Double.isNaN(LU[flatIndex])) {
+                    final int j = flatIndex / size;
+                    final int i = flatIndex % size;
+                    /*
+                     * Found a NaN value. First, if we are not in the translation column, ensure
+                     * that the column contains only zero values except on the current line.
+                     */
+                    int columnOfScale = -1;
+                    if (i != lastRowOrColumn) {                // Enter only if this column is not for translations.
+                        columnOfScale = i;                     // The non-translation element is the scale factor.
+                        for (int k=lastRowOrColumn; --k>=0;) { // Scan all other rows in the current column.
+                            if (k != j && LU[k*size + i] != 0) {
+                                // Found a non-zero element in the current column.
+                                // We can not proceed - cancel everything.
+                                indexOfNaN = null;
+                                indexCount = 0;
+                                break searchNaN;
+                            }
+                        }
+                    }
+                    /*
+                     * Next, ensure that the row contains only zero elements except for
+                     * the scale factor and the offset (the element in the translation
+                     * column, which is not checked by the loop below).
+                     */
+                    for (int k=lastRowOrColumn; --k>=0;) {
+                        if (k != i && LU[j*size + k] != 0) {
+                            if (columnOfScale >= 0) {
+                                // If there is more than 1 non-zero element,
+                                // abandon the attempt to handle NaN values.
+                                indexOfNaN = null;
+                                indexCount = 0;
+                                break searchNaN;
+                            }
+                            columnOfScale = k;
+                        }
+                    }
+                    /*
+                     * At this point, the NaN element has been determined as replaceable.
+                     * Remember its index; the replacement will be performed later.
+                     */
+                    if (indexOfNaN == null) {
+                        indexOfNaN = new int[lastRowOrColumn * (2*TUPLE_SIZE)]; // At most one scale and one offset per row.
+                    }
+                    indexOfNaN[indexCount++] = i;
+                    indexOfNaN[indexCount++] = j;
+                    indexOfNaN[indexCount++] = columnOfScale; // May be -1 (while uncommon)
+                    assert (indexCount % TUPLE_SIZE) == 0;
+                }
+            }
+            /*
+             * If there is any NaN value to edit, replace them by 0 if they appear in the translation column
+             * or by 1 otherwise (scale or shear). We perform this replacement after the loop searching for
+             * NaN, not inside the loop, in order to not change anything if the search has been canceled.
+             */
+            for (int k=0; k<indexCount; k += TUPLE_SIZE) {
+                final int i = indexOfNaN[k  ];
+                final int j = indexOfNaN[k+1];
+                final int flatIndex = j*size + i;
+                LU[flatIndex] = (i == lastRowOrColumn) ? 0 : 1;
+                LU[flatIndex + size*size] = 0; // Error term (see 'errorLU') in next method.
+            }
+        }
+        /*
+         * Now apply the inversion.
+         */
+        final MatrixSIS matrix = solve(LU, Y, eltY, size, innerSize);
+        /*
+         * At this point, the matrix has been inverted. If they were any NaN value in the original
+         * matrix, set the corresponding scale factor and offset to NaN in the resulting matrix.
+         */
+        for (int k=0; k<indexCount;) {
+            assert (k % TUPLE_SIZE) == 0;
+            final int i = indexOfNaN[k++];
+            final int j = indexOfNaN[k++];
+            final int s = indexOfNaN[k++];
+            if (i != lastRowOrColumn) {
+                // Found a scale factor to set to NaN.
+                matrix.setElement(i, j, Double.NaN); // Note that i,j indices are interchanged.
+                if (matrix.getElement(i, lastRowOrColumn) != 0) {
+                    matrix.setElement(i, lastRowOrColumn, Double.NaN); // = -offset/scale, so 0 stay 0.
+                }
+            } else if (s >= 0) {
+                // Found a translation factory to set to NaN.
+                matrix.setElement(s, lastRowOrColumn, Double.NaN);
+            }
+        }
+        return matrix;
+    }
 
+    /**
+     * Implementation of {@code solve} and {@code inverse} methods.
+     * This method contains the code ported from the JAMA package.
+     * Use a "left-looking", dot-product, Crout/Doolittle algorithm.
+     *
+     * <p>This method does <strong>not</strong> checks the matrix size.
+     * It is caller's responsibility to ensure that the following hold:</p>
+     *
+     * {@preformat java
+     *   X.getNumRow() == size;
+     *   X.getNumCol() == size;
+     *   Y.getNumRow() == size;
+     *   Y.getNumCol() == innerSize;
+     * }
+     *
+     * @param  LU        Elements of the {@code X} matrix to invert, including error terms.
+     * @param  Y         The desired result of {@code X} × <var>U</var>.
+     * @param  eltY      Elements and error terms of the {@code Y} matrix, or {@code null} if not available.
+     * @param  size      The value of {@code X.getNumRow()}, {@code X.getNumCol()} and {@code Y.getNumRow()}.
+     * @param  innerSize The value of {@code Y.getNumCol()}.
+     * @throws NoninvertibleMatrixException If the {@code X} matrix is not square or singular.
+     */
+    private static MatrixSIS solve(final double[] LU, final Matrix Y, final double[] eltY,
+            final int size, final int innerSize) throws NoninvertibleMatrixException
+    {
         final int errorLU = size * size;
-        final double[] LU = GeneralMatrix.getExtendedElements(X, size, size, true);
         assert errorLU == GeneralMatrix.indexOfErrors(size, size, LU);
         final int[] pivot = new int[size];
         for (int j=0; j<size; j++) {
@@ -256,8 +403,7 @@ final class Solver implements Matrix {
         for (int j=0; j<size; j++) {
             rat.setFrom(LU, j*size + j, errorLU);
             if (rat.isZero()) {
-                final Integer n = size;
-                throw new NoninvertibleMatrixException(Errors.format(Errors.Keys.NonInvertibleMatrix_2, n, n));
+                throw new NoninvertibleMatrixException(Errors.format(Errors.Keys.SingularMatrix));
             }
         }
         /*

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatricesTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatricesTest.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatricesTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatricesTest.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -27,6 +27,7 @@ import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
+import static java.lang.Double.NaN;
 import static org.apache.sis.test.Assert.*;
 import static org.opengis.referencing.cs.AxisDirection.*;
 
@@ -338,14 +339,21 @@ public final strictfp class MatricesTest
                 "│ 0  0  1  0 │\n" +
                 "│ 0  0  0  1 │\n" +
                 "└            ┘\n", new Matrix4().toString());
+
+        assertMultilinesEquals(
+                "┌               ┐\n" +
+                "│   1    0    0 │\n" +
+                "│ NaN  NaN  NaN │\n" +
+                "│   0    0    1 │\n" +
+                "└               ┘\n", new Matrix3(1, 0, 0, NaN, NaN, NaN, 0, 0, 1).toString());
         /*
          * Mix of values with different precision, ±0, ±1, NaN and infinities.
          */
         final MatrixSIS matrix = Matrices.create(4, 5, new double[] {
-            39.5193682106975150,  -68.5200,     -1.0,  1,  98,
-           -66.0358637477182200,   Double.NaN,  43.0,  0,  Double.NEGATIVE_INFINITY,
-             2.0741018968776337,   83.7260,     -0.0,  1,  -3,
-            91.8796187759200600,  -18.2674,     24.5,  0,  36.5
+            39.5193682106975150,  -68.5200,  -1.0,  1,  98,
+           -66.0358637477182200,       NaN,  43.0,  0,  Double.NEGATIVE_INFINITY,
+             2.0741018968776337,   83.7260,  -0.0,  1,  -3,
+            91.8796187759200600,  -18.2674,  24.5,  0,  36.5
         });
         assertMultilinesEquals(
                 "┌                                               ┐\n" +

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -71,4 +71,33 @@ public final strictfp class Matrix3Test 
         validate(matrix);
         assertArrayEquals(elements, matrix.getElements(), STRICT);
     }
+
+    /**
+     * Verifies our claim that {@code A.solve(B)} is equivalent to {@code A.inverse().multiply(B)}.
+     * This claim is documented in {@link MatrixSIS#solve(Matrix)} javadoc.
+     *
+     * @throws NoninvertibleMatrixException Should not happen.
+     */
+    @Test
+    public void testSolveEquivalence() throws NoninvertibleMatrixException {
+        final Matrix3 A = new Matrix3(
+                0.5,  0,    0,
+                0,    0.5,  0,
+                0,    0,    1);
+
+        final Matrix3 B = new Matrix3(
+                0,  3,  0,
+                3,  0,  0,
+                0,  0,  1);
+
+        // Verify the result of A.inverse().multiply(B) as a matter of principle.
+        final double[] expected = A.inverse().multiply(B).getElements();
+        assertArrayEquals(new double[] {
+                0,  6,  0,
+                6,  0,  0,
+                0,  0,  1}, expected, TOLERANCE);
+
+        // Now the actual test.
+        assertMatrixEquals(expected, SIZE, SIZE, A.solve(B), TOLERANCE);
+    }
 }

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix4Test.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -93,10 +93,10 @@ public final strictfp class Matrix4Test 
          * 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);
+                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.

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -181,6 +181,19 @@ public abstract strictfp class MatrixTes
     }
 
     /**
+     * Asserts that the given matrix is equals to the given expected values, up to the given tolerance threshold.
+     * This method compares the elements values in two slightly redundant ways.
+     */
+    static void assertMatrixEquals(final double[] expected, final int numRow, final int numCol,
+            final MatrixSIS actual, final double tolerance)
+    {
+        assertEquals("numRow", numRow, actual.getNumRow());
+        assertEquals("numCol", numCol, actual.getNumCol());
+        assertArrayEquals(expected, actual.getElements(), tolerance); // First because more informative in case of failure.
+        assertTrue(Matrices.create(numRow, numCol, expected).equals(actual, tolerance));
+    }
+
+    /**
      * Creates an array of the given length filled with random values. All random values are between 0 inclusive
      * and 100 exclusive. This method never write negative values. Consequently, any strictly negative value set
      * by the test method is guaranteed to be different than all original values in the returned array.

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/NonSquareMatrixTest.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -21,6 +21,7 @@ import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestUtilities;
 import org.junit.AfterClass;
 
+import static java.lang.Double.NaN;
 import static org.junit.Assert.*;
 
 
@@ -73,19 +74,84 @@ public final strictfp class NonSquareMat
     }
 
     /**
-     * TODO: inverse transform not yet implemented for non-square matrix.
+     * Tests {@link NonSquareMatrix#inverse()} with a non-square matrix.
      */
     @Override
-    @org.junit.Ignore
     public void testInverse() throws NoninvertibleMatrixException {
+        testDimensionReduction(null, 1, 0);
+        testDimensionIncrease (null, 1);
     }
 
     /**
-     * TODO: inverse transform not yet implemented for non-square matrix.
+     * Tests {@link NonSquareMatrix#solve(Matrix)} with a non-square matrix.
      */
     @Override
-    @org.junit.Ignore
     public void testSolve() throws NoninvertibleMatrixException {
+        testDimensionReduction(new Matrix3(
+                2, 0, 0,
+                0, 2, 0,
+                0, 0, 1), 2, NaN);
+        testDimensionIncrease(new GeneralMatrix(5, 5, new double[] {
+                2, 0, 0, 0, 0,
+                0, 2, 0, 0, 0,
+                0, 0, 2, 0, 0,
+                0, 0, 0, 2, 0,
+                0, 0, 0, 0, 1}), 2);
+    }
+
+    /**
+     * Tests {@link NonSquareMatrix#inverse()} or {@link NonSquareMatrix#solve(Matrix)} with a conversion
+     * matrix having more source dimensions (columns) than target dimensions (rows).
+     *
+     * @param  Y    The matrix to give to {@code solve(Y)}, {@code null} for testing {@code inverse()}.
+     * @param  sf   The scale factor by which to multiply all expected scale elements.
+     * @param  uks  Value of unknown scales (O for {@code inverse()}, or NaN for {@code solve(Y)}).
+     * @throws NoninvertibleMatrixException Should never happen.
+     */
+    private static void testDimensionReduction(final MatrixSIS Y, final double sf, final double uks)
+            throws NoninvertibleMatrixException
+    {
+        final MatrixSIS matrix = Matrices.create(3, 5, new double[] {
+            2, 0, 0, 0, 8,
+            0, 0, 4, 0, 5,
+            0, 0, 0, 0, 1
+        });
+        final double[] expected = {
+            0.5*sf,  0,           -4,
+            uks,     uks,        NaN,
+            0,       0.25*sf,  -1.25,
+            uks,     uks,        NaN,
+            0,       0,            1
+        };
+        final MatrixSIS inverse = (Y != null) ? matrix.solve(Y) : matrix.inverse();
+        assertMatrixEquals(expected, 5, 3, inverse, TOLERANCE);
+    }
+
+    /**
+     * Tests {@link NonSquareMatrix#inverse()} or {@link NonSquareMatrix#solve(Matrix)} with a conversion
+     * matrix having more target dimensions (rows) than source dimensions (columns).
+     *
+     * @param  Y    The matrix to give to {@code solve(Y)}, {@code null} for testing {@code inverse()}.
+     * @param  sf   The scale factor by which to multiply all expected scale elements.
+     * @throws NoninvertibleMatrixException Should never happen.
+     */
+    private static void testDimensionIncrease(final MatrixSIS Y, final double sf)
+            throws NoninvertibleMatrixException
+    {
+        final MatrixSIS matrix = Matrices.create(5, 3, new double[] {
+              2,   0,   8,
+            NaN, NaN, NaN,
+              0,   4,   5,
+              0,   0,   0,
+              0,   0,   1
+        });
+        final double[] expected = {
+            0.5*sf,  0,  0,        0,  -4,
+            0,       0,  0.25*sf,  0,  -1.25,
+            0,       0,  0,        0,   1
+        };
+        final MatrixSIS inverse = (Y != null) ? matrix.solve(Y) : matrix.inverse();
+        assertMatrixEquals(expected, 3, 5, inverse, TOLERANCE);
     }
 
     /**

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/SolverTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/SolverTest.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/SolverTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/SolverTest.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -19,10 +19,14 @@ package org.apache.sis.referencing.opera
 import java.util.Random;
 import Jama.Matrix;
 import org.apache.sis.test.DependsOn;
+import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestUtilities;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
+import static java.lang.Double.NaN;
+import static org.apache.sis.referencing.operation.matrix.MatrixTestCase.assertMatrixEquals;
+
 
 /**
  * Tests the {@link Solver} class using <a href="http://math.nist.gov/javanumerics/jama">JAMA</a>
@@ -110,7 +114,97 @@ public final strictfp class SolverTest e
                 continue;
             }
             final MatrixSIS U = Solver.solve(matrix, matrixArg);
-            MatrixTestCase.assertMatrixEquals(jama, U, TOLERANCE);
+            assertMatrixEquals(jama, U, TOLERANCE);
         }
     }
+
+    /**
+     * Tests {@link Solver#inverse(MatrixSIS, boolean)} with a square matrix that contains a {@link Double#NaN} value.
+     *
+     * @throws NoninvertibleMatrixException Should not happen.
+     */
+    @Test
+    @DependsOnMethod("testSolve")
+    public void testInverseWithNaN() throws NoninvertibleMatrixException {
+        /*
+         * Just for making sure that our matrix is correct.
+         */
+        matrix = Matrices.create(5, 5, new double[] {
+            20,  0,   0,   0, -3000,
+            0, -20,   0,   0,  4000,
+            0,   0,   0,   2,    20,
+            0,   0, 400,   0,  2000,
+            0,   0,   0,   0,     1
+        });
+        double[] expected = {
+            0.05,  0,  0,      0,  150,
+            0, -0.05,  0,      0,  200,
+            0,     0,  0, 0.0025,   -5,
+            0,     0,  0.5,    0,  -10,
+            0,     0,  0,      0,    1
+        };
+        MatrixSIS inverse = Solver.inverse(matrix, false);
+        assertMatrixEquals(expected, 5, 5, inverse, TOLERANCE);
+        /*
+         * Set a scale factor to NaN. The translation term for the corresponding
+         * dimension become unknown, so it most become NaN in the inverse matrix.
+         */
+        matrix = Matrices.create(5, 5, new double[] {
+            20,  0,   0,   0, -3000,
+            0, -20,   0,   0,  4000,
+            0,   0,   0, NaN,    20,  // Translation is 20: can not be converted.
+            0,   0, 400,   0,  2000,
+            0,   0,   0,   0,     1
+        });
+        expected = new double[] {
+            0.05,  0,  0,      0,  150,
+            0, -0.05,  0,      0,  200,
+            0,     0,  0, 0.0025,   -5,
+            0,     0,  NaN,    0,  NaN,
+            0,     0,  0,      0,    1
+        };
+        inverse = Solver.inverse(matrix, false);
+        assertMatrixEquals(expected, 5, 5, inverse, TOLERANCE);
+        /*
+         * Set a scale factor to NaN with translation equals to 0.
+         * The zero value should be preserved, since 0 × any == 0
+         * (ignoring infinities).
+         */
+        matrix = Matrices.create(5, 5, new double[] {
+            20,  0,   0,   0, -3000,
+            0, -20,   0,   0,  4000,
+            0,   0,   0, NaN,     0,  // Translation is 0: should be preserved.
+            0,   0, 400,   0,  2000,
+            0,   0,   0,   0,     1
+        });
+        expected = new double[] {
+            0.05,  0,  0,      0,  150,
+            0, -0.05,  0,      0,  200,
+            0,     0,  0, 0.0025,   -5,
+            0,     0,  NaN,    0,    0,
+            0,     0,  0,      0,    1
+        };
+        inverse = Solver.inverse(matrix, false);
+        assertMatrixEquals(expected, 5, 5, inverse, TOLERANCE);
+        /*
+         * Set a translation term to NaN. The translation should be NaN in
+         * the inverse matrix too, but the scale factor can still be compute.
+         */
+        matrix = Matrices.create(5, 5, new double[] {
+            20,  0,   0,   0, -3000,
+            0, -20,   0,   0,  4000,
+            0,   0,   0,   2,   NaN,
+            0,   0, 400,   0,  2000,
+            0,   0,   0,   0,     1
+        });
+        expected = new double[] {
+            0.05,  0,  0,      0,  150,
+            0, -0.05,  0,      0,  200,
+            0,     0,  0, 0.0025,   -5,
+            0,     0,  0.5,    0,  NaN,
+            0,     0,  0,      0,    1
+        };
+        inverse = Solver.inverse(matrix, false);
+        assertMatrixEquals(expected, 5, 5, inverse, TOLERANCE);
+    }
 }

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -65,6 +65,7 @@ public final strictfp class ReferencingT
      */
     @BeforeClass
     public static void verifyTestList() {
-        verifyTestList(ReferencingTestSuite.class, BASE_TEST_CLASSES);
+        assertNoMissingTest(ReferencingTestSuite.class);
+        verifyTestList(ReferencingTestSuite.class);
     }
 }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/DoubleDouble.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -62,6 +62,11 @@ import org.apache.sis.math.MathFunctions
  */
 public final class DoubleDouble extends Number {
     /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = -7602414219228638550L;
+
+    /**
      * {@code true} for disabling the extended precision. This variable should always be {@code false},
      * except for testing purpose. If set to {@code true}, then all double-double arithmetic operations
      * are immediately followed by a clearing of {@link DoubleDouble#error}.  The result should then be
@@ -79,9 +84,11 @@ public final class DoubleDouble extends 
     public static final boolean DISABLED = false;
 
     /**
-     * For cross-version compatibility.
+     * When computing <var>a</var> - <var>b</var> as a double-double (106 significand bits) value,
+     * if the amount of non-zero significand bits is equals or lower than that amount, consider the
+     * result as zero.
      */
-    private static final long serialVersionUID = -7602414219228638550L;
+    private static final int ZERO_THRESHOLD = 3;
 
     /**
      * The split constant used as part of multiplication algorithms. The split algorithm is as below
@@ -426,11 +433,11 @@ public final class DoubleDouble extends 
              * The two values almost cancelled, only their error terms are different.
              * The number of significand bits (mantissa) in the IEEE 'double' representation is 52,
              * not counting the hidden bit. So estimate the accuracy of the double-double number as
-             * the accuracy of the 'double' value (which is 1 ULP) scaled as if we had 50 additional
-             * significand bits (we ignore 2 bits as a safety margin). If the error is not greater
-             * than that value, then assume that it is not significant.
+             * the accuracy of the 'double' value (which is 1 ULP) scaled as if we had 52 additional
+             * significand bits (we ignore some more bits if ZERO_THRESHOLD is greater than 1).
+             * If the error is not greater than that value, then assume that it is not significant.
              */
-            if (Math.abs(error) <= Math.scalb(Math.ulp(otherValue), -50)) {
+            if (Math.abs(error) <= Math.scalb(Math.ulp(otherValue), ZERO_THRESHOLD - Numerics.SIGNIFICAND_SIZE)) {
                 error = 0;
                 return;
             }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -77,6 +77,12 @@ public final class Numerics extends Stat
     public static final long SIGN_BIT_MASK = Long.MIN_VALUE;
 
     /**
+     * Number of bits in the significand (mantissa) part of IEEE 754 {@code double} representation,
+     * including the hidden bit.
+     */
+    static final int SIGNIFICAND_SIZE = 53;
+
+    /**
      * A prime number used for hash code computation. Value 31 is often used because
      * some modern compilers can optimize {@code x*31} as {@code (x << 5) - x}
      * (Josh Bloch, <cite>Effective Java</cite>).

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -536,6 +536,11 @@ public final class Errors extends Indexe
         public static final int RequireDecimalSeparator = 33;
 
         /**
+         * Matrix is singular.
+         */
+        public static final int SingularMatrix = 125;
+
+        /**
          * Thread “{0}” seems stalled.
          */
         public static final int StalledThread_1 = 63;

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] Wed Oct  9 12:37:03 2013
@@ -117,6 +117,7 @@ NullArgument_1                  = Argume
 NullMapKey                      = Null key is not allowed in this dictionary.
 NullMapValue                    = Null values are not allowed in this dictionary.
 OddArrayLength_1                = Array length is {0}, while we expected an even length.
+SingularMatrix                  = Matrix is singular.
 RecursiveCreateCallForKey_1     = Recursive call while creating an object for the \u201c{0}\u201d key.
 RequireDecimalSeparator         = A decimal separator is required.
 StalledThread_1                 = Thread \u201c{0}\u201d seems stalled.

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] Wed Oct  9 12:37:03 2013
@@ -108,6 +108,7 @@ NullMapValue                    = Les va
 OddArrayLength_1                = La longueur du tableau est {0}, alors qu\u2019on attendait une longueur paire.
 RecursiveCreateCallForKey_1     = Appel r\u00e9cursif lors de la cr\u00e9ation d\u2019un objet pour la cl\u00e9 \u201c{0}\u201d.
 RequireDecimalSeparator         = Un s\u00e9parateur d\u00e9cimal est requis.
+SingularMatrix                  = La matrice est singuli\u00e8re.
 StalledThread_1                 = La t\u00e2che \u201c{0}\u201d semble bloqu\u00e9e.
 StreamIsForwardOnly_1           = Ne peut pas reculer dans le flux de donn\u00e9es \u201c{0}\u201d.
 TooFewArguments_2               = Au moins {0} argument{0,choice,1# \u00e9tait attendu|2#s \u00e9taient attendus}, mais seulement {1} {1,choice,1#a \u00e9t\u00e9 sp\u00e9cifi\u00e9|2#ont \u00e9t\u00e9 sp\u00e9cifi\u00e9s}.

Modified: sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -16,8 +16,12 @@
  */
 package org.apache.sis.test;
 
-import java.util.Map;
-import java.util.IdentityHashMap;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.HashSet;
+import java.io.File;
+import java.net.URL;
+import java.net.URISyntaxException;
 import org.apache.sis.util.Classes;
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
@@ -30,16 +34,16 @@ import static org.junit.Assert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-3.16)
- * @version 0.3
+ * @version 0.4
  * @module
  */
 @RunWith(Suite.class)
 public abstract strictfp class TestSuite {
     /**
      * The default set of base classes that all test cases are expected to extends.
-     * This is the usual argument value to the {@link #verifyTestList(Class, Class[])} method.
+     * This is the default argument value for {@link #verifyTestList(Class)} method.
      */
-    protected static final Class<?>[] BASE_TEST_CLASSES = {
+    private static final Class<?>[] BASE_TEST_CLASSES = {
         TestCase.class,
         org.opengis.test.TestCase.class
     };
@@ -51,6 +55,81 @@ public abstract strictfp class TestSuite
     }
 
     /**
+     * Verifies that we did not forgot to declare some test classes in the given suite.
+     * This method scans the directory for {@code *Test.class} files.
+     *
+     * @param suite The suite for which to check for missing tests.
+     */
+    protected static void assertNoMissingTest(final Class<? extends TestSuite> suite) {
+        final ClassLoader loader = suite.getClassLoader();
+        final URL url = loader.getResource(suite.getName().replace('.', '/') + ".class");
+        assertNotNull("Test suite class not found.", url);
+        File root;
+        try {
+            root = new File(url.toURI());
+        } catch (Exception e) { // (URISyntaxException | IllegalArgumentException) on JDK7 branch.
+            // If not a file, then it is probably an entry in a JAR file.
+            fail(e.toString());
+            return;
+        }
+        for (File c = new File(suite.getName().replace('.', File.separatorChar)); (c = c.getParentFile()) != null;) {
+            root = root.getParentFile();
+            assertNotNull("Unexpected directory structure.", root);
+            assertEquals("Unexpected directory structure.", c.getName(), root.getName());
+        }
+        /*
+         * At this point, we found the root "org" package. Verifies if we are in the Maven target directory.
+         * In some IDE configuration, all the ".class" files are in the same directory, in which case the
+         * verification performed by this method become irrelevant.
+         */
+        if (!new File(root.getParent(), ".." + File.separatorChar + "pom.xml").isFile()) {
+            return;
+        }
+        /*
+         * Now scan all "*Test.class" in the "target/org" directory and and sub-directories,
+         * and fail on the first missing test file if any.
+         */
+        final Set<Class<?>> tests = new HashSet<Class<?>>(Arrays.asList(suite.getAnnotation(Suite.SuiteClasses.class).value()));
+        removeExistingTests(loader, root, new StringBuilder(120).append(root.getName()), tests);
+        assertTrue(tests.toString(), tests.isEmpty());
+    }
+
+    /**
+     * Ensures that all tests in the given directory and sub-directories exit in the given set.
+     * This method invokes itself recursively for scanning the sub-directories.
+     */
+    private static void removeExistingTests(final ClassLoader loader, final File directory,
+            final StringBuilder path, final Set<Class<?>> tests)
+    {
+        final int length = path.append('.').length();
+        for (final File file : directory.listFiles()) {
+            if (!file.isHidden()) {
+                final String name = file.getName();
+                if (!name.startsWith(".")) {
+                    path.append(name);
+                    if (file.isDirectory()) {
+                        removeExistingTests(loader, file, path, tests);
+                    } else {
+                        if (name.endsWith("Test.class")) {
+                            path.setLength(path.length() - 6); // Remove trailing ".class"
+                            final String classname = path.toString();
+                            final Class<?> test;
+                            try {
+                                test = Class.forName(classname, false, loader);
+                            } catch (ClassNotFoundException e) {
+                                fail(e.toString());
+                                return;
+                            }
+                            assertTrue(classname, tests.remove(test));
+                        }
+                    }
+                    path.setLength(length);
+                }
+            }
+        }
+    }
+
+    /**
      * Verifies the list of tests before the suite is run.
      * This method verifies the following conditions:
      *
@@ -65,17 +144,29 @@ public abstract strictfp class TestSuite
      * {@preformat java
      *    &#64;BeforeClass
      *    public static void verifyTestList() {
-     *        verifyTestList(MetadataTestSuite.class, BASE_TEST_CLASSES);
+     *        assertNoMissingTest(MyTestSuite.class);
+     *        verifyTestList(MyTestSuite.class);
      *    }
      * }
      *
-     * @param suite The suite for which to verify order.
+     * @param suite The suite for which to verify test order.
+     */
+    protected static void verifyTestList(final Class<? extends TestSuite> suite) {
+        verifyTestList(suite, BASE_TEST_CLASSES);
+    }
+
+    /**
+     * Same verification than {@link #verifyTestList(Class)}, except that the set of base classes
+     * is explicitely specified. This method is preferred to {@code verifyTestList(Class)} only in
+     * the rare cases where some test cases need to extend something else than geoapi-conformance
+     * or Apache SIS test class.
+     *
+     * @param suite The suite for which to verify test order.
      * @param baseTestClasses The set of base classes that all test cases are expected to extends.
-     *        This is usually {@link #BASE_TEST_CLASSES}.
      */
     protected static void verifyTestList(final Class<? extends TestSuite> suite, final Class<?>[] baseTestClasses) {
         final Class<?>[] testCases = suite.getAnnotation(Suite.SuiteClasses.class).value();
-        final Map<Class<?>,Boolean> done = new IdentityHashMap<Class<?>,Boolean>(testCases.length);
+        final Set<Class<?>> done = new HashSet<Class<?>>(testCases.length);
         for (final Class<?> testCase : testCases) {
             if (!Classes.isAssignableToAny(testCase, baseTestClasses)) {
                 fail("Class " + testCase.getCanonicalName() + " does not extends TestCase.");
@@ -83,13 +174,13 @@ public abstract strictfp class TestSuite
             final DependsOn dependencies = testCase.getAnnotation(DependsOn.class);
             if (dependencies != null) {
                 for (final Class<?> dependency : dependencies.value()) {
-                    if (!done.containsKey(dependency)) {
+                    if (!done.contains(dependency)) {
                         fail("Class " + testCase.getCanonicalName() + " depends on " + dependency.getCanonicalName()
                                 + ", but the dependency has not been found before the test.");
                     }
                 }
             }
-            if (done.put(testCase, Boolean.TRUE) != null) {
+            if (!done.add(testCase)) {
                 fail("Class " + testCase.getCanonicalName() + " is declared twice.");
             }
         }

Modified: sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -124,6 +124,7 @@ import org.junit.BeforeClass;
     org.apache.sis.internal.jaxb.gco.StringAdapterTest.class,
     org.apache.sis.internal.jaxb.gco.MeasureTest.class,
     org.apache.sis.internal.jaxb.gco.PropertyTypeTest.class,
+    org.apache.sis.internal.jaxb.gmd.LanguageMarshallingTest.class,
     org.apache.sis.util.iso.NameMarshallingTest.class
 })
 public final strictfp class UtilityTestSuite extends TestSuite {
@@ -133,6 +134,7 @@ public final strictfp class UtilityTestS
      */
     @BeforeClass
     public static void verifyTestList() {
-        verifyTestList(UtilityTestSuite.class, BASE_TEST_CLASSES);
+        assertNoMissingTest(UtilityTestSuite.class);
+        verifyTestList(UtilityTestSuite.class);
     }
 }

Modified: sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/collection/CacheTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/collection/CacheTest.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/collection/CacheTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/collection/CacheTest.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -58,7 +58,8 @@ public final strictfp class CacheTest ex
      */
     @Test
     public void testStrongReferences() {
-        WeakValueHashMapTest.testStrongReferences(new Cache<Integer,Integer>(500, 0, false));
+        WeakValueHashMapTest.testStrongReferences(
+                new Cache<Integer,Integer>(WeakValueHashMapTest.SAMPLE_SIZE, 0, false));
     }
 
     /**
@@ -72,7 +73,8 @@ public final strictfp class CacheTest ex
     @Test
     @DependsOnMethod("testStrongReferences")
     public void testWeakReferences() throws InterruptedException {
-        WeakValueHashMapTest.testWeakReferences(new Cache<Integer,Integer>(500, 0, false));
+        WeakValueHashMapTest.testWeakReferences(
+                new Cache<Integer,Integer>(WeakValueHashMapTest.SAMPLE_SIZE, 0, false));
     }
 
     /**
@@ -207,7 +209,7 @@ public final strictfp class CacheTest ex
     @Performance
     @DependsOnMethod("testThreadBlocking")
     public void stress() throws InterruptedException {
-        final int count = 10000;
+        final int count = 5000;
         final Cache<Integer,Integer> cache = new Cache<Integer,Integer>();
         final AtomicReference<Throwable> failures = new AtomicReference<Throwable>();
         final class WriterThread extends Thread {
@@ -309,7 +311,8 @@ public final strictfp class CacheTest ex
          */
         final Statistics afterGC = validateStressEntries("After GC", cache);
         out.println("Statistics on the keys before and after garbage collection.");
-        out.println("The minimum value should be greater after GC.");
+        out.println("The minimum value shall always be equals or greater after GC.");
+        out.println("The mean value is usually greater too, except by coincidence.");
         final StatisticsFormat format = StatisticsFormat.getInstance();
         format.setBorderWidth(1);
         try {

Modified: sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/collection/WeakValueHashMapTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/collection/WeakValueHashMapTest.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/collection/WeakValueHashMapTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/test/java/org/apache/sis/util/collection/WeakValueHashMapTest.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -44,7 +44,7 @@ public final strictfp class WeakValueHas
     /**
      * The size of the test sets to be created.
      */
-    private static final int SAMPLE_SIZE = 500;
+    static final int SAMPLE_SIZE = 400;
 
     /**
      * Number of time to retry the tests.

Modified: sis/trunk/core/sis-utility/src/test/java/org/apache/sis/xml/OGCNamespacePrefixMapperTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/test/java/org/apache/sis/xml/OGCNamespacePrefixMapperTest.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/test/java/org/apache/sis/xml/OGCNamespacePrefixMapperTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/test/java/org/apache/sis/xml/OGCNamespacePrefixMapperTest.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -56,7 +56,7 @@ public final strictfp class OGCNamespace
         try {
             ensureOverrideMethods(new OGCNamespacePrefixMapper(null));
         } catch (NoClassDefFoundError e) {
-            assumeNoException(e);
+            // Ignore the exception, since it may be normal.
         }
     }
 
@@ -73,7 +73,7 @@ public final strictfp class OGCNamespace
         try {
             ensureOverrideMethods(new OGCNamespacePrefixMapper_Endorsed(null));
         } catch (NoClassDefFoundError e) {
-            assumeNoException(e);
+            // Ignore the exception, since it may be normal.
         }
     }
 

Modified: sis/trunk/pom.xml
URL: http://svn.apache.org/viewvc/sis/trunk/pom.xml?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/pom.xml (original)
+++ sis/trunk/pom.xml Wed Oct  9 12:37:03 2013
@@ -438,12 +438,22 @@ Apache SIS is a free software, Java lang
         </configuration>
       </plugin>
 
+      <!-- Execute test suites instead of individual test cases. -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <includes>
+            <include>**/*TestSuite.java</include>
+          </includes>
+        </configuration>
+      </plugin>
+
       <!-- JAR packaging
            Note: <index> and <addClasspath> are mutually exclusive: when both are enabled,
            the META-INF/INDEX.LIST file has precedence over the "Class-Path" entry in the
            META-INF/MANIFEST.MF file,  thus causing java.lang.NoClassDefFoundError if the
-           INDEX.LIST file is incomplete (which seem to happen in practice).
-      -->
+           INDEX.LIST file is incomplete (which seem to happen in practice). -->
       <plugin>
         <artifactId>maven-jar-plugin</artifactId>
         <configuration>

Modified: sis/trunk/storage/sis-netcdf/src/test/java/org/apache/sis/test/suite/NetcdfTestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/test/java/org/apache/sis/test/suite/NetcdfTestSuite.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/test/java/org/apache/sis/test/suite/NetcdfTestSuite.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/test/java/org/apache/sis/test/suite/NetcdfTestSuite.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -49,6 +49,7 @@ public final strictfp class NetcdfTestSu
      */
     @BeforeClass
     public static void verifyTestList() {
+        assertNoMissingTest(NetcdfTestSuite.class);
         verifyTestList(NetcdfTestSuite.class, new Class<?>[] {
             TestCase.class,
             IOTestCase.class

Modified: sis/trunk/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/CmdLineDriverTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/CmdLineDriverTest.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/CmdLineDriverTest.java [UTF-8] (original)
+++ sis/trunk/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/CmdLineDriverTest.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -17,9 +17,10 @@
 package org.apache.sis.storage.shapefile;
 
 import java.io.IOException;
+import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 
 /**
@@ -30,7 +31,7 @@ import static org.junit.Assert.assertTru
  * @version 0.4
  * @module
  */
-public final strictfp class CmdLineDriverTest {
+public final strictfp class CmdLineDriverTest extends TestCase {
 
     @Test
     public void testApp() throws IOException {

Modified: sis/trunk/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/ShapeFileTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/ShapeFileTest.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/ShapeFileTest.java [UTF-8] (original)
+++ sis/trunk/storage/sis-shapefile/src/test/java/org/apache/sis/storage/shapefile/ShapeFileTest.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -18,12 +18,12 @@ package org.apache.sis.storage.shapefile
 
 import java.io.File;
 import java.io.IOException;
-
 import java.net.URISyntaxException;
 import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.*;
 
 
 /**
@@ -33,7 +33,7 @@ import static junit.framework.Assert.ass
  * @version 0.4
  * @module
  */
-public final strictfp class ShapeFileTest {
+public final strictfp class ShapeFileTest extends TestCase {
     private static String path(final String name) throws IOException, URISyntaxException {
         return new File(ShapeFileTest.class.getResource(name).toURI()).getPath();
     }

Modified: sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/storage/ProbeResult.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/storage/ProbeResult.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/storage/ProbeResult.java [UTF-8] (original)
+++ sis/trunk/storage/sis-storage/src/main/java/org/apache/sis/storage/ProbeResult.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -192,12 +192,12 @@ public class ProbeResult implements Seri
      *
      * <table class="sis">
      *   <tr><th>MIME type</th>                                                    <th>Description</th>                                 <th>Namespace</th></tr>
-     *   <tr><td>{@code "application/gml+xml"}</td>                                <td>Official mime type for OGC GML</td>              <td>{@value org.apache.sis.XML.Namespaces#GML}</td></tr>
+     *   <tr><td>{@code "application/gml+xml"}</td>                                <td>Official mime type for OGC GML</td>              <td>{@value org.apache.sis.xml.Namespaces#GML}</td></tr>
      *   <tr><td>{@code "application/vnd.eu.europa.ec.inspire.resource+xml"}</td>  <td>Official mime type for INSPIRE Resources</td>    <td></td></tr>
-     *   <tr><td>{@code "application/vnd.iso.19139+xml"}</td>                      <td>Unofficial mime type for ISO 19139 metadata</td> <td>{@value org.apache.sis.XML.Namespaces#GMD}</td></tr>
+     *   <tr><td>{@code "application/vnd.iso.19139+xml"}</td>                      <td>Unofficial mime type for ISO 19139 metadata</td> <td>{@value org.apache.sis.xml.Namespaces#GMD}</td></tr>
      *   <tr><td>{@code "application/vnd.ogc.wms_xml"}</td>                        <td>Unofficial mime type for OGC WMS</td>            <td></td></tr>
      *   <tr><td>{@code "application/vnd.ogc.wfs_xml"}</td>                        <td>Unofficial mime type for OGC WFS </td>           <td></td></tr>
-     *   <tr><td>{@code "application/vnd.ogc.csw_xml"}</td>                        <td>Unofficial mime type for OGC CSW</td>            <td>{@value org.apache.sis.XML.Namespaces#CSW}</td></tr>
+     *   <tr><td>{@code "application/vnd.ogc.csw_xml"}</td>                        <td>Unofficial mime type for OGC CSW</td>            <td>{@value org.apache.sis.xml.Namespaces#CSW}</td></tr>
      *   <tr><td>{@code "application/vnd.google-earth.kml+xml"}</td>               <td></td><td></td></tr>
      *   <tr><td>{@code "application/rdf+xml"}</td>                                <td></td><td></td></tr>
      *   <tr><td>{@code "application/soap+xml"}</td>                               <td></td><td></td></tr>

Modified: sis/trunk/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java?rev=1530584&r1=1530583&r2=1530584&view=diff
==============================================================================
--- sis/trunk/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java [UTF-8] (original)
+++ sis/trunk/storage/sis-storage/src/test/java/org/apache/sis/test/suite/StorageTestSuite.java [UTF-8] Wed Oct  9 12:37:03 2013
@@ -48,6 +48,7 @@ public final strictfp class StorageTestS
      */
     @BeforeClass
     public static void verifyTestList() {
-        verifyTestList(StorageTestSuite.class, BASE_TEST_CLASSES);
+        assertNoMissingTest(StorageTestSuite.class);
+        verifyTestList(StorageTestSuite.class);
     }
 }



Mime
View raw message