Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 63A21200C56 for ; Fri, 14 Apr 2017 17:51:04 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 60C58160B8C; Fri, 14 Apr 2017 15:51:04 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 40FA0160BAF for ; Fri, 14 Apr 2017 17:51:02 +0200 (CEST) Received: (qmail 46594 invoked by uid 500); 14 Apr 2017 15:51:01 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 46295 invoked by uid 99); 14 Apr 2017 15:51:00 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 14 Apr 2017 15:51:00 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 1E557E0117; Fri, 14 Apr 2017 15:51:00 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: av@apache.org To: commits@ignite.apache.org Date: Fri, 14 Apr 2017 15:51:04 -0000 Message-Id: In-Reply-To: <0b1063d4bce14dfe90e596512f497ab6@git.apache.org> References: <0b1063d4bce14dfe90e596512f497ab6@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [05/13] ignite git commit: IGNITE-4572 Machine Learning: Develop distributed algebra support for dense and sparse data sets. archived-at: Fri, 14 Apr 2017 15:51:04 -0000 http://git-wip-us.apache.org/repos/asf/ignite/blob/acd21fb8/modules/math/src/test/java/org/apache/ignite/math/decompositions/CholeskyDecompositionTest.java ---------------------------------------------------------------------- diff --git a/modules/math/src/test/java/org/apache/ignite/math/decompositions/CholeskyDecompositionTest.java b/modules/math/src/test/java/org/apache/ignite/math/decompositions/CholeskyDecompositionTest.java new file mode 100644 index 0000000..fa311e0 --- /dev/null +++ b/modules/math/src/test/java/org/apache/ignite/math/decompositions/CholeskyDecompositionTest.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.math.decompositions; + +import org.apache.ignite.math.Matrix; +import org.apache.ignite.math.Vector; +import org.apache.ignite.math.exceptions.CardinalityException; +import org.apache.ignite.math.exceptions.NonPositiveDefiniteMatrixException; +import org.apache.ignite.math.exceptions.NonSymmetricMatrixException; +import org.apache.ignite.math.impls.matrix.DenseLocalOnHeapMatrix; +import org.apache.ignite.math.impls.matrix.PivotedMatrixView; +import org.apache.ignite.math.impls.vector.DenseLocalOnHeapVector; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** */ +public class CholeskyDecompositionTest { + /** */ + @Test + public void basicTest() { + basicTest(new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d, 0.0d}, + {-1.0d, 2.0d, -1.0d}, + {0.0d, -1.0d, 2.0d} + })); + } + + /** + * Test for {@link DecompositionSupport} features. + */ + @Test + public void decompositionSupportTest() { + basicTest(new PivotedMatrixView(new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d, 0.0d}, + {-1.0d, 2.0d, -1.0d}, + {0.0d, -1.0d, 2.0d} + }))); + } + + /** */ + @Test(expected = AssertionError.class) + public void nullMatrixTest() { + new CholeskyDecomposition(null); + } + + /** */ + @Test(expected = CardinalityException.class) + public void wrongMatrixSizeTest() { + new CholeskyDecomposition(new DenseLocalOnHeapMatrix(2, 3)); + } + + /** */ + @Test(expected = NonSymmetricMatrixException.class) + public void nonSymmetricMatrixTest() { + new CholeskyDecomposition(new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d, 10.0d}, + {-1.0d, 2.0d, -1.0d}, + {-10.0d, -1.0d, 2.0d} + })); + } + + /** */ + @Test(expected = NonPositiveDefiniteMatrixException.class) + public void nonAbsPositiveMatrixTest() { + new CholeskyDecomposition(new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d, 0.0d}, + {-1.0d, 0.0d, -1.0d}, + {0.0d, -1.0d, 2.0d} + })); + } + + /** */ + @Test(expected = CardinalityException.class) + public void solveWrongVectorSizeTest() { + new CholeskyDecomposition(new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d, 0.0d}, + {-1.0d, 2.0d, -1.0d}, + {0.0d, -1.0d, 2.0d} + })).solve(new DenseLocalOnHeapVector(2)); + } + + /** */ + @Test(expected = CardinalityException.class) + public void solveWrongMatrixSizeTest() { + new CholeskyDecomposition(new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d, 0.0d}, + {-1.0d, 2.0d, -1.0d}, + {0.0d, -1.0d, 2.0d} + })).solve(new DenseLocalOnHeapMatrix(2, 3)); + } + + /** */ + private void basicTest(Matrix m) { + // This decomposition is useful when dealing with systems of linear equations of the form + // m x = b where m is a Hermitian matrix. + // For such systems Cholesky decomposition provides + // more effective method of solving compared to LU decomposition. + // Suppose we want to solve system + // m x = b for various bs. Then after we computed Cholesky decomposition, we can feed various bs + // as a matrix of the form + // (b1, b2, ..., bm) + // to the method Cholesky::solve which returns solutions in the form + // (sol1, sol2, ..., solm) + CholeskyDecomposition dec = new CholeskyDecomposition(m); + assertEquals("Unexpected value for decomposition determinant.", + 4d, dec.getDeterminant(), 0d); + + Matrix l = dec.getL(); + Matrix lt = dec.getLT(); + + assertNotNull("Matrix l is expected to be not null.", l); + assertNotNull("Matrix lt is expected to be not null.", lt); + + for (int row = 0; row < l.rowSize(); row++) + for (int col = 0; col < l.columnSize(); col++) + assertEquals("Unexpected value transposed matrix at (" + row + "," + col + ").", + l.get(row, col), lt.get(col, row), 0d); + + Matrix bs = new DenseLocalOnHeapMatrix(new double[][] { + {4.0, -6.0, 7.0}, + {1.0, 1.0, 1.0} + }).transpose(); + Matrix sol = dec.solve(bs); + + assertNotNull("Solution matrix is expected to be not null.", sol); + assertEquals("Solution rows are not as expected.", bs.rowSize(), sol.rowSize()); + assertEquals("Solution columns are not as expected.", bs.columnSize(), sol.columnSize()); + + for (int i = 0; i < sol.columnSize(); i++) + assertNotNull("Solution matrix column is expected to be not null at index " + i, sol.viewColumn(i)); + + Vector b = new DenseLocalOnHeapVector(new double[] {4.0, -6.0, 7.0}); + Vector solVec = dec.solve(b); + + for (int idx = 0; idx < b.size(); idx++) + assertEquals("Unexpected value solution vector at " + idx, + b.get(idx), solVec.get(idx), 0d); + + dec.destroy(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/acd21fb8/modules/math/src/test/java/org/apache/ignite/math/decompositions/EigenDecompositionTest.java ---------------------------------------------------------------------- diff --git a/modules/math/src/test/java/org/apache/ignite/math/decompositions/EigenDecompositionTest.java b/modules/math/src/test/java/org/apache/ignite/math/decompositions/EigenDecompositionTest.java new file mode 100644 index 0000000..e4e7b15 --- /dev/null +++ b/modules/math/src/test/java/org/apache/ignite/math/decompositions/EigenDecompositionTest.java @@ -0,0 +1,193 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.math.decompositions; + +import org.apache.ignite.math.Matrix; +import org.apache.ignite.math.Vector; +import org.apache.ignite.math.impls.matrix.DenseLocalOnHeapMatrix; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * Tests for {@link EigenDecomposition} + */ +public class EigenDecompositionTest { + /** */ + private static final double EPSILON = 1e-11; + + /** */ + @Test + public void testMatrixWithRealEigenvalues() { + test(new double[][] { + {1.0d, 0.0d, 0.0d, 0.0d}, + {0.0d, 1.0d, 0.0d, 0.0d}, + {0.0d, 0.0d, 2.0d, 0.0d}, + {1.0d, 1.0d, 0.0d, 2.0d}}, + new double[] {1, 2, 2, 1}); + } + + /** */ + @Test + public void testSymmetricMatrix() { + EigenDecomposition decomposition = new EigenDecomposition(new DenseLocalOnHeapMatrix(new double[][] { + {1.0d, 0.0d, 0.0d, 1.0d}, + {0.0d, 1.0d, 0.0d, 1.0d}, + {0.0d, 0.0d, 2.0d, 0.0d}, + {1.0d, 1.0d, 0.0d, 2.0d}})); + + Matrix d = decomposition.getD(); + Matrix v = decomposition.getV(); + + assertNotNull("Matrix d is expected to be not null.", d); + assertNotNull("Matrix v is expected to be not null.", v); + + assertEquals("Unexpected rows in d matrix.", 4, d.rowSize()); + assertEquals("Unexpected cols in d matrix.", 4, d.columnSize()); + + assertEquals("Unexpected rows in v matrix.", 4, v.rowSize()); + assertEquals("Unexpected cols in v matrix.", 4, v.columnSize()); + + assertIsDiagonalNonZero(d); + + decomposition.destroy(); + } + + /** */ + @Test + public void testNonSquareMatrix() { + EigenDecomposition decomposition = new EigenDecomposition(new DenseLocalOnHeapMatrix(new double[][] { + {1.0d, 0.0d, 0.0d}, + {0.0d, 1.0d, 0.0d}, + {0.0d, 0.0d, 2.0d}, + {1.0d, 1.0d, 0.0d}})); + // todo find out why decomposition of 3X4 matrix throws row index exception + + Matrix d = decomposition.getD(); + Matrix v = decomposition.getV(); + + assertNotNull("Matrix d is expected to be not null.", d); + assertNotNull("Matrix v is expected to be not null.", v); + + assertEquals("Unexpected rows in d matrix.", 4, d.rowSize()); + assertEquals("Unexpected cols in d matrix.", 4, d.columnSize()); + + assertEquals("Unexpected rows in v matrix.", 4, v.rowSize()); + assertEquals("Unexpected cols in v matrix.", 3, v.columnSize()); + + assertIsDiagonal(d, true); + + decomposition.destroy(); + } + + /** */ + private void test(double[][] mRaw, double[] expRealEigenValues) { + DenseLocalOnHeapMatrix m = new DenseLocalOnHeapMatrix(mRaw); + EigenDecomposition decomposition = new EigenDecomposition(m); + + Matrix d = decomposition.getD(); + Matrix v = decomposition.getV(); + + assertIsDiagonalNonZero(d); + + // check that d's diagonal consists of eigenvalues of m. + assertDiagonalConsistsOfEigenvalues(m, d, v); + + // m = v d v^{-1} is equivalent to + // m v = v d + assertMatricesAreEqual(m.times(v), v.times(d)); + + assertEigenvalues(decomposition, expRealEigenValues); + + decomposition.destroy(); + } + + /** */ + private void assertEigenvalues(EigenDecomposition decomposition, double[] expRealEigenValues) { + Vector real = decomposition.getRealEigenValues(); + Vector imag = decomposition.getImagEigenvalues(); + + assertEquals("Real values size differs from expected.", expRealEigenValues.length, real.size()); + assertEquals("Imag values size differs from expected.", expRealEigenValues.length, imag.size()); + + for (int idx = 0; idx < expRealEigenValues.length; idx++) { + assertEquals("Real eigen value differs from expected at " + idx, + expRealEigenValues[idx], real.get(idx), 0d); + + assertEquals("Imag eigen value differs from expected at " + idx, + 0d, imag.get(idx), 0d); + } + + } + + /** */ + private void assertDiagonalConsistsOfEigenvalues(DenseLocalOnHeapMatrix m, Matrix d, Matrix v) { + int n = m.columnSize(); + for (int i = 0; i < n; i++) { + Vector eigenVector = v.viewColumn(i); + double eigenVal = d.getX(i, i); + assertVectorsAreEqual(m.times(eigenVector), eigenVector.times(eigenVal)); + } + + } + + /** */ + private void assertMatricesAreEqual(Matrix exp, Matrix actual) { + assertTrue("The row sizes of matrices are not equal", exp.rowSize() == actual.rowSize()); + assertTrue("The col sizes of matrices are not equal", exp.columnSize() == actual.columnSize()); + + // Since matrix is square, we need only one dimension + int n = exp.columnSize(); + + for (int i = 0; i < n; i++) + for (int j = 0; j < n; j++) + assertEquals("Values should be equal", exp.getX(i, j), actual.getX(i, j), EPSILON); + } + + /** */ + private void assertVectorsAreEqual(Vector exp, Vector actual) { + assertTrue("Vectors sizes are not equal", exp.size() == actual.size()); + + // Since matrix is square, we need only one dimension + int n = exp.size(); + + for (int i = 0; i < n; i++) + assertEquals("Values should be equal", exp.getX(i), actual.getX(i), EPSILON); + } + + /** */ + private void assertIsDiagonalNonZero(Matrix m) { + assertIsDiagonal(m, false); + } + + /** */ + private void assertIsDiagonal(Matrix m, boolean zeroesAllowed) { + // Since matrix is square, we need only one dimension + int n = m.columnSize(); + + assertEquals("Diagonal matrix is not square", n, m.rowSize()); + + for (int i = 0; i < n; i++) + for (int j = 0; j < n; j++) + assertTrue("Matrix is not diagonal, violation at (" + i + "," + j + ")", + ((i == j) && (zeroesAllowed || m.getX(i, j) != 0)) + || ((i != j) && m.getX(i, j) == 0)); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/acd21fb8/modules/math/src/test/java/org/apache/ignite/math/decompositions/LUDecompositionTest.java ---------------------------------------------------------------------- diff --git a/modules/math/src/test/java/org/apache/ignite/math/decompositions/LUDecompositionTest.java b/modules/math/src/test/java/org/apache/ignite/math/decompositions/LUDecompositionTest.java new file mode 100644 index 0000000..0feb48f --- /dev/null +++ b/modules/math/src/test/java/org/apache/ignite/math/decompositions/LUDecompositionTest.java @@ -0,0 +1,250 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.math.decompositions; + +import org.apache.ignite.math.Matrix; +import org.apache.ignite.math.Vector; +import org.apache.ignite.math.exceptions.CardinalityException; +import org.apache.ignite.math.exceptions.SingularMatrixException; +import org.apache.ignite.math.impls.matrix.DenseLocalOnHeapMatrix; +import org.apache.ignite.math.impls.matrix.PivotedMatrixView; +import org.apache.ignite.math.impls.vector.DenseLocalOnHeapVector; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Tests for {@link LUDecomposition}. + */ +public class LUDecompositionTest { + /** */ + private Matrix testL; + /** */ + private Matrix testU; + /** */ + private Matrix testP; + /** */ + private Matrix testMatrix; + /** */ + private int[] rawPivot; + + /** */ + @Before + public void setUp() { + double[][] rawMatrix = new double[][] { + {2.0d, 1.0d, 1.0d, 0.0d}, + {4.0d, 3.0d, 3.0d, 1.0d}, + {8.0d, 7.0d, 9.0d, 5.0d}, + {6.0d, 7.0d, 9.0d, 8.0d}}; + double[][] rawL = { + {1.0d, 0.0d, 0.0d, 0.0d}, + {3.0d / 4.0d, 1.0d, 0.0d, 0.0d}, + {1.0d / 2.0d, -2.0d / 7.0d, 1.0d, 0.0d}, + {1.0d / 4.0d, -3.0d / 7.0d, 1.0d / 3.0d, 1.0d}}; + double[][] rawU = { + {8.0d, 7.0d, 9.0d, 5.0d}, + {0.0d, 7.0d / 4.0d, 9.0d / 4.0d, 17.0d / 4.0d}, + {0.0d, 0.0d, -6.0d / 7.0d, -2.0d / 7.0d}, + {0.0d, 0.0d, 0.0d, 2.0d / 3.0d}}; + double[][] rawP = new double[][] { + {0, 0, 1.0d, 0}, + {0, 0, 0, 1.0d}, + {0, 1.0d, 0, 0}, + {1.0d, 0, 0, 0}}; + + rawPivot = new int[] {3, 4, 2, 1}; + + testMatrix = new DenseLocalOnHeapMatrix(rawMatrix); + testL = new DenseLocalOnHeapMatrix(rawL); + testU = new DenseLocalOnHeapMatrix(rawU); + testP = new DenseLocalOnHeapMatrix(rawP); + } + + /** */ + @Test + public void getL() throws Exception { + Matrix luDecompositionL = new LUDecomposition(testMatrix).getL(); + + assertEquals("Unexpected row size.", testL.rowSize(), luDecompositionL.rowSize()); + assertEquals("Unexpected column size.", testL.columnSize(), luDecompositionL.columnSize()); + + for (int i = 0; i < testL.rowSize(); i++) + for (int j = 0; j < testL.columnSize(); j++) + assertEquals("Unexpected value at (" + i + "," + j + ").", + testL.getX(i, j), luDecompositionL.getX(i, j), 0.0000001d); + + luDecompositionL.destroy(); + } + + /** */ + @Test + public void getU() throws Exception { + Matrix luDecompositionU = new LUDecomposition(testMatrix).getU(); + + assertEquals("Unexpected row size.", testU.rowSize(), luDecompositionU.rowSize()); + assertEquals("Unexpected column size.", testU.columnSize(), luDecompositionU.columnSize()); + + for (int i = 0; i < testU.rowSize(); i++) + for (int j = 0; j < testU.columnSize(); j++) + assertEquals("Unexpected value at (" + i + "," + j + ").", + testU.getX(i, j), luDecompositionU.getX(i, j), 0.0000001d); + + luDecompositionU.destroy(); + } + + /** */ + @Test + public void getP() throws Exception { + Matrix luDecompositionP = new LUDecomposition(testMatrix).getP(); + + assertEquals("Unexpected row size.", testP.rowSize(), luDecompositionP.rowSize()); + assertEquals("Unexpected column size.", testP.columnSize(), luDecompositionP.columnSize()); + + for (int i = 0; i < testP.rowSize(); i++) + for (int j = 0; j < testP.columnSize(); j++) + assertEquals("Unexpected value at (" + i + "," + j + ").", + testP.getX(i, j), luDecompositionP.getX(i, j), 0.0000001d); + + luDecompositionP.destroy(); + } + + /** */ + @Test + public void getPivot() throws Exception { + Vector pivot = new LUDecomposition(testMatrix).getPivot(); + + assertEquals("Unexpected pivot size.", rawPivot.length, pivot.size()); + + for (int i = 0; i < testU.rowSize(); i++) + assertEquals("Unexpected value at " + i, rawPivot[i], (int)pivot.get(i) + 1); + } + + /** + * Test for {@link DecompositionSupport} features. + */ + @Test + public void decompositionSupportTest() { + LUDecomposition dec = new LUDecomposition(new PivotedMatrixView(testMatrix)); + Matrix luDecompositionL = dec.getL(); + + assertEquals("Unexpected L row size.", testL.rowSize(), luDecompositionL.rowSize()); + assertEquals("Unexpected L column size.", testL.columnSize(), luDecompositionL.columnSize()); + + for (int i = 0; i < testL.rowSize(); i++) + for (int j = 0; j < testL.columnSize(); j++) + assertEquals("Unexpected L value at (" + i + "," + j + ").", + testL.getX(i, j), luDecompositionL.getX(i, j), 0.0000001d); + + Matrix luDecompositionU = dec.getU(); + + assertEquals("Unexpected U row size.", testU.rowSize(), luDecompositionU.rowSize()); + assertEquals("Unexpected U column size.", testU.columnSize(), luDecompositionU.columnSize()); + + for (int i = 0; i < testU.rowSize(); i++) + for (int j = 0; j < testU.columnSize(); j++) + assertEquals("Unexpected U value at (" + i + "," + j + ").", + testU.getX(i, j), luDecompositionU.getX(i, j), 0.0000001d); + + Matrix luDecompositionP = dec.getP(); + + assertEquals("Unexpected P row size.", testP.rowSize(), luDecompositionP.rowSize()); + assertEquals("Unexpected P column size.", testP.columnSize(), luDecompositionP.columnSize()); + + for (int i = 0; i < testP.rowSize(); i++) + for (int j = 0; j < testP.columnSize(); j++) + assertEquals("Unexpected P value at (" + i + "," + j + ").", + testP.getX(i, j), luDecompositionP.getX(i, j), 0.0000001d); + + dec.destroy(); + } + + /** */ + @Test + public void singularDeterminant() throws Exception { + assertEquals("Unexpected determinant for singular matrix decomposition.", + 0d, new LUDecomposition(new DenseLocalOnHeapMatrix(2, 2)).determinant(), 0d); + } + + /** */ + @Test(expected = CardinalityException.class) + public void solveVecWrongSize() throws Exception { + new LUDecomposition(testMatrix).solve(new DenseLocalOnHeapVector(testMatrix.rowSize() + 1)); + } + + /** */ + @Test(expected = SingularMatrixException.class) + public void solveVecSingularMatrix() throws Exception { + new LUDecomposition(new DenseLocalOnHeapMatrix(testMatrix.rowSize(), testMatrix.rowSize())) + .solve(new DenseLocalOnHeapVector(testMatrix.rowSize())); + } + + /** */ + @Test + public void solveVec() throws Exception { + Vector sol = new LUDecomposition(new PivotedMatrixView(testMatrix)) + .solve(new DenseLocalOnHeapVector(testMatrix.rowSize())); + + assertEquals("Wrong solution vector size.", testMatrix.rowSize(), sol.size()); + + for (int i = 0; i < sol.size(); i++) + assertEquals("Unexpected value at index " + i, 0d, sol.getX(i), 0.0000001d); + } + + /** */ + @Test(expected = CardinalityException.class) + public void solveMtxWrongSize() throws Exception { + new LUDecomposition(testMatrix).solve( + new DenseLocalOnHeapMatrix(testMatrix.rowSize() + 1, testMatrix.rowSize())); + } + + /** */ + @Test(expected = SingularMatrixException.class) + public void solveMtxSingularMatrix() throws Exception { + new LUDecomposition(new DenseLocalOnHeapMatrix(testMatrix.rowSize(), testMatrix.rowSize())) + .solve(new DenseLocalOnHeapMatrix(testMatrix.rowSize(), testMatrix.rowSize())); + } + + /** */ + @Test + public void solveMtx() throws Exception { + Matrix sol = new LUDecomposition(new PivotedMatrixView(testMatrix)) + .solve(new DenseLocalOnHeapMatrix(testMatrix.rowSize(), testMatrix.rowSize())); + + assertEquals("Wrong solution matrix row size.", testMatrix.rowSize(), sol.rowSize()); + + assertEquals("Wrong solution matrix column size.", testMatrix.rowSize(), sol.columnSize()); + + for (int row = 0; row < sol.rowSize(); row++) + for (int col = 0; col < sol.columnSize(); col++) + assertEquals("Unexpected P value at (" + row + "," + col + ").", + 0d, sol.getX(row, col), 0.0000001d); + } + + /** */ + @Test(expected = AssertionError.class) + public void nullMatrixTest() { + new LUDecomposition(null); + } + + /** */ + @Test(expected = CardinalityException.class) + public void nonSquareMatrixTest() { + new LUDecomposition(new DenseLocalOnHeapMatrix(2, 3)); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/acd21fb8/modules/math/src/test/java/org/apache/ignite/math/decompositions/QRDecompositionTest.java ---------------------------------------------------------------------- diff --git a/modules/math/src/test/java/org/apache/ignite/math/decompositions/QRDecompositionTest.java b/modules/math/src/test/java/org/apache/ignite/math/decompositions/QRDecompositionTest.java new file mode 100644 index 0000000..3bb92d1 --- /dev/null +++ b/modules/math/src/test/java/org/apache/ignite/math/decompositions/QRDecompositionTest.java @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.math.decompositions; + +import org.apache.ignite.math.Matrix; +import org.apache.ignite.math.impls.matrix.DenseLocalOnHeapMatrix; +import org.apache.ignite.math.impls.matrix.PivotedMatrixView; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** */ +public class QRDecompositionTest { + /** */ + @Test + public void basicTest() { + basicTest(new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d, 0.0d}, + {-1.0d, 2.0d, -1.0d}, + {0.0d, -1.0d, 2.0d} + })); + } + + /** + * Test for {@link DecompositionSupport} features. + */ + @Test + public void decompositionSupportTest() { + basicTest(new PivotedMatrixView(new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d, 0.0d}, + {-1.0d, 2.0d, -1.0d}, + {0.0d, -1.0d, 2.0d} + }))); + } + + /** */ + @Test(expected = AssertionError.class) + public void nullMatrixTest() { + new QRDecomposition(null); + } + + /** */ + @Test(expected = IllegalArgumentException.class) + public void solveWrongMatrixSizeTest() { + new QRDecomposition(new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d, 0.0d}, + {-1.0d, 2.0d, -1.0d}, + {0.0d, -1.0d, 2.0d} + })).solve(new DenseLocalOnHeapMatrix(2, 3)); + } + + /** */ + private void basicTest(Matrix m) { + QRDecomposition dec = new QRDecomposition(m); + assertTrue("Unexpected value for full rank in decomposition " + dec, dec.hasFullRank()); + + Matrix q = dec.getQ(); + Matrix r = dec.getR(); + + assertNotNull("Matrix q is expected to be not null.", q); + assertNotNull("Matrix r is expected to be not null.", r); + + Matrix qSafeCp = safeCopy(q); + + Matrix expIdentity = qSafeCp.times(qSafeCp.transpose()); + + final double delta = 0.0001; + + for (int row = 0; row < expIdentity.rowSize(); row++) + for (int col = 0; col < expIdentity.columnSize(); col++) + assertEquals("Unexpected identity matrix value at (" + row + "," + col + ").", + row == col ? 1d : 0d, expIdentity.get(col, row), delta); + + for (int row = 0; row < r.rowSize(); row++) + for (int col = 0; col < row - 1; col++) + assertEquals("Unexpected upper triangular matrix value at (" + row + "," + col + ").", + 0d, r.get(row, col), delta); + + Matrix recomposed = qSafeCp.times(r); + + for (int row = 0; row < m.rowSize(); row++) + for (int col = 0; col < m.columnSize(); col++) + assertEquals("Unexpected recomposed matrix value at (" + row + "," + col + ").", + m.get(row, col), recomposed.get(row, col), delta); + + Matrix sol = dec.solve(new DenseLocalOnHeapMatrix(3, 10)); + assertEquals("Unexpected rows in solution matrix.", 3, sol.rowSize()); + assertEquals("Unexpected cols in solution matrix.", 10, sol.columnSize()); + + for (int row = 0; row < sol.rowSize(); row++) + for (int col = 0; col < sol.columnSize(); col++) + assertEquals("Unexpected solution matrix value at (" + row + "," + col + ").", + 0d, sol.get(row, col), delta); + + dec.destroy(); + + QRDecomposition dec1 = new QRDecomposition(new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d}, + {-1.0d, 2.0d}, + {0.0d, -1.0d} + })); + + assertTrue("Unexpected value for full rank in decomposition " + dec1, dec1.hasFullRank()); + + dec1.destroy(); + + QRDecomposition dec2 = new QRDecomposition(new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d, 0.0d, 0.0d}, + {-1.0d, 2.0d, -1.0d, 0.0d}, + {0.0d, -1.0d, 2.0d, 0.0d} + })); + + assertTrue("Unexpected value for full rank in decomposition " + dec2, dec2.hasFullRank()); + + dec2.destroy(); + } + + /** */ + private Matrix safeCopy(Matrix orig) { + return new DenseLocalOnHeapMatrix(orig.rowSize(), orig.columnSize()).assign(orig); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/acd21fb8/modules/math/src/test/java/org/apache/ignite/math/decompositions/SingularValueDecompositionTest.java ---------------------------------------------------------------------- diff --git a/modules/math/src/test/java/org/apache/ignite/math/decompositions/SingularValueDecompositionTest.java b/modules/math/src/test/java/org/apache/ignite/math/decompositions/SingularValueDecompositionTest.java new file mode 100644 index 0000000..d0b89f8 --- /dev/null +++ b/modules/math/src/test/java/org/apache/ignite/math/decompositions/SingularValueDecompositionTest.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.math.decompositions; + +import org.apache.ignite.math.Matrix; +import org.apache.ignite.math.impls.matrix.DenseLocalOnHeapMatrix; +import org.apache.ignite.math.impls.matrix.PivotedMatrixView; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** */ +public class SingularValueDecompositionTest { + /** */ + @Test + public void basicTest() { + basicTest(new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d, 0.0d}, + {-1.0d, 2.0d, -1.0d}, + {0.0d, -1.0d, 2.0d} + })); + } + + /** + * Test for {@link DecompositionSupport} features. + */ + @Test + public void decompositionSupportTest() { + basicTest(new PivotedMatrixView(new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d, 0.0d}, + {-1.0d, 2.0d, -1.0d}, + {0.0d, -1.0d, 2.0d} + }))); + } + + /** */ + @Test + public void rowsLessThanColumnsTest() { + DenseLocalOnHeapMatrix m = new DenseLocalOnHeapMatrix(new double[][] { + {2.0d, -1.0d, 0.0d}, + {-1.0d, 2.0d, -1.0d} + }); + + SingularValueDecomposition dec = new SingularValueDecomposition(m); + assertEquals("Unexpected value for singular values size.", + 2, dec.getSingularValues().length); + + Matrix s = dec.getS(); + Matrix u = dec.getU(); + Matrix v = dec.getV(); + Matrix covariance = dec.getCovariance(0.5); + + assertNotNull("Matrix s is expected to be not null.", s); + assertNotNull("Matrix u is expected to be not null.", u); + assertNotNull("Matrix v is expected to be not null.", v); + assertNotNull("Covariance matrix is expected to be not null.", covariance); + + dec.destroy(); + } + + /** */ + @Test(expected = AssertionError.class) + public void nullMatrixTest() { + new SingularValueDecomposition(null); + } + + /** */ + private void basicTest(Matrix m) { + SingularValueDecomposition dec = new SingularValueDecomposition(m); + assertEquals("Unexpected value for singular values size.", + 3, dec.getSingularValues().length); + + Matrix s = dec.getS(); + Matrix u = dec.getU(); + Matrix v = dec.getV(); + Matrix covariance = dec.getCovariance(0.5); + + assertNotNull("Matrix s is expected to be not null.", s); + assertNotNull("Matrix u is expected to be not null.", u); + assertNotNull("Matrix v is expected to be not null.", v); + assertNotNull("Covariance matrix is expected to be not null.", covariance); + + assertTrue("Decomposition cond is expected to be positive.", dec.cond() > 0); + assertTrue("Decomposition norm2 is expected to be positive.", dec.norm2() > 0); + assertEquals("Decomposition rank differs from expected.", 3, dec.rank()); + assertEquals("Decomposition singular values size differs from expected.", + 3, dec.getSingularValues().length); + + Matrix recomposed = (u.times(s).times(v.transpose())); + + for (int row = 0; row < m.rowSize(); row++) + for (int col = 0; col < m.columnSize(); col++) + assertEquals("Unexpected recomposed matrix value at (" + row + "," + col + ").", + m.get(row, col), recomposed.get(row, col), 0.001); + + for (int row = 0; row < covariance.rowSize(); row++) + for (int col = row + 1; col < covariance.columnSize(); col++) + assertEquals("Unexpected covariance matrix value at (" + row + "," + col + ").", + covariance.get(row, col), covariance.get(col, row), 0.001); + + dec.destroy(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/acd21fb8/modules/math/src/test/java/org/apache/ignite/math/impls/MathTestConstants.java ---------------------------------------------------------------------- diff --git a/modules/math/src/test/java/org/apache/ignite/math/impls/MathTestConstants.java b/modules/math/src/test/java/org/apache/ignite/math/impls/MathTestConstants.java new file mode 100644 index 0000000..122c62e --- /dev/null +++ b/modules/math/src/test/java/org/apache/ignite/math/impls/MathTestConstants.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.math.impls; + +/** + * Collect constants for org.apache.ignite.math tests + */ +public interface MathTestConstants { + /** */ + public double SECOND_ARG = 1d; + + /** + * We assume that we will check calculation precision in other tests. + */ + public double EXP_DELTA = 0.1d; + + /** */ + public String UNEXPECTED_VAL = "Unexpected value."; + + /** */ + public String NULL_GUID = "Null GUID."; + + /** */ + public String UNEXPECTED_GUID_VAL = "Unexpected GUID value."; + + /** */ + public String EMPTY_GUID = "Empty GUID."; + + /** */ + public String VALUES_SHOULD_BE_NOT_EQUALS = "Values should be not equals."; + + /** */ + public String NULL_VAL = "Null value."; + + /** */ + public String NULL_VALUES = "Null values."; + + /** */ + public String NOT_NULL_VAL = "Not null value."; + + /** */ + public double TEST_VAL = 1d; + + /** */ + public String VAL_NOT_EQUALS = "Values not equals."; + + /** */ + public String NO_NEXT_ELEMENT = "No next element."; + + /** */ + public int STORAGE_SIZE = 100; + + /** */ + public String WRONG_ATTRIBUTE_VAL = "Wrong attribute value."; + + /** */ + public String NULL_DATA_ELEMENT = "Null data element."; + + /** */ + public String WRONG_DATA_ELEMENT = "Wrong data element."; + + /** */ + public double NIL_DELTA = 0d; + + /** */ + public String NULL_DATA_STORAGE = "Null data storage."; + + /** */ + public String WRONG_DATA_SIZE = "Wrong data size."; + + /** */ + public String UNEXPECTED_DATA_VAL = "Unexpected data value."; +} http://git-wip-us.apache.org/repos/asf/ignite/blob/acd21fb8/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/CacheMatrixTest.java ---------------------------------------------------------------------- diff --git a/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/CacheMatrixTest.java b/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/CacheMatrixTest.java new file mode 100644 index 0000000..8a6d077 --- /dev/null +++ b/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/CacheMatrixTest.java @@ -0,0 +1,369 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.math.impls.matrix; + +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.internal.util.IgniteUtils; +import org.apache.ignite.math.ExternalizeTest; +import org.apache.ignite.math.IdentityValueMapper; +import org.apache.ignite.math.Matrix; +import org.apache.ignite.math.MatrixKeyMapper; +import org.apache.ignite.math.exceptions.UnsupportedOperationException; +import org.apache.ignite.math.impls.MathTestConstants; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.apache.ignite.testframework.junits.common.GridCommonTest; + +/** + * Tests for {@link CacheMatrix}. + */ +@GridCommonTest(group = "Distributed Models") +public class CacheMatrixTest extends GridCommonAbstractTest { + /** Number of nodes in grid */ + private static final int NODE_COUNT = 3; + /** Cache name. */ + private static final String CACHE_NAME = "test-cache"; + /** */ + private static final String UNEXPECTED_ATTRIBUTE_VALUE = "Unexpected attribute value."; + /** Grid instance. */ + private Ignite ignite; + /** Matrix rows */ + private final int rows = MathTestConstants.STORAGE_SIZE; + /** Matrix cols */ + private final int cols = MathTestConstants.STORAGE_SIZE; + + /** + * Default constructor. + */ + public CacheMatrixTest() { + super(false); + } + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + for (int i = 1; i <= NODE_COUNT; i++) + startGrid(i); + } + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + stopAllGrids(); + } + + /** + * {@inheritDoc} + */ + @Override protected void beforeTest() throws Exception { + ignite = grid(NODE_COUNT); + + ignite.configuration().setPeerClassLoadingEnabled(true); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + ignite.destroyCache(CACHE_NAME); + } + + /** */ + public void testGetSet() throws Exception { + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + double v = Math.random(); + cacheMatrix.set(i, j, v); + + assert Double.compare(v, cacheMatrix.get(i, j)) == 0; + assert Double.compare(v, cache.get(keyMapper.apply(i, j))) == 0; + } + } + } + + /** */ + public void testCopy() throws Exception { + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + fillMatrix(cacheMatrix); + + try { + cacheMatrix.copy(); + + fail("UnsupportedOperationException expected"); + } + catch (UnsupportedOperationException e) { + // No-op. + } + } + + /** */ + public void testLike() throws Exception { + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + try { + cacheMatrix.like(rows, cols); + + fail("UnsupportedOperationException expected"); + } + catch (UnsupportedOperationException e) { + // No-op. + } + } + + /** */ + public void testLikeVector() throws Exception { + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + try { + cacheMatrix.likeVector(cols); + + fail("UnsupportedOperationException expected"); + } + catch (UnsupportedOperationException e) { + // No-op. + } + } + + /** */ + public void testPlus() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + double plusVal = 2; + + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + initMatrix(cacheMatrix); + + cacheMatrix.plus(plusVal); + + for (int i = 0; i < rows; i++) + for (int j = 0; j < cols; j++) + assertEquals(plusVal, cacheMatrix.get(i, j)); + } + + /** */ + public void testDivide() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + double initVal = 1; + double divVal = 2; + + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + initMatrix(cacheMatrix); + cacheMatrix.assign(initVal); + cacheMatrix.divide(divVal); + + for (int i = 0; i < rows; i++) + for (int j = 0; j < cols; j++) + assertTrue(Double.compare(cacheMatrix.get(i, j), initVal / divVal) == 0); + } + + /** */ + public void testTimes() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + double initVal = 1; + double timVal = 2; + + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + initMatrix(cacheMatrix); + cacheMatrix.assign(initVal); + cacheMatrix.times(timVal); + + for (int i = 0; i < rows; i++) + for (int j = 0; j < cols; j++) + assertTrue(Double.compare(cacheMatrix.get(i, j), initVal * timVal) == 0); + } + + /** */ + public void testSum() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + double initVal = 1; + + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + double sum = 0; + + initMatrix(cacheMatrix); + sum = cacheMatrix.sum(); + + assertTrue(Double.compare(sum, 0d) == 0); + + cacheMatrix.assign(1d); + sum = cacheMatrix.sum(); + + assertTrue(Double.compare(sum, rows * cols) == 0); + } + + /** */ + public void testAssignSingleValue() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + double initVal = 1; + + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + initMatrix(cacheMatrix); + + cacheMatrix.assign(initVal); + + for (int i = 0; i < rows; i++) + for (int j = 0; j < cols; j++) + assertEquals(initVal, cacheMatrix.get(i, j)); + } + + /** */ + public void testAssignArray() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + double[][] initVal = new double[rows][cols]; + + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + for (int i = 0; i < rows; i++) + for (int j = 0; j < cols; j++) + initVal[i][j] = Math.random(); + + cacheMatrix.assign(initVal); + + for (int i = 0; i < rows; i++) + for (int j = 0; j < cols; j++) + assertEquals(initVal[i][j], cacheMatrix.get(i, j)); + } + + /** */ + public void testAttributes() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + assertFalse(UNEXPECTED_ATTRIBUTE_VALUE, cacheMatrix.isSequentialAccess()); + assertFalse(UNEXPECTED_ATTRIBUTE_VALUE, cacheMatrix.isDense()); + assertFalse(UNEXPECTED_ATTRIBUTE_VALUE, cacheMatrix.isArrayBased()); + assertTrue(UNEXPECTED_ATTRIBUTE_VALUE, cacheMatrix.isRandomAccess()); + assertTrue(UNEXPECTED_ATTRIBUTE_VALUE, cacheMatrix.isDistributed()); + } + + /** */ + public void testExternalization() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + final CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + ExternalizeTest> externalizeTest = new ExternalizeTest>() { + + @Override public void externalizeTest() { + super.externalizeTest(cacheMatrix); + } + }; + + externalizeTest.externalizeTest(); + } + + /** */ + public void testMinMax() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + final CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + for (int i = 0; i < rows; i++) + for (int j = 0; j < cols; j++) + cacheMatrix.set(i, j, i * rows + j); + + assertEquals(0.0, cacheMatrix.minValue(), 0.0); + assertEquals(rows * cols - 1, cacheMatrix.maxValue(), 0.0); + } + + /** */ + public void testMap() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + MatrixKeyMapper keyMapper = getKeyMapper(rows, cols); + IgniteCache cache = getCache(); + final CacheMatrix cacheMatrix = new CacheMatrix<>(rows, cols, cache, keyMapper, new IdentityValueMapper()); + + initMatrix(cacheMatrix); + + cacheMatrix.map(value -> value + 10); + + for (int i = 0; i < rows; i++) + for (int j = 0; j < cols; j++) + assertEquals(10.0, cacheMatrix.getX(i, j), 0.0); + } + + /** */ + private IgniteCache getCache() { + assert ignite != null; + + CacheConfiguration cfg = new CacheConfiguration(); + cfg.setName(CACHE_NAME); + + IgniteCache cache = ignite.getOrCreateCache(CACHE_NAME); + + assert cache != null; + return cache; + } + + /** */ + private MatrixKeyMapper getKeyMapper(final int rows, final int cols) { + return new MatrixKeyMapperForTests(rows, cols); + } + + /** Init the given matrix by random values. */ + private void fillMatrix(Matrix m) { + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + m.set(i, j, Math.random()); + } + + /** Init the given matrix by zeros. */ + private void initMatrix(Matrix m) { + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + m.set(i, j, 0d); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/acd21fb8/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/DenseLocalOffHeapMatrixConstructorTest.java ---------------------------------------------------------------------- diff --git a/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/DenseLocalOffHeapMatrixConstructorTest.java b/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/DenseLocalOffHeapMatrixConstructorTest.java new file mode 100644 index 0000000..1f0537c --- /dev/null +++ b/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/DenseLocalOffHeapMatrixConstructorTest.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.math.impls.matrix; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** */ +public class DenseLocalOffHeapMatrixConstructorTest { + /** */ + @Test + public void invalidArgsTest() { + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new DenseLocalOffHeapMatrix(0, 1), "invalid row parameter"); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new DenseLocalOffHeapMatrix(1, 0), "invalid col parameter"); + + //noinspection ConstantConditions + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new DenseLocalOffHeapMatrix(null), "null matrix parameter"); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new DenseLocalOffHeapMatrix(new double[][] {null, new double[1]}), + "null row in matrix"); + } + + /** */ + @Test + public void basicTest() { + assertEquals("Expected number of rows, int parameters.", 1, + new DenseLocalOffHeapMatrix(1, 2).rowSize()); + + assertEquals("Expected number of rows, double[][] parameter.", 1, + new DenseLocalOffHeapMatrix(new double[][] {new double[2]}).rowSize()); + + assertEquals("Expected number of cols, int parameters.", 1, + new DenseLocalOffHeapMatrix(2, 1).columnSize()); + + assertEquals("Expected number of cols, double[][] parameter.", 1, + new DenseLocalOffHeapMatrix(new double[][] {new double[1], new double[1]}).columnSize()); + + double[][] data1 = new double[][] {{1, 2}, {3, 4}}, data2 = new double[][] {{1, 2}, {3, 5}}; + + assertTrue("Matrices with same values are expected to be equal", + new DenseLocalOffHeapMatrix(data1).equals(new DenseLocalOffHeapMatrix(data1))); + + assertFalse("Matrices with same values are expected to be equal", + new DenseLocalOffHeapMatrix(data1).equals(new DenseLocalOffHeapMatrix(data2))); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/acd21fb8/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/DenseLocalOnHeapMatrixConstructorTest.java ---------------------------------------------------------------------- diff --git a/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/DenseLocalOnHeapMatrixConstructorTest.java b/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/DenseLocalOnHeapMatrixConstructorTest.java new file mode 100644 index 0000000..0a25e31 --- /dev/null +++ b/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/DenseLocalOnHeapMatrixConstructorTest.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.math.impls.matrix; + +import java.util.function.Supplier; +import org.apache.ignite.math.Matrix; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +/** */ +public class DenseLocalOnHeapMatrixConstructorTest { + /** */ + @Test + public void invalidArgsTest() { + verifyAssertionError(() -> new DenseLocalOnHeapMatrix(0, 1), "invalid row parameter"); + + verifyAssertionError(() -> new DenseLocalOnHeapMatrix(1, 0), "invalid col parameter"); + + //noinspection ConstantConditions + verifyAssertionError(() -> new DenseLocalOnHeapMatrix(null), "null matrix parameter"); + + verifyAssertionError(() -> new DenseLocalOnHeapMatrix(new double[][] {null, new double[1]}), + "null row in matrix"); + } + + /** */ + @Test + public void basicTest() { + assertEquals("Expected number of rows, int parameters.", 1, + new DenseLocalOnHeapMatrix(1, 2).rowSize()); + + assertEquals("Expected number of rows, double[][] parameter.", 1, + new DenseLocalOnHeapMatrix(new double[][] {new double[2]}).rowSize()); + + assertEquals("Expected number of cols, int parameters.", 1, + new DenseLocalOnHeapMatrix(2, 1).columnSize()); + + assertEquals("Expected number of cols, double[][] parameter.", 1, + new DenseLocalOnHeapMatrix(new double[][] {new double[1], new double[1]}).columnSize()); + } + + /** */ + static void verifyAssertionError(Supplier ctor, String desc) { + try { + assertNotNull("Unexpected null matrix in " + desc, ctor.get()); + } + catch (AssertionError ae) { + return; + } + + fail("Expected error not caught in " + desc); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/acd21fb8/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/DiagonalMatrixTest.java ---------------------------------------------------------------------- diff --git a/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/DiagonalMatrixTest.java b/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/DiagonalMatrixTest.java new file mode 100644 index 0000000..c0c2af7 --- /dev/null +++ b/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/DiagonalMatrixTest.java @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.math.impls.matrix; + +import org.apache.ignite.math.ExternalizeTest; +import org.apache.ignite.math.Matrix; +import org.apache.ignite.math.Vector; +import org.apache.ignite.math.exceptions.UnsupportedOperationException; +import org.apache.ignite.math.impls.MathTestConstants; +import org.apache.ignite.math.impls.vector.DenseLocalOnHeapVector; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Tests for {@link DiagonalMatrix}. + */ +public class DiagonalMatrixTest extends ExternalizeTest { + /** */ + public static final String UNEXPECTED_VALUE = "Unexpected value"; + + /** */ + private DiagonalMatrix testMatrix; + + /** */ + @Before + public void setup() { + DenseLocalOnHeapMatrix parent = new DenseLocalOnHeapMatrix(MathTestConstants.STORAGE_SIZE, MathTestConstants.STORAGE_SIZE); + fillMatrix(parent); + testMatrix = new DiagonalMatrix(parent); + } + + /** {@inheritDoc} */ + @Override public void externalizeTest() { + externalizeTest(testMatrix); + } + + /** */ + @Test + public void testSetGetBasic() { + double testVal = 42; + for (int i = 0; i < MathTestConstants.STORAGE_SIZE; i++) { + testMatrix.set(i, i, testVal); + + assertEquals(UNEXPECTED_VALUE + " at (" + i + "," + i + ")", testMatrix.get(i, i), testVal, 0d); + } + + //noinspection EqualsWithItself + assertTrue("Matrix is expected to be equal to self.", testMatrix.equals(testMatrix)); + //noinspection ObjectEqualsNull + assertFalse("Matrix is expected to be not equal to null.", testMatrix.equals(null)); + } + + /** */ + @Test + public void testSetGet() { + verifyDiagonal(testMatrix); + + final int size = MathTestConstants.STORAGE_SIZE; + + for (Matrix m : new Matrix[] { + new DenseLocalOnHeapMatrix(size + 1, size), + new DenseLocalOnHeapMatrix(size, size + 1)}) { + fillMatrix(m); + + verifyDiagonal(new DiagonalMatrix(m)); + } + + final double[] data = new double[size]; + + for (int i = 0; i < size; i++) + data[i] = 1 + i; + + final Matrix m = new DiagonalMatrix(new DenseLocalOnHeapVector(data)); + + assertEquals("Rows in matrix constructed from vector", size, m.rowSize()); + assertEquals("Cols in matrix constructed from vector", size, m.columnSize()); + + for (int i = 0; i < size; i++) + assertEquals(UNEXPECTED_VALUE + " at vector index " + i, data[i], m.get(i, i), 0d); + + verifyDiagonal(m); + + final Matrix m1 = new DiagonalMatrix(data); + + assertEquals("Rows in matrix constructed from array", size, m1.rowSize()); + assertEquals("Cols in matrix constructed from array", size, m1.columnSize()); + + for (int i = 0; i < size; i++) + assertEquals(UNEXPECTED_VALUE + " at array index " + i, data[i], m1.get(i, i), 0d); + + verifyDiagonal(m1); + } + + /** */ + @Test + public void testConstant() { + final int size = MathTestConstants.STORAGE_SIZE; + + for (double val : new double[] {-1.0, 0.0, 1.0}) { + Matrix m = new DiagonalMatrix(size, val); + + assertEquals("Rows in matrix", size, m.rowSize()); + assertEquals("Cols in matrix", size, m.columnSize()); + + for (int i = 0; i < size; i++) + assertEquals(UNEXPECTED_VALUE + " at index " + i, val, m.get(i, i), 0d); + + verifyDiagonal(m, true); + } + } + + /** */ + @Test + public void testAttributes() { + assertTrue(UNEXPECTED_VALUE, testMatrix.rowSize() == MathTestConstants.STORAGE_SIZE); + assertTrue(UNEXPECTED_VALUE, testMatrix.columnSize() == MathTestConstants.STORAGE_SIZE); + + assertFalse(UNEXPECTED_VALUE, testMatrix.isArrayBased()); + assertTrue(UNEXPECTED_VALUE, testMatrix.isDense()); + assertFalse(UNEXPECTED_VALUE, testMatrix.isDistributed()); + + assertEquals(UNEXPECTED_VALUE, testMatrix.isRandomAccess(), !testMatrix.isSequentialAccess()); + assertTrue(UNEXPECTED_VALUE, testMatrix.isRandomAccess()); + } + + /** */ + @Test + public void testNullParams() { + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new DiagonalMatrix((Matrix)null), "Null Matrix parameter"); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new DiagonalMatrix((Vector)null), "Null Vector parameter"); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new DiagonalMatrix((double[])null), "Null double[] parameter"); + } + + /** */ + private void verifyDiagonal(Matrix m, boolean readonly) { + final int rows = m.rowSize(), cols = m.columnSize(); + + final String sizeDetails = "rows" + "X" + "cols " + rows + "X" + cols; + + for (int i = 0; i < rows; i++) + for (int j = 0; j < cols; j++) { + final String details = " at (" + i + "," + j + "), " + sizeDetails; + + final boolean diagonal = i == j; + + final double old = m.get(i, j); + + if (!diagonal) + assertEquals(UNEXPECTED_VALUE + details, 0, old, 0d); + + final double exp = diagonal && !readonly ? old + 1 : old; + + boolean expECaught = false; + + try { + m.set(i, j, exp); + } + catch (UnsupportedOperationException uoe) { + if (diagonal && !readonly) + throw uoe; + + expECaught = true; + } + + if ((!diagonal || readonly) && !expECaught) + fail("Expected exception was not caught " + details); + + assertEquals(UNEXPECTED_VALUE + details, exp, m.get(i, j), 0d); + } + } + + /** */ + private void verifyDiagonal(Matrix m) { + verifyDiagonal(m, false); + } + + /** */ + private void fillMatrix(Matrix m) { + final int rows = m.rowSize(), cols = m.columnSize(); + + boolean negative = false; + + for (int i = 0; i < rows; i++) + for (int j = 0; j < cols; j++) + m.set(i, j, (negative = !negative) ? -(i * cols + j + 1) : i * cols + j + 1); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/acd21fb8/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/FunctionMatrixConstructorTest.java ---------------------------------------------------------------------- diff --git a/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/FunctionMatrixConstructorTest.java b/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/FunctionMatrixConstructorTest.java new file mode 100644 index 0000000..a5ac84a --- /dev/null +++ b/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/FunctionMatrixConstructorTest.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.math.impls.matrix; + +import org.apache.ignite.math.Matrix; +import org.apache.ignite.math.exceptions.UnsupportedOperationException; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** */ +public class FunctionMatrixConstructorTest { + /** */ + @Test + public void invalidArgsTest() { + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new FunctionMatrix(0, 1, (i, j) -> 0.0), + "Invalid row parameter."); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new FunctionMatrix(1, 0, (i, j) -> 0.0), + "Invalid col parameter."); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new FunctionMatrix(1, 1, null), + "Invalid func parameter."); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new FunctionMatrix(0, 1, (i, j) -> 0.0, null), + "Invalid row parameter, with setter func."); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new FunctionMatrix(1, 0, (i, j) -> 0.0, null), + "Invalid col parameter, with setter func."); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new FunctionMatrix(1, 1, null, null), + "Invalid func parameter, with setter func."); + } + + /** */ + @Test + public void basicTest() { + for (int rows : new int[] {1, 2, 3}) + for (int cols : new int[] {1, 2, 3}) + basicTest(rows, cols); + + Matrix m = new FunctionMatrix(1, 1, (i, j) -> 1d); + //noinspection EqualsWithItself + assertTrue("Matrix is expected to be equal to self.", m.equals(m)); + //noinspection ObjectEqualsNull + assertFalse("Matrix is expected to be not equal to null.", m.equals(null)); + } + + /** */ + private void basicTest(int rows, int cols) { + double[][] data = new double[rows][cols]; + + for (int row = 0; row < rows; row++) + for (int col = 0; col < cols; col++) + data[row][col] = row * cols + row; + + Matrix mReadOnly = new FunctionMatrix(rows, cols, (i, j) -> data[i][j]); + + assertEquals("Rows in matrix.", rows, mReadOnly.rowSize()); + assertEquals("Cols in matrix.", cols, mReadOnly.columnSize()); + + for (int row = 0; row < rows; row++) + for (int col = 0; col < cols; col++) { + assertEquals("Unexpected value at " + row + "x" + col, data[row][col], mReadOnly.get(row, col), 0d); + + boolean expECaught = false; + + try { + mReadOnly.set(row, col, 0.0); + } + catch (UnsupportedOperationException uoe) { + expECaught = true; + } + + assertTrue("Expected exception wasn't thrown at " + row + "x" + col, expECaught); + } + + Matrix m = new FunctionMatrix(rows, cols, (i, j) -> data[i][j], (i, j, val) -> data[i][j] = val); + + assertEquals("Rows in matrix, with setter function.", rows, m.rowSize()); + assertEquals("Cols in matrix, with setter function.", cols, m.columnSize()); + + for (int row = 0; row < rows; row++) + for (int col = 0; col < cols; col++) { + assertEquals("Unexpected value at " + row + "x" + col, data[row][col], m.get(row, col), 0d); + + m.set(row, col, -data[row][col]); + } + + for (int row = 0; row < rows; row++) + for (int col = 0; col < cols; col++) + assertEquals("Unexpected value set at " + row + "x" + col, -(row * cols + row), m.get(row, col), 0d); + + assertTrue("Incorrect copy for empty matrix.", m.copy().equals(m)); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/acd21fb8/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/MatrixAttributeTest.java ---------------------------------------------------------------------- diff --git a/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/MatrixAttributeTest.java b/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/MatrixAttributeTest.java new file mode 100644 index 0000000..c9fb390 --- /dev/null +++ b/modules/math/src/test/java/org/apache/ignite/math/impls/matrix/MatrixAttributeTest.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.math.impls.matrix; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; +import org.apache.ignite.math.Matrix; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Attribute tests for matrices. + * + * TODO: WIP + */ +public class MatrixAttributeTest { + /** */ + private final List attrCfgs = Arrays.asList( + new AttrCfg("isDense", Matrix::isDense, + DenseLocalOnHeapMatrix.class, DenseLocalOffHeapMatrix.class, RandomMatrix.class, DiagonalMatrix.class), + new AttrCfg("isArrayBased", Matrix::isArrayBased, DenseLocalOnHeapMatrix.class), + new AttrCfg("isDistributed", Matrix::isDistributed), + new AttrCfg("isRandomAccess", Matrix::isRandomAccess, DenseLocalOnHeapMatrix.class, DenseLocalOffHeapMatrix.class, RandomMatrix.class, DiagonalMatrix.class, SparseLocalOnHeapMatrix.class), + new AttrCfg("isSequentialAccess", Matrix::isSequentialAccess, DiagonalMatrix.class) + ); + + /** */ + private final List specFixture = Arrays.asList( + new Specification(new DenseLocalOnHeapMatrix(1, 1)), + new Specification(new DenseLocalOffHeapMatrix(1, 1)), + new Specification(new RandomMatrix(1, 1)), + new Specification(new DiagonalMatrix(new double[] {1.0})), + new Specification(new FunctionMatrix(1, 1, (x, y) -> 1.0)), + new Specification(new SparseLocalOnHeapMatrix(1, 1)) + ); + + /** */ + @Test + public void isDenseTest() { + assertAttribute("isDense"); + } + + /** */ + @Test + public void isArrayBasedTest() { + assertAttribute("isArrayBased"); + } + + /** */ + @Test + public void isSequentialAccessTest() { + assertAttribute("isSequentialAccess"); + } + + /** */ + @Test + public void isRandomAccessTest() { + assertAttribute("isRandomAccess"); + } + + /** */ + @Test + public void isDistributedTest() { + assertAttribute("isDistributed"); + } + + /** */ + private void assertAttribute(String name) { + final MatrixAttributeTest.AttrCfg attr = attrCfg(name); + + for (MatrixAttributeTest.Specification spec : specFixture) + spec.verify(attr); + } + + /** */ + private MatrixAttributeTest.AttrCfg attrCfg(String name) { + for (MatrixAttributeTest.AttrCfg attr : attrCfgs) + if (attr.name.equals(name)) + return attr; + + throw new IllegalArgumentException("Undefined attribute " + name); + } + + /** See http://en.wikipedia.org/wiki/Specification_pattern */ + private static class Specification { + /** */ + private final Matrix m; + /** */ + private final Class underlyingType; + /** */ + private final List attrsFromUnderlying; + /** */ + final String desc; + + /** */ + Specification(Matrix m, Class underlyingType, String... attrsFromUnderlying) { + this.m = m; + this.underlyingType = underlyingType; + this.attrsFromUnderlying = Arrays.asList(attrsFromUnderlying); + final Class clazz = m.getClass(); + desc = clazz.getSimpleName() + (clazz.equals(underlyingType) + ? "" : " (underlying type " + underlyingType.getSimpleName() + ")"); + } + + /** */ + Specification(Matrix m) { + this(m, m.getClass()); + } + + /** */ + void verify(MatrixAttributeTest.AttrCfg attr) { + final boolean obtained = attr.obtain.apply(m); + + final Class typeToCheck + = attrsFromUnderlying.contains(attr.name) ? underlyingType : m.getClass(); + + final boolean exp = attr.trueInTypes.contains(typeToCheck); + + assertEquals("Unexpected " + attr.name + " value for " + desc, exp, obtained); + } + } + + /** */ + private static class AttrCfg { + /** */ + final String name; + /** */ + final Function obtain; + /** */ + final List trueInTypes; + + /** */ + AttrCfg(String name, Function obtain, Class... trueInTypes) { + this.name = name; + this.obtain = obtain; + this.trueInTypes = Arrays.asList(trueInTypes); + } + } +}