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 4D525200C79 for ; Thu, 4 May 2017 15:37:12 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 4BF47160BC8; Thu, 4 May 2017 13:37:12 +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 6A34F160BC6 for ; Thu, 4 May 2017 15:37:06 +0200 (CEST) Received: (qmail 14148 invoked by uid 500); 4 May 2017 13:37:05 -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 14042 invoked by uid 99); 4 May 2017 13:37:05 -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; Thu, 04 May 2017 13:37:05 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 41493E04AA; Thu, 4 May 2017 13:37:05 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: sboikov@apache.org To: commits@ignite.apache.org Date: Thu, 04 May 2017 13:37:08 -0000 Message-Id: <2c999d689d414e7fb64a475595b97f96@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [04/67] [abbrv] ignite git commit: IGNITE-5000 Rename Ignite Math module to Ignite ML module added missed licenses renamed packages fixed wrong ml profile activation (cherry picked from commit d78e071) archived-at: Thu, 04 May 2017 13:37:12 -0000 http://git-wip-us.apache.org/repos/asf/ignite/blob/0abf6601/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixImplementationsTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixImplementationsTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixImplementationsTest.java new file mode 100644 index 0000000..c827037 --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixImplementationsTest.java @@ -0,0 +1,1113 @@ +/* + * 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.ml.math.impls.matrix; + +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Supplier; +import org.apache.ignite.ml.math.ExternalizeTest; +import org.apache.ignite.ml.math.Matrix; +import org.apache.ignite.ml.math.Vector; +import org.apache.ignite.ml.math.exceptions.CardinalityException; +import org.apache.ignite.ml.math.exceptions.ColumnIndexException; +import org.apache.ignite.ml.math.exceptions.IndexException; +import org.apache.ignite.ml.math.exceptions.RowIndexException; +import org.apache.ignite.ml.math.exceptions.UnsupportedOperationException; +import org.apache.ignite.ml.math.impls.vector.DenseLocalOffHeapVector; +import org.apache.ignite.ml.math.impls.vector.DenseLocalOnHeapVector; +import org.apache.ignite.ml.math.impls.vector.RandomVector; +import org.apache.ignite.ml.math.impls.vector.SparseLocalVector; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Tests for {@link Matrix} implementations. + */ +public class MatrixImplementationsTest extends ExternalizeTest { + /** */ + private static final double DEFAULT_DELTA = 0.000000001d; + + /** */ + private void consumeSampleMatrix(BiConsumer consumer) { + new MatrixImplementationFixtures().consumeSampleMatrix(consumer); + } + + /** */ + @Test + public void externalizeTest() { + consumeSampleMatrix((m, desc) -> externalizeTest(m)); + } + + /** */ + @Test + public void testLike() { + consumeSampleMatrix((m, desc) -> { + Class cls = likeMatrixType(m); + + if (cls != null) { + Matrix like = m.like(m.rowSize(), m.columnSize()); + + assertEquals("Wrong \"like\" matrix for " + desc + "; Unexpected rows.", like.rowSize(), m.rowSize()); + assertEquals("Wrong \"like\" matrix for " + desc + "; Unexpected columns.", like.columnSize(), m.columnSize()); + + assertEquals("Wrong \"like\" matrix for " + desc + + "; Unexpected class: " + like.getClass().toString(), + cls, + like.getClass()); + + return; + } + + boolean expECaught = false; + + try { + m.like(1, 1); + } + catch (UnsupportedOperationException uoe) { + expECaught = true; + } + + assertTrue("Expected exception was not caught for " + desc, expECaught); + }); + } + + /** */ + @Test + public void testCopy() { + consumeSampleMatrix((m, desc) -> { + Matrix cp = m.copy(); + assertTrue("Incorrect copy for empty matrix " + desc, cp.equals(m)); + + if (!readOnly(m)) + fillMatrix(m); + + cp = m.copy(); + + assertTrue("Incorrect copy for matrix " + desc, cp.equals(m)); + }); + } + + /** */ + @Test + public void testHaveLikeVector() throws InstantiationException, IllegalAccessException { + for (Class key : likeVectorTypesMap().keySet()) { + Class val = likeVectorTypesMap().get(key); + + if (val == null && !ignore(key)) + System.out.println("Missing test for implementation of likeMatrix for " + key.getSimpleName()); + } + } + + /** */ + @Test + public void testLikeVector() { + consumeSampleMatrix((m, desc) -> { + if (likeVectorTypesMap().containsKey(m.getClass())) { + Vector likeVector = m.likeVector(m.columnSize()); + + assertNotNull(likeVector); + assertEquals("Unexpected value for " + desc, likeVector.size(), m.columnSize()); + + return; + } + + boolean expECaught = false; + + try { + m.likeVector(1); + } + catch (UnsupportedOperationException uoe) { + expECaught = true; + } + + assertTrue("Expected exception was not caught for " + desc, expECaught); + }); + } + + /** */ + @Test + public void testAssignSingleElement() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + final double assignVal = Math.random(); + + m.assign(assignVal); + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + assertEquals("Unexpected value for " + desc + " at (" + i + "," + j + ")", + assignVal, m.get(i, j), 0d); + }); + } + + /** */ + @Test + public void testAssignArray() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + double[][] data = new double[m.rowSize()][m.columnSize()]; + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + data[i][j] = Math.random(); + + m.assign(data); + + for (int i = 0; i < m.rowSize(); i++) { + for (int j = 0; j < m.columnSize(); j++) + assertEquals("Unexpected value for " + desc + " at (" + i + "," + j + ")", + data[i][j], m.get(i, j), 0d); + } + }); + } + + /** */ + @Test + public void testAssignFunction() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + m.assign((i, j) -> (double)(i * m.columnSize() + j)); + + for (int i = 0; i < m.rowSize(); i++) { + for (int j = 0; j < m.columnSize(); j++) + assertEquals("Unexpected value for " + desc + " at (" + i + "," + j + ")", + (double)(i * m.columnSize() + j), m.get(i, j), 0d); + } + }); + } + + /** */ + @Test + public void testPlus() { + consumeSampleMatrix((m, desc) -> { + if (readOnly(m)) + return; + + double[][] data = fillAndReturn(m); + + double plusVal = Math.random(); + + Matrix plus = m.plus(plusVal); + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + assertEquals("Unexpected value for " + desc + " at (" + i + "," + j + ")", + data[i][j] + plusVal, plus.get(i, j), 0d); + }); + } + + /** */ + @Test + public void testPlusMatrix() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + double[][] data = fillAndReturn(m); + + Matrix plus = m.plus(m); + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + assertEquals("Unexpected value for " + desc + " at (" + i + "," + j + ")", + data[i][j] * 2.0, plus.get(i, j), 0d); + }); + } + + /** */ + @Test + public void testMinusMatrix() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + fillMatrix(m); + + Matrix minus = m.minus(m); + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + assertEquals("Unexpected value for " + desc + " at (" + i + "," + j + ")", + 0.0, minus.get(i, j), 0d); + }); + } + + /** */ + @Test + public void testTimes() { + consumeSampleMatrix((m, desc) -> { + if (readOnly(m)) + return; + + double[][] data = fillAndReturn(m); + + double timeVal = Math.random(); + Matrix times = m.times(timeVal); + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + assertEquals("Unexpected value for " + desc + " at (" + i + "," + j + ")", + data[i][j] * timeVal, times.get(i, j), 0d); + }); + } + + /** */ + @Test + public void testTimesVector() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + double[][] data = fillAndReturn(m); + + double[] arr = fillArray(m.columnSize()); + + Vector times = m.times(new DenseLocalOnHeapVector(arr)); + + assertEquals("Unexpected vector size for " + desc, times.size(), m.rowSize()); + + for (int i = 0; i < m.rowSize(); i++) { + double exp = 0.0; + + for (int j = 0; j < m.columnSize(); j++) + exp += arr[j] * data[i][j]; + + assertEquals("Unexpected value for " + desc + " at " + i, + times.get(i), exp, 0d); + } + + testInvalidCardinality(() -> m.times(new DenseLocalOnHeapVector(m.columnSize() + 1)), desc); + }); + } + + /** */ + @Test + public void testTimesMatrix() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + double[][] data = fillAndReturn(m); + + double[] arr = fillArray(m.columnSize()); + + Matrix mult = new DenseLocalOnHeapMatrix(m.columnSize(), 1); + + mult.setColumn(0, arr); + + Matrix times = m.times(mult); + + assertEquals("Unexpected rows for " + desc, times.rowSize(), m.rowSize()); + + assertEquals("Unexpected cols for " + desc, times.columnSize(), 1); + + for (int i = 0; i < m.rowSize(); i++) { + double exp = 0.0; + + for (int j = 0; j < m.columnSize(); j++) + exp += arr[j] * data[i][j]; + + assertEquals("Unexpected value for " + desc + " at " + i, + exp, times.get(i, 0), 0d); + } + + testInvalidCardinality(() -> m.times(new DenseLocalOnHeapMatrix(m.columnSize() + 1, 1)), desc); + }); + } + + /** */ + @Test + public void testDivide() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + double[][] data = fillAndReturn(m); + + double divVal = Math.random(); + + Matrix divide = m.divide(divVal); + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + assertEquals("Unexpected value for " + desc + " at (" + i + "," + j + ")", + data[i][j] / divVal, divide.get(i, j), 0d); + }); + } + + /** */ + @Test + public void testTranspose() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + fillMatrix(m); + + Matrix transpose = m.transpose(); + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + assertEquals("Unexpected value for " + desc + " at (" + i + "," + j + ")", + m.get(i, j), transpose.get(j, i), 0d); + }); + } + + /** */ + @Test + public void testDeterminant() { + consumeSampleMatrix((m, desc) -> { + if (m.rowSize() != m.columnSize()) + return; + + if (ignore(m.getClass())) + return; + + double[][] doubles = fillIntAndReturn(m); + + if (m.rowSize() == 1) { + assertEquals("Unexpected value " + desc, m.determinant(), doubles[0][0], 0d); + + return; + } + + if (m.rowSize() == 2) { + double det = doubles[0][0] * doubles[1][1] - doubles[0][1] * doubles[1][0]; + assertEquals("Unexpected value " + desc, m.determinant(), det, 0d); + + return; + } + + if (m.rowSize() > 512) + return; // IMPL NOTE if row size >= 30000 it takes unacceptably long for normal test run. + + Matrix diagMtx = m.like(m.rowSize(), m.columnSize()); + + diagMtx.assign(0); + for (int i = 0; i < m.rowSize(); i++) + diagMtx.set(i, i, m.get(i, i)); + + double det = 1; + + for (int i = 0; i < diagMtx.rowSize(); i++) + det *= diagMtx.get(i, i); + + try { + assertEquals("Unexpected value " + desc, det, diagMtx.determinant(), DEFAULT_DELTA); + } + catch (Exception e) { + System.out.println(desc); + throw e; + } + }); + } + + /** */ + @Test + public void testInverse() { + consumeSampleMatrix((m, desc) -> { + if (m.rowSize() != m.columnSize()) + return; + + if (ignore(m.getClass())) + return; + + if (m.rowSize() > 256) + return; // IMPL NOTE this is for quicker test run. + + fillNonSingularMatrix(m); + + assertTrue("Unexpected zero determinant " + desc, Math.abs(m.determinant()) > 0d); + + Matrix inverse = m.inverse(); + + Matrix mult = m.times(inverse); + + final double delta = 0.001d; + + assertEquals("Unexpected determinant " + desc, 1d, mult.determinant(), delta); + + assertEquals("Unexpected top left value " + desc, 1d, mult.get(0, 0), delta); + + if (m.rowSize() == 1) + return; + + assertEquals("Unexpected center value " + desc, + 1d, mult.get(m.rowSize() / 2, m.rowSize() / 2), delta); + + assertEquals("Unexpected bottom right value " + desc, + 1d, mult.get(m.rowSize() - 1, m.rowSize() - 1), delta); + + assertEquals("Unexpected top right value " + desc, + 0d, mult.get(0, m.rowSize() - 1), delta); + + assertEquals("Unexpected bottom left value " + desc, + 0d, mult.get(m.rowSize() - 1, 0), delta); + }); + } + + /** */ + @Test + public void testMap() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + fillMatrix(m); + + m.map(x -> 10d); + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + assertEquals("Unexpected value for " + desc + " at (" + i + "," + j + ")", + 10d, m.get(i, j), 0d); + }); + } + + /** */ + @Test + public void testMapMatrix() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + double[][] doubles = fillAndReturn(m); + + testMapMatrixWrongCardinality(m, desc); + + Matrix cp = m.copy(); + + m.map(cp, (m1, m2) -> m1 + m2); + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + assertEquals("Unexpected value for " + desc + " at (" + i + "," + j + ")", + m.get(i, j), doubles[i][j] * 2, 0d); + }); + } + + /** */ + @Test + public void testViewRow() { + consumeSampleMatrix((m, desc) -> { + if (!readOnly(m)) + fillMatrix(m); + + for (int i = 0; i < m.rowSize(); i++) { + Vector vector = m.viewRow(i); + assert vector != null; + + for (int j = 0; j < m.columnSize(); j++) + assertEquals("Unexpected value for " + desc + " at (" + i + "," + j + ")", + m.get(i, j), vector.get(j), 0d); + } + }); + } + + /** */ + @Test + public void testViewCol() { + consumeSampleMatrix((m, desc) -> { + if (!readOnly(m)) + fillMatrix(m); + + for (int i = 0; i < m.columnSize(); i++) { + Vector vector = m.viewColumn(i); + assert vector != null; + + for (int j = 0; j < m.rowSize(); j++) + assertEquals("Unexpected value for " + desc + " at (" + i + "," + j + ")", + m.get(j, i), vector.get(j), 0d); + } + }); + } + + /** */ + @Test + public void testFoldRow() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + fillMatrix(m); + + Vector foldRows = m.foldRows(Vector::sum); + + for (int i = 0; i < m.rowSize(); i++) { + Double locSum = 0d; + + for (int j = 0; j < m.columnSize(); j++) + locSum += m.get(i, j); + + assertEquals("Unexpected value for " + desc + " at " + i, + foldRows.get(i), locSum, 0d); + } + }); + } + + /** */ + @Test + public void testFoldCol() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + fillMatrix(m); + + Vector foldCols = m.foldColumns(Vector::sum); + + for (int j = 0; j < m.columnSize(); j++) { + Double locSum = 0d; + + for (int i = 0; i < m.rowSize(); i++) + locSum += m.get(i, j); + + assertEquals("Unexpected value for " + desc + " at " + j, + foldCols.get(j), locSum, 0d); + } + }); + } + + /** */ + @Test + public void testSum() { + consumeSampleMatrix((m, desc) -> { + double[][] data = fillAndReturn(m); + + double sum = m.sum(); + + double rawSum = 0; + for (double[] anArr : data) + for (int j = 0; j < data[0].length; j++) + rawSum += anArr[j]; + + assertEquals("Unexpected value for " + desc, + rawSum, sum, 0d); + }); + } + + /** */ + @Test + public void testMax() { + consumeSampleMatrix((m, desc) -> { + double[][] doubles = fillAndReturn(m); + double max = Double.NEGATIVE_INFINITY; + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + max = max < doubles[i][j] ? doubles[i][j] : max; + + assertEquals("Unexpected value for " + desc, m.maxValue(), max, 0d); + }); + } + + /** */ + @Test + public void testMin() { + consumeSampleMatrix((m, desc) -> { + double[][] doubles = fillAndReturn(m); + double min = Double.MAX_VALUE; + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + min = min > doubles[i][j] ? doubles[i][j] : min; + + assertEquals("Unexpected value for " + desc, m.minValue(), min, 0d); + }); + } + + /** */ + @Test + public void testGetElement() { + consumeSampleMatrix((m, desc) -> { + if (!(readOnly(m))) + fillMatrix(m); + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) { + final Matrix.Element e = m.getElement(i, j); + + final String details = desc + " at [" + i + "," + j + "]"; + + assertEquals("Unexpected element row " + details, i, e.row()); + assertEquals("Unexpected element col " + details, j, e.column()); + + final double val = m.get(i, j); + + assertEquals("Unexpected value for " + details, val, e.get(), 0d); + + boolean expECaught = false; + + final double newVal = val * 2.0; + + try { + e.set(newVal); + } + catch (UnsupportedOperationException uoe) { + if (!(readOnly(m))) + throw uoe; + + expECaught = true; + } + + if (readOnly(m)) { + if (!expECaught) + fail("Expected exception was not caught for " + details); + + continue; + } + + assertEquals("Unexpected value set for " + details, newVal, m.get(i, j), 0d); + } + }); + } + + /** */ + @Test + public void testGetX() { + consumeSampleMatrix((m, desc) -> { + if (!(readOnly(m))) + fillMatrix(m); + + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + assertEquals("Unexpected value for " + desc + " at [" + i + "," + j + "]", + m.get(i, j), m.getX(i, j), 0d); + }); + } + + /** */ + @Test + public void testGetMetaStorage() { + consumeSampleMatrix((m, desc) -> assertNotNull("Null meta storage in " + desc, m.getMetaStorage())); + } + + /** */ + @Test + public void testGuid() { + consumeSampleMatrix((m, desc) -> assertNotNull("Null guid in " + desc, m.guid())); + } + + /** */ + @Test + public void testSwapRows() { + consumeSampleMatrix((m, desc) -> { + if (readOnly(m)) + return; + + double[][] doubles = fillAndReturn(m); + + final int swap_i = m.rowSize() == 1 ? 0 : 1; + final int swap_j = 0; + + Matrix swap = m.swapRows(swap_i, swap_j); + + for (int col = 0; col < m.columnSize(); col++) { + assertEquals("Unexpected value for " + desc + " at col " + col + ", swap_i " + swap_i, + swap.get(swap_i, col), doubles[swap_j][col], 0d); + + assertEquals("Unexpected value for " + desc + " at col " + col + ", swap_j " + swap_j, + swap.get(swap_j, col), doubles[swap_i][col], 0d); + } + + testInvalidRowIndex(() -> m.swapRows(-1, 0), desc + " negative first swap index"); + testInvalidRowIndex(() -> m.swapRows(0, -1), desc + " negative second swap index"); + testInvalidRowIndex(() -> m.swapRows(m.rowSize(), 0), desc + " too large first swap index"); + testInvalidRowIndex(() -> m.swapRows(0, m.rowSize()), desc + " too large second swap index"); + }); + } + + /** */ + @Test + public void testSwapColumns() { + consumeSampleMatrix((m, desc) -> { + if (readOnly(m)) + return; + + double[][] doubles = fillAndReturn(m); + + final int swap_i = m.columnSize() == 1 ? 0 : 1; + final int swap_j = 0; + + Matrix swap = m.swapColumns(swap_i, swap_j); + + for (int row = 0; row < m.rowSize(); row++) { + assertEquals("Unexpected value for " + desc + " at row " + row + ", swap_i " + swap_i, + swap.get(row, swap_i), doubles[row][swap_j], 0d); + + assertEquals("Unexpected value for " + desc + " at row " + row + ", swap_j " + swap_j, + swap.get(row, swap_j), doubles[row][swap_i], 0d); + } + + testInvalidColIndex(() -> m.swapColumns(-1, 0), desc + " negative first swap index"); + testInvalidColIndex(() -> m.swapColumns(0, -1), desc + " negative second swap index"); + testInvalidColIndex(() -> m.swapColumns(m.columnSize(), 0), desc + " too large first swap index"); + testInvalidColIndex(() -> m.swapColumns(0, m.columnSize()), desc + " too large second swap index"); + }); + } + + /** */ + @Test + public void testSetRow() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + fillMatrix(m); + + int rowIdx = m.rowSize() / 2; + + double[] newValues = fillArray(m.columnSize()); + + m.setRow(rowIdx, newValues); + + for (int col = 0; col < m.columnSize(); col++) + assertEquals("Unexpected value for " + desc + " at " + col, + newValues[col], m.get(rowIdx, col), 0d); + + testInvalidCardinality(() -> m.setRow(rowIdx, new double[m.columnSize() + 1]), desc); + }); + } + + /** */ + @Test + public void testSetColumn() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + fillMatrix(m); + + int colIdx = m.columnSize() / 2; + + double[] newValues = fillArray(m.rowSize()); + + m.setColumn(colIdx, newValues); + + for (int row = 0; row < m.rowSize(); row++) + assertEquals("Unexpected value for " + desc + " at " + row, + newValues[row], m.get(row, colIdx), 0d); + + testInvalidCardinality(() -> m.setColumn(colIdx, new double[m.rowSize() + 1]), desc); + }); + } + + /** */ + @Test + public void testViewPart() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + fillMatrix(m); + + int rowOff = m.rowSize() < 3 ? 0 : 1; + int rows = m.rowSize() < 3 ? 1 : m.rowSize() - 2; + int colOff = m.columnSize() < 3 ? 0 : 1; + int cols = m.columnSize() < 3 ? 1 : m.columnSize() - 2; + + Matrix view1 = m.viewPart(rowOff, rows, colOff, cols); + Matrix view2 = m.viewPart(new int[] {rowOff, colOff}, new int[] {rows, cols}); + + String details = desc + " view [" + rowOff + ", " + rows + ", " + colOff + ", " + cols + "]"; + + for (int i = 0; i < rows; i++) + for (int j = 0; j < cols; j++) { + assertEquals("Unexpected view1 value for " + details + " at (" + i + "," + j + ")", + m.get(i + rowOff, j + colOff), view1.get(i, j), 0d); + + assertEquals("Unexpected view2 value for " + details + " at (" + i + "," + j + ")", + m.get(i + rowOff, j + colOff), view2.get(i, j), 0d); + } + }); + } + + /** */ + @Test + public void testDensity() { + consumeSampleMatrix((m, desc) -> { + if (!readOnly(m)) + fillMatrix(m); + + assertTrue("Unexpected density with threshold 0 for " + desc, m.density(0.0)); + + assertFalse("Unexpected density with threshold 1 for " + desc, m.density(1.0)); + }); + } + + /** */ + @Test + public void testMaxAbsRowSumNorm() { + consumeSampleMatrix((m, desc) -> { + if (!readOnly(m)) + fillMatrix(m); + + assertEquals("Unexpected value for " + desc, + maxAbsRowSumNorm(m), m.maxAbsRowSumNorm(), 0d); + }); + } + + /** */ + @Test + public void testAssignRow() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + fillMatrix(m); + + int rowIdx = m.rowSize() / 2; + + double[] newValues = fillArray(m.columnSize()); + + m.assignRow(rowIdx, new DenseLocalOnHeapVector(newValues)); + + for (int col = 0; col < m.columnSize(); col++) + assertEquals("Unexpected value for " + desc + " at " + col, + newValues[col], m.get(rowIdx, col), 0d); + + testInvalidCardinality(() -> m.assignRow(rowIdx, new DenseLocalOnHeapVector(m.columnSize() + 1)), desc); + }); + } + + /** */ + @Test + public void testAssignColumn() { + consumeSampleMatrix((m, desc) -> { + if (ignore(m.getClass())) + return; + + fillMatrix(m); + + int colIdx = m.columnSize() / 2; + + double[] newValues = fillArray(m.rowSize()); + + m.assignColumn(colIdx, new DenseLocalOnHeapVector(newValues)); + + for (int row = 0; row < m.rowSize(); row++) + assertEquals("Unexpected value for " + desc + " at " + row, + newValues[row], m.get(row, colIdx), 0d); + }); + } + + /** */ + private double[] fillArray(int len) { + double[] newValues = new double[len]; + + for (int i = 0; i < newValues.length; i++) + newValues[i] = newValues.length - i; + return newValues; + } + + /** */ + private double maxAbsRowSumNorm(Matrix m) { + double max = 0.0; + + for (int x = 0; x < m.rowSize(); x++) { + double sum = 0; + + for (int y = 0; y < m.columnSize(); y++) + sum += Math.abs(m.getX(x, y)); + + if (sum > max) + max = sum; + } + + return max; + } + + /** */ + private void testInvalidRowIndex(Supplier supplier, String desc) { + try { + supplier.get(); + } + catch (RowIndexException | IndexException ie) { + return; + } + + fail("Expected exception was not caught for " + desc); + } + + /** */ + private void testInvalidColIndex(Supplier supplier, String desc) { + try { + supplier.get(); + } + catch (ColumnIndexException | IndexException ie) { + return; + } + + fail("Expected exception was not caught for " + desc); + } + + /** */ + private void testMapMatrixWrongCardinality(Matrix m, String desc) { + for (int rowDelta : new int[] {-1, 0, 1}) + for (int colDelta : new int[] {-1, 0, 1}) { + if (rowDelta == 0 && colDelta == 0) + continue; + + int rowNew = m.rowSize() + rowDelta; + int colNew = m.columnSize() + colDelta; + + if (rowNew < 1 || colNew < 1) + continue; + + testInvalidCardinality(() -> m.map(new DenseLocalOnHeapMatrix(rowNew, colNew), (m1, m2) -> m1 + m2), + desc + " wrong cardinality when mapping to size " + rowNew + "x" + colNew); + } + } + + /** */ + private void testInvalidCardinality(Supplier supplier, String desc) { + try { + supplier.get(); + } + catch (CardinalityException ce) { + return; + } + + fail("Expected exception was not caught for " + desc); + } + + /** */ + private boolean readOnly(Matrix m) { + return m instanceof RandomMatrix; + } + + /** */ + private double[][] fillIntAndReturn(Matrix m) { + double[][] data = new double[m.rowSize()][m.columnSize()]; + + if (readOnly(m)) { + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + data[i][j] = m.get(i, j); + + } + else { + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + data[i][j] = i * m.rowSize() + j + 1; + + m.assign(data); + } + return data; + } + + /** */ + private double[][] fillAndReturn(Matrix m) { + double[][] data = new double[m.rowSize()][m.columnSize()]; + + if (readOnly(m)) { + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + data[i][j] = m.get(i, j); + + } + else { + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + data[i][j] = -0.5d + Math.random(); + + m.assign(data); + } + return data; + } + + /** */ + private void fillNonSingularMatrix(Matrix m) { + for (int i = 0; i < m.rowSize(); i++) { + m.set(i, i, 10); + + for (int j = 0; j < m.columnSize(); j++) + if (j != i) + m.set(i, j, 0.01d); + } + } + + /** */ + 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()); + } + + /** Ignore test for given matrix type. */ + private boolean ignore(Class clazz) { + List> ignoredClasses = Arrays.asList(RandomMatrix.class, PivotedMatrixView.class, + MatrixView.class, FunctionMatrix.class, TransposedMatrixView.class); + + for (Class ignoredClass : ignoredClasses) + if (ignoredClass.isAssignableFrom(clazz)) + return true; + + return false; + } + + /** */ + private Class likeMatrixType(Matrix m) { + for (Class clazz : likeTypesMap().keySet()) + if (clazz.isAssignableFrom(m.getClass())) + return likeTypesMap().get(clazz); + + return null; + } + + /** */ + private static Map, Class> likeVectorTypesMap() { + return new LinkedHashMap, Class>() {{ + put(DenseLocalOnHeapMatrix.class, DenseLocalOnHeapVector.class); + put(DenseLocalOffHeapMatrix.class, DenseLocalOffHeapVector.class); + put(RandomMatrix.class, RandomVector.class); + put(SparseLocalOnHeapMatrix.class, SparseLocalVector.class); + put(DenseLocalOnHeapMatrix.class, DenseLocalOnHeapVector.class); + put(DiagonalMatrix.class, DenseLocalOnHeapVector.class); // IMPL NOTE per fixture + // IMPL NOTE check for presence of all implementations here will be done in testHaveLikeMatrix via Fixture + }}; + } + + /** */ + private static Map, Class> likeTypesMap() { + return new LinkedHashMap, Class>() {{ + put(DenseLocalOnHeapMatrix.class, DenseLocalOnHeapMatrix.class); + put(DenseLocalOffHeapMatrix.class, DenseLocalOffHeapMatrix.class); + put(RandomMatrix.class, RandomMatrix.class); + put(SparseLocalOnHeapMatrix.class, SparseLocalOnHeapMatrix.class); + put(DenseLocalOnHeapMatrix.class, DenseLocalOnHeapMatrix.class); + put(DiagonalMatrix.class, DenseLocalOnHeapMatrix.class); // IMPL NOTE per fixture + put(FunctionMatrix.class, FunctionMatrix.class); + // IMPL NOTE check for presence of all implementations here will be done in testHaveLikeMatrix via Fixture + }}; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/0abf6601/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixKeyMapperForTests.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixKeyMapperForTests.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixKeyMapperForTests.java new file mode 100644 index 0000000..bc628c9 --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixKeyMapperForTests.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ignite.ml.math.impls.matrix; + +import org.apache.ignite.ml.math.MatrixKeyMapper; + +/** */ +public class MatrixKeyMapperForTests implements MatrixKeyMapper { + /** */ private int rows; + /** */ private int cols; + + /** */ + public MatrixKeyMapperForTests() { + // No-op. + } + + /** */ + public MatrixKeyMapperForTests(int rows, int cols) { + this.rows = rows; + this.cols = cols; + } + + /** */ + @Override public Integer apply(int x, int y) { + return x * cols + y; + } + + /** */ + @Override public boolean isValid(Integer integer) { + return (rows * cols) > integer; + } + + /** */ + @Override public int hashCode() { + int hash = 1; + + hash += hash * 31 + rows; + hash += hash * 31 + cols; + + return hash; + } + + /** */ + @Override public boolean equals(Object obj) { + if (this == obj) + return true; + + if (obj == null || getClass() != obj.getClass()) + return false; + + MatrixKeyMapperForTests that = (MatrixKeyMapperForTests)obj; + + return rows == that.rows && cols == that.cols; + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/0abf6601/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixViewConstructorTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixViewConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixViewConstructorTest.java new file mode 100644 index 0000000..82564cb --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/MatrixViewConstructorTest.java @@ -0,0 +1,114 @@ +/* + * 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.ml.math.impls.matrix; + +import org.apache.ignite.ml.math.Matrix; +import org.apache.ignite.ml.math.impls.storage.matrix.MatrixDelegateStorage; +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +/** */ +public class MatrixViewConstructorTest { + /** */ + @Test + public void invalidArgsTest() { + Matrix m = new DenseLocalOnHeapMatrix(1, 1); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new MatrixView((Matrix)null, 0, 0, 1, 1), + "Null parent matrix."); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new MatrixView(m, -1, 0, 1, 1), + "Invalid row offset."); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new MatrixView(m, 0, -1, 1, 1), + "Invalid col offset."); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new MatrixView(m, 0, 0, 0, 1), + "Invalid rows."); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new MatrixView(m, 0, 0, 1, 0), + "Invalid cols."); + } + + /** */ + @Test + public void basicTest() { + for (Matrix m : new Matrix[] { + new DenseLocalOnHeapMatrix(3, 3), + new DenseLocalOnHeapMatrix(3, 4), new DenseLocalOnHeapMatrix(4, 3)}) + for (int rowOff : new int[] {0, 1}) + for (int colOff : new int[] {0, 1}) + for (int rows : new int[] {1, 2}) + for (int cols : new int[] {1, 2}) + basicTest(m, rowOff, colOff, rows, cols); + } + + /** */ + private void basicTest(Matrix parent, int rowOff, int colOff, int rows, int cols) { + for (int row = 0; row < parent.rowSize(); row++) + for (int col = 0; col < parent.columnSize(); col++) + parent.set(row, col, row * parent.columnSize() + col + 1); + + Matrix view = new MatrixView(parent, rowOff, colOff, rows, cols); + + assertEquals("Rows in view.", rows, view.rowSize()); + assertEquals("Cols in view.", cols, view.columnSize()); + + for (int row = 0; row < rows; row++) + for (int col = 0; col < cols; col++) + assertEquals("Unexpected value at " + row + "x" + col, + parent.get(row + rowOff, col + colOff), view.get(row, col), 0d); + + for (int row = 0; row < rows; row++) + for (int col = 0; col < cols; col++) + view.set(row, col, 0d); + + for (int row = 0; row < rows; row++) + for (int col = 0; col < cols; col++) + assertEquals("Unexpected value set at " + row + "x" + col, + 0d, parent.get(row + rowOff, col + colOff), 0d); + } + + /** */ + @Test + public void attributeTest() { + for (Matrix m : new Matrix[] { + new DenseLocalOnHeapMatrix(3, 3), + new DenseLocalOnHeapMatrix(3, 4), new DenseLocalOnHeapMatrix(4, 3)}) { + MatrixView matrixView = new MatrixView(m, 0, 0, m.rowSize(), m.columnSize()); + + MatrixDelegateStorage delegateStorage = (MatrixDelegateStorage)matrixView.getStorage(); + + assertEquals(m.rowSize(), matrixView.rowSize()); + assertEquals(m.columnSize(), matrixView.columnSize()); + + assertEquals(m.rowSize(), (delegateStorage).rowsLength()); + assertEquals(m.columnSize(), (delegateStorage).columnsLength()); + + assertEquals(m.isSequentialAccess(), delegateStorage.isSequentialAccess()); + assertEquals(m.isRandomAccess(), delegateStorage.isRandomAccess()); + assertEquals(m.isDistributed(), delegateStorage.isDistributed()); + assertEquals(m.isDense(), delegateStorage.isDense()); + assertEquals(m.isArrayBased(), delegateStorage.isArrayBased()); + + assertArrayEquals(m.getStorage().data(), delegateStorage.data()); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/0abf6601/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/PivotedMatrixViewConstructorTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/PivotedMatrixViewConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/PivotedMatrixViewConstructorTest.java new file mode 100644 index 0000000..87bf3ad --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/PivotedMatrixViewConstructorTest.java @@ -0,0 +1,129 @@ +/* + * 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.ml.math.impls.matrix; + +import java.util.Arrays; +import org.apache.ignite.ml.math.Matrix; +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** */ +public class PivotedMatrixViewConstructorTest { + /** */ + @Test + public void invalidArgsTest() { + Matrix m = new DenseLocalOnHeapMatrix(1, 1); + + int[] pivot = new int[] {0}; + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new PivotedMatrixView(null), + "Null parent matrix."); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new PivotedMatrixView(null, pivot), + "Null parent matrix, with pivot."); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new PivotedMatrixView(m, null), + "Null pivot."); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new PivotedMatrixView(m, null, pivot), + "Null row pivot."); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new PivotedMatrixView(m, pivot, null), + "Null col pivot."); + } + + /** */ + @Test + public void basicTest() { + Matrix m = new DenseLocalOnHeapMatrix(2, 2); + + int[] pivot = new int[] {0, 1}; + + PivotedMatrixView view = new PivotedMatrixView(m, pivot); + + assertEquals("Rows in view.", m.rowSize(), view.rowSize()); + assertEquals("Cols in view.", m.columnSize(), view.columnSize()); + + assertTrue("Row pivot array in view.", Arrays.equals(pivot, view.rowPivot())); + assertTrue("Col pivot array in view.", Arrays.equals(pivot, view.columnPivot())); + + Assert.assertEquals("Base matrix in view.", m, view.getBaseMatrix()); + + assertEquals("Row pivot value in view.", 0, view.rowPivot(0)); + assertEquals("Col pivot value in view.", 0, view.columnPivot(0)); + + assertEquals("Row unpivot value in view.", 0, view.rowUnpivot(0)); + assertEquals("Col unpivot value in view.", 0, view.columnUnpivot(0)); + + Matrix swap = view.swap(1, 1); + + for (int row = 0; row < view.rowSize(); row++) + for (int col = 0; col < view.columnSize(); col++) + assertEquals("Unexpected swap value set at (" + row + "," + col + ").", + view.get(row, col), swap.get(row, col), 0d); + + //noinspection EqualsWithItself + assertTrue("View is expected to be equal to self.", view.equals(view)); + //noinspection ObjectEqualsNull + assertFalse("View is expected to be not equal to null.", view.equals(null)); + } + + /** */ + @Test + public void pivotTest() { + int[] pivot = new int[] {2, 1, 0, 3}; + + for (Matrix m : new Matrix[] { + new DenseLocalOnHeapMatrix(3, 3), + new DenseLocalOnHeapMatrix(3, 4), new DenseLocalOnHeapMatrix(4, 3)}) + pivotTest(m, pivot); + } + + /** */ + private void pivotTest(Matrix parent, int[] pivot) { + for (int row = 0; row < parent.rowSize(); row++) + for (int col = 0; col < parent.columnSize(); col++) + parent.set(row, col, row * parent.columnSize() + col + 1); + + Matrix view = new PivotedMatrixView(parent, pivot); + + int rows = parent.rowSize(); + int cols = parent.columnSize(); + + assertEquals("Rows in view.", rows, view.rowSize()); + assertEquals("Cols in view.", cols, view.columnSize()); + + for (int row = 0; row < rows; row++) + for (int col = 0; col < cols; col++) + assertEquals("Unexpected value at " + row + "x" + col, + parent.get(pivot[row], pivot[col]), view.get(row, col), 0d); + + int min = rows < cols ? rows : cols; + + for (int idx = 0; idx < min; idx++) + view.set(idx, idx, 0d); + + for (int idx = 0; idx < min; idx++) + assertEquals("Unexpected value set at " + idx, + 0d, parent.get(pivot[idx], pivot[idx]), 0d); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/0abf6601/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/RandomMatrixConstructorTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/RandomMatrixConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/RandomMatrixConstructorTest.java new file mode 100644 index 0000000..558e4d8 --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/RandomMatrixConstructorTest.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.ml.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 RandomMatrixConstructorTest { + /** */ + @Test + public void invalidArgsTest() { + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new RandomMatrix(0, 1), "invalid row parameter"); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new RandomMatrix(1, 0), "invalid col parameter"); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new RandomMatrix(0, 1, true), "invalid row parameter, fastHash true"); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new RandomMatrix(1, 0, true), "invalid col parameter, fastHash true"); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new RandomMatrix(0, 1, false), "invalid row parameter, fastHash false"); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new RandomMatrix(1, 0, false), "invalid col parameter, fastHash false"); + } + + /** */ + @Test + public void basicTest() { + assertEquals("Expected number of rows, int parameters.", 1, + new RandomMatrix(1, 2).rowSize()); + + assertEquals("Expected number of cols, int parameters.", 1, + new RandomMatrix(2, 1).columnSize()); + + assertEquals("Expected number of rows, int parameters, fastHash true.", 1, + new RandomMatrix(1, 2, true).rowSize()); + + assertEquals("Expected number of cols, int parameters, fastHash true.", 1, + new RandomMatrix(2, 1, true).columnSize()); + + assertEquals("Expected number of rows, int parameters, fastHash false.", 1, + new RandomMatrix(1, 2, false).rowSize()); + + assertEquals("Expected number of cols, int parameters, fastHash false.", 1, + new RandomMatrix(2, 1, false).columnSize()); + + RandomMatrix m = new RandomMatrix(1, 1); + //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)); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/0abf6601/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/SparseDistributedMatrixTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/SparseDistributedMatrixTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/SparseDistributedMatrixTest.java new file mode 100644 index 0000000..8985806 --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/SparseDistributedMatrixTest.java @@ -0,0 +1,265 @@ +// @java.file.header + +/* _________ _____ __________________ _____ + * __ ____/___________(_)______ /__ ____/______ ____(_)_______ + * _ / __ __ ___/__ / _ __ / _ / __ _ __ `/__ / __ __ \ + * / /_/ / _ / _ / / /_/ / / /_/ / / /_/ / _ / _ / / / + * \____/ /_/ /_/ \_,__/ \____/ \__,_/ /_/ /_/ /_/ + */ + +/* + * 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.ml.math.impls.matrix; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import org.apache.ignite.Ignite; +import org.apache.ignite.internal.util.IgniteUtils; +import org.apache.ignite.ml.math.Matrix; +import org.apache.ignite.ml.math.StorageConstants; +import org.apache.ignite.ml.math.exceptions.UnsupportedOperationException; +import org.apache.ignite.ml.math.impls.MathTestConstants; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.apache.ignite.testframework.junits.common.GridCommonTest; + +import static org.apache.ignite.ml.math.impls.MathTestConstants.UNEXPECTED_VAL; + +/** + * Tests for {@link SparseDistributedMatrix}. + */ +@GridCommonTest(group = "Distributed Models") +public class SparseDistributedMatrixTest extends GridCommonAbstractTest { + /** Number of nodes in grid */ + private static final int NODE_COUNT = 3; + /** Cache name. */ + private static final String CACHE_NAME = "test-cache"; + /** Precision. */ + private static final double PRECISION = 0.0; + /** Grid instance. */ + private Ignite ignite; + /** Matrix rows */ + private final int rows = MathTestConstants.STORAGE_SIZE; + /** Matrix cols */ + private final int cols = MathTestConstants.STORAGE_SIZE; + /** Matrix for tests */ + private SparseDistributedMatrix cacheMatrix; + + /** + * Default constructor. + */ + public SparseDistributedMatrixTest() { + 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); + + if (cacheMatrix != null) { + cacheMatrix.destroy(); + cacheMatrix = null; + } + } + + /** */ + public void testGetSet() throws Exception { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + cacheMatrix = new SparseDistributedMatrix(rows, cols, StorageConstants.ROW_STORAGE_MODE, StorageConstants.RANDOM_ACCESS_MODE); + + 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; + } + } + } + + /** */ + public void testExternalize() throws IOException, ClassNotFoundException { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + cacheMatrix = new SparseDistributedMatrix(rows, cols, StorageConstants.ROW_STORAGE_MODE, StorageConstants.RANDOM_ACCESS_MODE); + + cacheMatrix.set(1, 1, 1.0); + + ByteArrayOutputStream byteArrOutputStream = new ByteArrayOutputStream(); + ObjectOutputStream objOutputStream = new ObjectOutputStream(byteArrOutputStream); + + objOutputStream.writeObject(cacheMatrix); + + ByteArrayInputStream byteArrInputStream = new ByteArrayInputStream(byteArrOutputStream.toByteArray()); + ObjectInputStream objInputStream = new ObjectInputStream(byteArrInputStream); + + SparseDistributedMatrix objRestored = (SparseDistributedMatrix)objInputStream.readObject(); + + assertTrue(MathTestConstants.VAL_NOT_EQUALS, cacheMatrix.equals(objRestored)); + assertEquals(MathTestConstants.VAL_NOT_EQUALS, objRestored.get(1, 1), 1.0, 0.0); + } + + /** Test simple math. */ + public void testMath() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + cacheMatrix = new SparseDistributedMatrix(rows, cols, StorageConstants.ROW_STORAGE_MODE, StorageConstants.RANDOM_ACCESS_MODE); + initMtx(cacheMatrix); + + cacheMatrix.assign(2.0); + for (int i = 0; i < cacheMatrix.rowSize(); i++) + for (int j = 0; j < cacheMatrix.columnSize(); j++) + assertEquals(UNEXPECTED_VAL, 2.0, cacheMatrix.get(i, j), PRECISION); + + cacheMatrix.plus(3.0); + for (int i = 0; i < cacheMatrix.rowSize(); i++) + for (int j = 0; j < cacheMatrix.columnSize(); j++) + assertEquals(UNEXPECTED_VAL, 5.0, cacheMatrix.get(i, j), PRECISION); + + cacheMatrix.times(2.0); + for (int i = 0; i < cacheMatrix.rowSize(); i++) + for (int j = 0; j < cacheMatrix.columnSize(); j++) + assertEquals(UNEXPECTED_VAL, 10.0, cacheMatrix.get(i, j), PRECISION); + + cacheMatrix.divide(10.0); + for (int i = 0; i < cacheMatrix.rowSize(); i++) + for (int j = 0; j < cacheMatrix.columnSize(); j++) + assertEquals(UNEXPECTED_VAL, 1.0, cacheMatrix.get(i, j), PRECISION); + + assertEquals(UNEXPECTED_VAL, cacheMatrix.rowSize() * cacheMatrix.columnSize(), cacheMatrix.sum(), PRECISION); + } + + /** */ + public void testMinMax() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + cacheMatrix = new SparseDistributedMatrix(rows, cols, StorageConstants.ROW_STORAGE_MODE, StorageConstants.RANDOM_ACCESS_MODE); + + for (int i = 0; i < cacheMatrix.rowSize(); i++) + for (int j = 0; j < cacheMatrix.columnSize(); j++) + cacheMatrix.set(i, j, i * cols + j + 1); + + assertEquals(UNEXPECTED_VAL, 1.0, cacheMatrix.minValue(), PRECISION); + assertEquals(UNEXPECTED_VAL, rows * cols, cacheMatrix.maxValue(), PRECISION); + + for (int i = 0; i < cacheMatrix.rowSize(); i++) + for (int j = 0; j < cacheMatrix.columnSize(); j++) + cacheMatrix.set(i, j, -1.0 * (i * cols + j + 1)); + + assertEquals(UNEXPECTED_VAL, -rows * cols, cacheMatrix.minValue(), PRECISION); + assertEquals(UNEXPECTED_VAL, -1.0, cacheMatrix.maxValue(), PRECISION); + + for (int i = 0; i < cacheMatrix.rowSize(); i++) + for (int j = 0; j < cacheMatrix.columnSize(); j++) + cacheMatrix.set(i, j, i * cols + j); + + assertEquals(UNEXPECTED_VAL, 1.0, cacheMatrix.minValue(), PRECISION); + assertEquals(UNEXPECTED_VAL, rows * cols - 1.0, cacheMatrix.maxValue(), PRECISION); + } + + /** */ + public void testMap() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + cacheMatrix = new SparseDistributedMatrix(rows, cols, StorageConstants.ROW_STORAGE_MODE, StorageConstants.RANDOM_ACCESS_MODE); + initMtx(cacheMatrix); + + cacheMatrix.map(i -> 100.0); + for (int i = 0; i < cacheMatrix.rowSize(); i++) + for (int j = 0; j < cacheMatrix.columnSize(); j++) + assertEquals(UNEXPECTED_VAL, 100.0, cacheMatrix.get(i, j), PRECISION); + } + + /** */ + public void testCopy() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + cacheMatrix = new SparseDistributedMatrix(rows, cols, StorageConstants.ROW_STORAGE_MODE, StorageConstants.RANDOM_ACCESS_MODE); + + try { + cacheMatrix.copy(); + fail("UnsupportedOperationException expected."); + } + catch (UnsupportedOperationException e) { + return; + } + fail("UnsupportedOperationException expected."); + } + + /** */ + public void testLike() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + cacheMatrix = new SparseDistributedMatrix(rows, cols, StorageConstants.ROW_STORAGE_MODE, StorageConstants.RANDOM_ACCESS_MODE); + + try { + cacheMatrix.like(1, 1); + fail("UnsupportedOperationException expected."); + } + catch (UnsupportedOperationException e) { + return; + } + fail("UnsupportedOperationException expected."); + } + + /** */ + public void testLikeVector() { + IgniteUtils.setCurrentIgniteName(ignite.configuration().getIgniteInstanceName()); + + cacheMatrix = new SparseDistributedMatrix(rows, cols, StorageConstants.ROW_STORAGE_MODE, StorageConstants.RANDOM_ACCESS_MODE); + + try { + cacheMatrix.likeVector(1); + fail("UnsupportedOperationException expected."); + } + catch (UnsupportedOperationException e) { + return; + } + fail("UnsupportedOperationException expected."); + } + + /** */ + private void initMtx(Matrix m) { + for (int i = 0; i < m.rowSize(); i++) + for (int j = 0; j < m.columnSize(); j++) + m.set(i, j, 1.0); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/0abf6601/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/SparseLocalOnHeapMatrixConstructorTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/SparseLocalOnHeapMatrixConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/SparseLocalOnHeapMatrixConstructorTest.java new file mode 100644 index 0000000..bc05eb7 --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/SparseLocalOnHeapMatrixConstructorTest.java @@ -0,0 +1,53 @@ +/* + * 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.ml.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 SparseLocalOnHeapMatrixConstructorTest { + /** */ + @Test + public void invalidArgsTest() { + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new SparseLocalOnHeapMatrix(0, 1), + "invalid row parameter"); + + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new SparseLocalOnHeapMatrix(1, 0), + "invalid col parameter"); + } + + /** */ + @Test + public void basicTest() { + assertEquals("Expected number of rows.", 1, + new SparseLocalOnHeapMatrix(1, 2).rowSize()); + + assertEquals("Expected number of cols, int parameters.", 1, + new SparseLocalOnHeapMatrix(2, 1).columnSize()); + + SparseLocalOnHeapMatrix m = new SparseLocalOnHeapMatrix(1, 1); + //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)); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/0abf6601/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/TransposedMatrixViewTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/TransposedMatrixViewTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/TransposedMatrixViewTest.java new file mode 100644 index 0000000..22ec7cc --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/matrix/TransposedMatrixViewTest.java @@ -0,0 +1,87 @@ +/* + * 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.ml.math.impls.matrix; + +import org.apache.ignite.ml.math.ExternalizeTest; +import org.apache.ignite.ml.math.exceptions.UnsupportedOperationException; +import org.apache.ignite.ml.math.impls.MathTestConstants; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Tests for {@link TransposedMatrixView}. + */ +public class TransposedMatrixViewTest extends ExternalizeTest { + /** */ + private static final String UNEXPECTED_VALUE = "Unexpected value"; + /** */ + private TransposedMatrixView testMatrix; + /** */ + private DenseLocalOnHeapMatrix parent; + + /** */ + @Before + public void setup() { + parent = new DenseLocalOnHeapMatrix(MathTestConstants.STORAGE_SIZE, MathTestConstants.STORAGE_SIZE); + fillMatrix(parent); + testMatrix = new TransposedMatrixView(parent); + } + + /** {@inheritDoc} */ + @Override public void externalizeTest() { + externalizeTest(testMatrix); + } + + /** */ + @Test + public void testView() { + assertEquals(UNEXPECTED_VALUE, parent.rowSize(), testMatrix.columnSize()); + assertEquals(UNEXPECTED_VALUE, parent.columnSize(), testMatrix.rowSize()); + + for (int i = 0; i < parent.rowSize(); i++) + for (int j = 0; j < parent.columnSize(); j++) + assertEquals(UNEXPECTED_VALUE, parent.get(i, j), testMatrix.get(j, i), 0d); + } + + /** */ + @Test + public void testNullParams() { + DenseLocalOnHeapMatrixConstructorTest.verifyAssertionError(() -> new TransposedMatrixView(null), "Null Matrix parameter"); + } + + /** */ + @Test(expected = UnsupportedOperationException.class) + public void testLike() { + testMatrix.like(0, 0); + } + + /** */ + @Test(expected = UnsupportedOperationException.class) + public void testLikeVector() { + testMatrix.likeVector(0); + } + + /** */ + private void fillMatrix(DenseLocalOnHeapMatrix mtx) { + for (int i = 0; i < mtx.rowSize(); i++) + for (int j = 0; j < mtx.columnSize(); j++) + mtx.setX(i, j, i * mtx.rowSize() + j); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/0abf6601/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixArrayStorageTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixArrayStorageTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixArrayStorageTest.java new file mode 100644 index 0000000..569ed57 --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixArrayStorageTest.java @@ -0,0 +1,63 @@ +/* + * 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.ml.math.impls.storage.matrix; + +import org.apache.ignite.ml.math.impls.MathTestConstants; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * Unit tests for {@link ArrayMatrixStorage}. + */ +public class MatrixArrayStorageTest extends MatrixBaseStorageTest { + /** {@inheritDoc} */ + @Override public void setUp() { + storage = new ArrayMatrixStorage(MathTestConstants.STORAGE_SIZE, MathTestConstants.STORAGE_SIZE); + } + + /** */ + @Test + public void isSequentialAccess() throws Exception { + assertFalse(MathTestConstants.UNEXPECTED_VAL, storage.isSequentialAccess()); + } + + /** */ + @Test + public void isDense() throws Exception { + assertTrue(MathTestConstants.UNEXPECTED_VAL, storage.isDense()); + } + + /** */ + @Test + public void isArrayBased() throws Exception { + assertTrue(MathTestConstants.UNEXPECTED_VAL, storage.isArrayBased()); + } + + /** */ + @Test + public void data() throws Exception { + double[][] data = storage.data(); + assertNotNull(MathTestConstants.NULL_VAL, data); + assertTrue(MathTestConstants.UNEXPECTED_VAL, data.length == MathTestConstants.STORAGE_SIZE); + assertTrue(MathTestConstants.UNEXPECTED_VAL, data[0].length == MathTestConstants.STORAGE_SIZE); + } + +} http://git-wip-us.apache.org/repos/asf/ignite/blob/0abf6601/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixBaseStorageTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixBaseStorageTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixBaseStorageTest.java new file mode 100644 index 0000000..94e87c2 --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixBaseStorageTest.java @@ -0,0 +1,89 @@ +/* + * 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.ml.math.impls.storage.matrix; + +import org.apache.ignite.ml.math.ExternalizeTest; +import org.apache.ignite.ml.math.MatrixStorage; +import org.apache.ignite.ml.math.impls.MathTestConstants; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Abstract class with base tests for each matrix storage. + */ +public abstract class MatrixBaseStorageTest extends ExternalizeTest { + /** */ + protected T storage; + + /** */ + @Before + public abstract void setUp(); + + /** */ + @After + public void tearDown() throws Exception { + storage.destroy(); + } + + /** */ + @Test + public void getSet() throws Exception { + int rows = MathTestConstants.STORAGE_SIZE; + int cols = MathTestConstants.STORAGE_SIZE; + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + double data = Math.random(); + + storage.set(i, j, data); + + Assert.assertEquals(MathTestConstants.VAL_NOT_EQUALS, storage.get(i, j), data, MathTestConstants.NIL_DELTA); + } + } + } + + /** */ + @Test + public void columnSize() throws Exception { + assertEquals(MathTestConstants.VAL_NOT_EQUALS, storage.columnSize(), MathTestConstants.STORAGE_SIZE); + } + + /** */ + @Test + public void rowSize() throws Exception { + assertEquals(MathTestConstants.VAL_NOT_EQUALS, storage.rowSize(), MathTestConstants.STORAGE_SIZE); + } + + /** */ + @Override public void externalizeTest() { + fillMatrix(); + super.externalizeTest(storage); + } + + /** */ + protected void fillMatrix() { + for (int i = 0; i < storage.rowSize(); i++) { + for (int j = 0; j < storage.columnSize(); j++) + storage.set(i, j, Math.random()); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/0abf6601/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixOffHeapStorageTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixOffHeapStorageTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixOffHeapStorageTest.java new file mode 100644 index 0000000..52d57fd --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixOffHeapStorageTest.java @@ -0,0 +1,39 @@ +/* + * 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.ml.math.impls.storage.matrix; + +import org.apache.ignite.ml.math.impls.MathTestConstants; +import org.junit.Test; + +import static org.junit.Assert.assertNull; + +/** + * Unit tests for {@link DenseOffHeapMatrixStorage}. + */ +public class MatrixOffHeapStorageTest extends MatrixBaseStorageTest { + /** {@inheritDoc} */ + @Override public void setUp() { + storage = new DenseOffHeapMatrixStorage(MathTestConstants.STORAGE_SIZE, MathTestConstants.STORAGE_SIZE); + } + + /** */ + @Test + public void data() throws Exception { + assertNull(MathTestConstants.UNEXPECTED_VAL, storage.data()); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/0abf6601/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixStorageFixtures.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixStorageFixtures.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixStorageFixtures.java new file mode 100644 index 0000000..03473cf --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixStorageFixtures.java @@ -0,0 +1,137 @@ +/* + * 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.ml.math.impls.storage.matrix; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.function.BiConsumer; +import java.util.function.Supplier; +import org.apache.ignite.ml.math.MatrixStorage; +import org.apache.ignite.ml.math.StorageConstants; +import org.jetbrains.annotations.NotNull; + +/** + * + */ +class MatrixStorageFixtures { + /** */ + private static final List>> suppliers = Collections.singletonList( + (Supplier>) SparseLocalMatrixStorageFixture::new + ); + + /** */ + void consumeSampleStorages(BiConsumer paramsConsumer, + BiConsumer consumer) { + for (Supplier> fixtureSupplier : suppliers) { + final Iterable fixture = fixtureSupplier.get(); + + for (MatrixStorage matrixStorage : fixture) { + if (paramsConsumer != null) + paramsConsumer.accept(matrixStorage.rowSize(), matrixStorage.columnSize()); + + consumer.accept(matrixStorage, fixture.toString()); + } + } + } + + /** */ + private static class SparseLocalMatrixStorageFixture implements Iterable { + /** */ + private final Integer[] rows = new Integer[] {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 512, 1024, null}; + /** */ + private final Integer[] cols = new Integer[] {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024, 512, null}; + /** */ + private final Integer[] randomAccess = new Integer[] {StorageConstants.SEQUENTIAL_ACCESS_MODE, StorageConstants.RANDOM_ACCESS_MODE, null}; + /** */ + private final Integer[] rowStorage = new Integer[] {StorageConstants.ROW_STORAGE_MODE, StorageConstants.COLUMN_STORAGE_MODE, null}; + /** */ + private int sizeIdx = 0; + /** */ + private int acsModeIdx = 0; + /** */ + private int stoModeIdx = 0; + + /** {@inheritDoc} */ + @NotNull + @Override public Iterator iterator() { + return new Iterator() { + /** {@inheritDoc} */ + @Override public boolean hasNext() { + return hasNextCol(sizeIdx) && hasNextRow(sizeIdx) + && hasNextAcsMode(acsModeIdx) && hasNextStoMode(stoModeIdx); + } + + /** {@inheritDoc} */ + @Override public MatrixStorage next() { + if (!hasNext()) + throw new NoSuchElementException(SparseLocalMatrixStorageFixture.this.toString()); + + MatrixStorage storage = new SparseLocalOnHeapMatrixStorage( + rows[sizeIdx], cols[sizeIdx], randomAccess[acsModeIdx], rowStorage[stoModeIdx]); + + nextIdx(); + + return storage; + } + + private void nextIdx() { + if (hasNextStoMode(stoModeIdx + 1)) { + stoModeIdx++; + + return; + } + + stoModeIdx = 0; + + if (hasNextAcsMode(acsModeIdx + 1)) { + acsModeIdx++; + + return; + } + + acsModeIdx = 0; + sizeIdx++; + } + }; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "SparseLocalMatrixStorageFixture{ " + "rows=" + rows[sizeIdx] + ", cols=" + cols[sizeIdx] + + ", access mode=" + randomAccess[acsModeIdx] + ", storage mode=" + rowStorage[stoModeIdx] + "}"; + } + + /** */ private boolean hasNextRow(int idx) { + return rows[idx] != null; + } + + /** */ private boolean hasNextCol(int idx) { + return cols[idx] != null; + } + + /** */ private boolean hasNextAcsMode(int idx) { + return randomAccess[idx] != null; + } + + /** */ private boolean hasNextStoMode(int idx) { + return rowStorage[idx] != null; + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/0abf6601/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixStorageImplementationTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixStorageImplementationTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixStorageImplementationTest.java new file mode 100644 index 0000000..72daeca --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/storage/matrix/MatrixStorageImplementationTest.java @@ -0,0 +1,73 @@ +/* + * 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.ml.math.impls.storage.matrix; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; +import org.apache.ignite.ml.math.ExternalizeTest; +import org.apache.ignite.ml.math.MatrixStorage; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +/** + * Unit tests for {@link MatrixStorage} implementations. + * + * TODO: add attribute tests. + */ +public class MatrixStorageImplementationTest extends ExternalizeTest { + /** + * The columnSize() and the rowSize() test. + */ + @Test + public void sizeTest() { + final AtomicReference expRowSize = new AtomicReference<>(0); + final AtomicReference expColSize = new AtomicReference<>(0); + + consumeSampleStorages((x, y) -> { + expRowSize.set(x); + expColSize.set(y); + }, + (ms, desc) -> assertTrue("Expected size for " + desc, expColSize.get().equals(ms.columnSize()) && expRowSize.get().equals(ms.rowSize()))); + } + + /** */ + @Test + public void getSetTest() { + consumeSampleStorages(null, (ms, desc) -> { + for (int i = 0; i < ms.rowSize(); i++) { + for (int j = 0; j < ms.columnSize(); j++) { + double random = Math.random(); + ms.set(i, j, random); + assertTrue("Unexpected value for " + desc + " x:" + i + ", y:" + j, Double.compare(random, ms.get(i, j)) == 0); + } + } + }); + } + + /** */ + @Override public void externalizeTest() { + consumeSampleStorages(null, (ms, desc) -> externalizeTest(ms)); + } + + /** */ + private void consumeSampleStorages(BiConsumer paramsConsumer, + BiConsumer consumer) { + new MatrixStorageFixtures().consumeSampleStorages(paramsConsumer, consumer); + } +}