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 B4C8D200C7E for ; Tue, 18 Apr 2017 07:39:12 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id B3246160BB9; Tue, 18 Apr 2017 05:39: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 8A062160BB0 for ; Tue, 18 Apr 2017 07:39:10 +0200 (CEST) Received: (qmail 56319 invoked by uid 500); 18 Apr 2017 05:39:09 -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 54881 invoked by uid 99); 18 Apr 2017 05:39:04 -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; Tue, 18 Apr 2017 05:39:04 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id E6A73DFC31; Tue, 18 Apr 2017 05:39:03 +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: Tue, 18 Apr 2017 05:39:14 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [12/46] ignite git commit: IGNITE-5000 Rename Ignite Math module to Ignite ML module archived-at: Tue, 18 Apr 2017 05:39:12 -0000 http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/MatrixVectorViewTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/MatrixVectorViewTest.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/MatrixVectorViewTest.java new file mode 100644 index 0000000..b7e390e --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/MatrixVectorViewTest.java @@ -0,0 +1,209 @@ +package org.apache.ignite.math.impls.vector; + +import org.apache.ignite.math.Matrix; +import org.apache.ignite.math.Vector; +import org.apache.ignite.math.exceptions.IndexException; +import org.apache.ignite.math.impls.matrix.DenseLocalOnHeapMatrix; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Tests for {@link MatrixVectorView}. + */ +public class MatrixVectorViewTest { + /** */ + private static final String UNEXPECTED_VALUE = "Unexpected value"; + /** */ + private static final int SMALL_SIZE = 3; + /** */ + private static final int IMPOSSIBLE_SIZE = -1; + + /** */ + private Matrix parent; + + /** */ + @Before + public void setup() { + parent = newMatrix(SMALL_SIZE, SMALL_SIZE); + } + + /** */ + @Test + public void testDiagonal() { + Vector vector = parent.viewDiagonal(); + + for (int i = 0; i < SMALL_SIZE; i++) + assertView(i, i, vector, i); + } + + /** */ + @Test + public void testRow() { + for (int i = 0; i < SMALL_SIZE; i++) { + Vector viewRow = parent.viewRow(i); + + for (int j = 0; j < SMALL_SIZE; j++) + assertView(i, j, viewRow, j); + } + } + + /** */ + @Test + public void testCols() { + for (int i = 0; i < SMALL_SIZE; i++) { + Vector viewCol = parent.viewColumn(i); + + for (int j = 0; j < SMALL_SIZE; j++) + assertView(j, i, viewCol, j); + } + } + + /** */ + @Test + public void basicTest() { + for (int rowSize : new int[] {1, 2, 3, 4}) + for (int colSize : new int[] {1, 2, 3, 4}) + for (int row = 0; row < rowSize; row++) + for (int col = 0; col < colSize; col++) + for (int rowStride = 0; rowStride < rowSize; rowStride++) + for (int colStride = 0; colStride < colSize; colStride++) + if (rowStride != 0 || colStride != 0) + assertMatrixVectorView(newMatrix(rowSize, colSize), row, col, rowStride, colStride); + } + + /** */ + @Test(expected = AssertionError.class) + public void parentNullTest() { + //noinspection ConstantConditions + assertEquals(IMPOSSIBLE_SIZE, + new MatrixVectorView(null, 1, 1, 1, 1).size()); + } + + /** */ + @Test(expected = IndexException.class) + public void rowNegativeTest() { + //noinspection ConstantConditions + assertEquals(IMPOSSIBLE_SIZE, + new MatrixVectorView(parent, -1, 1, 1, 1).size()); + } + + /** */ + @Test(expected = IndexException.class) + public void colNegativeTest() { + //noinspection ConstantConditions + assertEquals(IMPOSSIBLE_SIZE, + new MatrixVectorView(parent, 1, -1, 1, 1).size()); + } + + /** */ + @Test(expected = IndexException.class) + public void rowTooLargeTest() { + //noinspection ConstantConditions + assertEquals(IMPOSSIBLE_SIZE, + new MatrixVectorView(parent, parent.rowSize() + 1, 1, 1, 1).size()); + } + + /** */ + @Test(expected = IndexException.class) + public void colTooLargeTest() { + //noinspection ConstantConditions + assertEquals(IMPOSSIBLE_SIZE, + new MatrixVectorView(parent, 1, parent.columnSize() + 1, 1, 1).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void rowStrideNegativeTest() { + //noinspection ConstantConditions + assertEquals(IMPOSSIBLE_SIZE, + new MatrixVectorView(parent, 1, 1, -1, 1).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void colStrideNegativeTest() { + //noinspection ConstantConditions + assertEquals(IMPOSSIBLE_SIZE, + new MatrixVectorView(parent, 1, 1, 1, -1).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void rowStrideTooLargeTest() { + //noinspection ConstantConditions + assertEquals(IMPOSSIBLE_SIZE, + new MatrixVectorView(parent, 1, 1, parent.rowSize() + 1, 1).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void colStrideTooLargeTest() { + //noinspection ConstantConditions + assertEquals(IMPOSSIBLE_SIZE, + new MatrixVectorView(parent, 1, 1, 1, parent.columnSize() + 1).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void bothStridesZeroTest() { + //noinspection ConstantConditions + assertEquals(IMPOSSIBLE_SIZE, + new MatrixVectorView(parent, 1, 1, 0, 0).size()); + } + + /** */ + private void assertMatrixVectorView(Matrix parent, int row, int col, int rowStride, int colStride) { + MatrixVectorView view = new MatrixVectorView(parent, row, col, rowStride, colStride); + + String desc = "parent [" + parent.rowSize() + "x" + parent.columnSize() + "], view [" + + row + "x" + col + "], strides [" + rowStride + ", " + colStride + "]"; + + final int size = view.size(); + + final int sizeByRows = rowStride == 0 ? IMPOSSIBLE_SIZE : (parent.rowSize() - row) / rowStride; + final int sizeByCols = colStride == 0 ? IMPOSSIBLE_SIZE : (parent.columnSize() - col) / colStride; + + assertTrue("Size " + size + " differs from expected for " + desc, + size == sizeByRows || size == sizeByCols); + + for (int idx = 0; idx < size; idx++) { + final int rowIdx = row + idx * rowStride; + final int colIdx = col + idx * colStride; + + assertEquals(UNEXPECTED_VALUE + " at view index " + idx + desc, + parent.get(rowIdx, colIdx), view.get(idx), 0d); + } + } + + /** */ + private Matrix newMatrix(int rowSize, int colSize) { + Matrix res = new DenseLocalOnHeapMatrix(rowSize, colSize); + + for (int i = 0; i < res.rowSize(); i++) + for (int j = 0; j < res.columnSize(); j++) + res.set(i, j, i * res.rowSize() + j); + + return res; + } + + /** */ + private void assertView(int row, int col, Vector view, int viewIdx) { + assertValue(row, col, view, viewIdx); + + parent.set(row, col, parent.get(row, col) + 1); + + assertValue(row, col, view, viewIdx); + + view.set(viewIdx, view.get(viewIdx) + 2); + + assertValue(row, col, view, viewIdx); + } + + /** */ + private void assertValue(int row, int col, Vector view, int viewIdx) { + assertEquals(UNEXPECTED_VALUE + " at row " + row + " col " + col, parent.get(row, col), view.get(viewIdx), 0d); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/PivotedVectorViewConstructorTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/PivotedVectorViewConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/PivotedVectorViewConstructorTest.java new file mode 100644 index 0000000..91650dc --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/PivotedVectorViewConstructorTest.java @@ -0,0 +1,211 @@ +/* + * 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.vector; + +import org.apache.ignite.math.Vector; +import org.apache.ignite.math.exceptions.CardinalityException; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +/** */ +public class PivotedVectorViewConstructorTest { + /** */ + private static final int IMPOSSIBLE_SIZE = -1; + + /** */ + private static final SampleParams sampleParams = new SampleParams(); + + /** */ + @Test(expected = NullPointerException.class) + public void nullVecParamTest() { + assertEquals("Expect exception due to null vector param.", IMPOSSIBLE_SIZE, + new PivotedVectorView(null, sampleParams.pivot).size()); + } + + /** */ + @Test(expected = NullPointerException.class) + public void nullVecParam2Test() { + assertEquals("Expect exception due to null vector param, with unpivot.", IMPOSSIBLE_SIZE, + new PivotedVectorView(null, sampleParams.pivot, sampleParams.unpivot).size()); + } + + /** */ + @Test(expected = NullPointerException.class) + public void nullPivotParamTest() { + assertEquals("Expect exception due to null pivot param.", IMPOSSIBLE_SIZE, + new PivotedVectorView(sampleParams.vec, null).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void nullPivotParam2Test() { + assertEquals("Expect exception due to null pivot param, with unpivot.", IMPOSSIBLE_SIZE, + new PivotedVectorView(sampleParams.vec, null, sampleParams.unpivot).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void nullUnpivotParam2Test() { + assertEquals("Expect exception due to null unpivot param.", IMPOSSIBLE_SIZE, + new PivotedVectorView(sampleParams.vec, sampleParams.pivot, null).size()); + } + + /** */ + @Test(expected = CardinalityException.class) + public void emptyPivotTest() { + assertEquals("Expect exception due to empty pivot param.", IMPOSSIBLE_SIZE, + new PivotedVectorView(sampleParams.vec, new int[] {}).size()); + } + + /** */ + @Test(expected = CardinalityException.class) + public void emptyPivot2Test() { + assertEquals("Expect exception due to empty pivot param, with unpivot.", IMPOSSIBLE_SIZE, + new PivotedVectorView(sampleParams.vec, new int[] {}, sampleParams.unpivot).size()); + } + + /** */ + @Test(expected = CardinalityException.class) + public void wrongPivotTest() { + assertEquals("Expect exception due to wrong pivot param.", IMPOSSIBLE_SIZE, + new PivotedVectorView(sampleParams.vec, new int[] {0}).size()); + } + + /** */ + @Test(expected = CardinalityException.class) + public void wrongPivot2Test() { + assertEquals("Expect exception due to wrong pivot param, with unpivot.", IMPOSSIBLE_SIZE, + new PivotedVectorView(sampleParams.vec, new int[] {0}, sampleParams.unpivot).size()); + } + + /** */ + @Test(expected = CardinalityException.class) + public void emptyUnpivotTest() { + assertEquals("Expect exception due to empty unpivot param.", IMPOSSIBLE_SIZE, + new PivotedVectorView(sampleParams.vec, sampleParams.pivot, new int[] {}).size()); + } + + /** */ + @Test(expected = CardinalityException.class) + public void wrongUnpivotTest() { + assertEquals("Expect exception due to wrong unpivot param, with unpivot.", IMPOSSIBLE_SIZE, + new PivotedVectorView(sampleParams.vec, sampleParams.pivot, new int[] {0}).size()); + } + + /** */ + @Test + public void basicPivotTest() { + final PivotedVectorView pvv = new PivotedVectorView(sampleParams.vec, sampleParams.pivot); + + final int size = sampleParams.vec.size(); + + assertEquals("View size differs from expected.", size, pvv.size()); + + assertSame("Base vector differs from expected.", sampleParams.vec, pvv.getBaseVector()); + + for (int idx = 0; idx < size; idx++) { + assertEquals("Sample pivot and unpivot differ from expected", + idx, sampleParams.unpivot[sampleParams.pivot[idx]]); + + assertEquals("Pivot differs from expected at index " + idx, + sampleParams.pivot[idx], pvv.pivot(idx)); + + assertEquals("Default unpivot differs from expected at index " + idx, + sampleParams.unpivot[idx], pvv.unpivot(idx)); + + final Metric metric = new Metric(sampleParams.vec.get(idx), pvv.get(pvv.pivot(idx))); + + assertTrue("Not close enough at index " + idx + ", " + metric, metric.closeEnough()); + } + + for (int idx = 0; idx < size; idx++) { + sampleParams.vec.set(idx, sampleParams.vec.get(idx) + idx + 1); + + final Metric metric = new Metric(sampleParams.vec.get(idx), pvv.get(pvv.pivot(idx))); + + assertTrue("Modified value not close enough at index " + idx + ", " + metric, metric.closeEnough()); + } + } + + /** */ + @Test + public void basicUnpivotTest() { + final PivotedVectorView pvv = new PivotedVectorView(sampleParams.vec, sampleParams.pivot, sampleParams.unpivot); + + final int size = sampleParams.vec.size(); + + assertEquals("View size differs from expected.", size, pvv.size()); + + for (int idx = 0; idx < size; idx++) { + assertEquals("Unpivot differs from expected at index " + idx, + sampleParams.unpivot[idx], pvv.unpivot(idx)); + + final Metric metric = new Metric(sampleParams.vec.get(idx), pvv.get(pvv.unpivot(idx))); + + assertTrue("Not close enough at index " + idx + ", " + metric, metric.closeEnough()); + } + } + + /** */ + private static class SampleParams { + /** */ + final double[] data = new double[] {0, 1}; + /** */ + final Vector vec = new DenseLocalOnHeapVector(data); + /** */ + final int[] pivot = new int[] {1, 0}; + /** */ + final int[] unpivot = new int[] {1, 0}; + } + + /** */ + private static class Metric { // todo consider if softer tolerance (like say 0.1 or 0.01) would make sense here + /** */ + private final double exp; + + /** */ + private final double obtained; + + /** **/ + Metric(double exp, double obtained) { + this.exp = exp; + this.obtained = obtained; + } + + /** */ + boolean closeEnough() { + return new Double(exp).equals(obtained) || closeEnoughToZero(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "Metric{" + "expected=" + exp + + ", obtained=" + obtained + + '}'; + } + + /** */ + private boolean closeEnoughToZero() { + return (new Double(exp).equals(0.0) && new Double(obtained).equals(-0.0)) + || (new Double(exp).equals(-0.0) && new Double(obtained).equals(0.0)); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/RandomVectorConstructorTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/RandomVectorConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/RandomVectorConstructorTest.java new file mode 100644 index 0000000..6d4e4f1 --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/RandomVectorConstructorTest.java @@ -0,0 +1,145 @@ +/* + * 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.vector; + +import java.util.HashMap; +import java.util.Map; +import org.apache.ignite.math.Vector; +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 RandomVectorConstructorTest { + /** */ + private static final int IMPOSSIBLE_SIZE = -1; + + /** */ + @Test(expected = org.apache.ignite.math.exceptions.UnsupportedOperationException.class) + public void mapInvalidArgsTest() { + assertEquals("Expect exception due to invalid args.", IMPOSSIBLE_SIZE, + new RandomVector(new HashMap() {{ + put("invalid", 99); + }}).size()); + } + + /** */ + @Test(expected = UnsupportedOperationException.class) + public void mapMissingArgsTest() { + final Map test = new HashMap() {{ + put("paramMissing", "whatever"); + }}; + + assertEquals("Expect exception due to missing args.", + -1, new RandomVector(test).size()); + } + + /** */ + @Test(expected = ClassCastException.class) + public void mapInvalidParamTypeTest() { + final Map test = new HashMap() {{ + put("size", "whatever"); + put("fastHash", true); + }}; + + assertEquals("Expect exception due to invalid param type.", IMPOSSIBLE_SIZE, + new RandomVector(test).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void mapNullTest() { + //noinspection ConstantConditions + assertEquals("Null map args.", IMPOSSIBLE_SIZE, + new RandomVector(null).size()); + } + + /** */ + @Test + public void mapTest() { + assertEquals("Size from args.", 99, + new RandomVector(new HashMap() {{ + put("size", 99); + }}).size()); + + final int test = 99; + + assertEquals("Size from args with fastHash false.", test, + new RandomVector(new HashMap() {{ + put("size", test); + put("fastHash", false); + }}).size()); + + assertEquals("Size from args with fastHash true.", test, + new RandomVector(new HashMap() {{ + put("size", test); + put("fastHash", true); + }}).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void negativeSizeTest() { + assertEquals("Negative size.", IMPOSSIBLE_SIZE, + new RandomVector(-1).size()); + } + + /** */ + @Test + public void basicTest() { + final int basicSize = 3; + + Vector v1 = new RandomVector(basicSize); + + //noinspection EqualsWithItself + assertTrue("Expect vector to be equal to self", v1.equals(v1)); + + //noinspection ObjectEqualsNull + assertFalse("Expect vector to be not equal to null", v1.equals(null)); + + assertEquals("Size differs from expected", basicSize, v1.size()); + + verifyValues(v1); + + Vector v2 = new RandomVector(basicSize, true); + + assertEquals("Size differs from expected", basicSize, v2.size()); + + verifyValues(v2); + + Vector v3 = new RandomVector(basicSize, false); + + assertEquals("Size differs from expected", basicSize, v3.size()); + + verifyValues(v3); + } + + /** */ + private void verifyValues(Vector v) { + for (Vector.Element e : v.all()) { + double val = e.get(); + + assertTrue("Value too small: " + val + " at index " + e.index(), -1d <= val); + + assertTrue("Value too large: " + val + " at index " + e.index(), val <= 1d); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/SingleElementVectorConstructorTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/SingleElementVectorConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/SingleElementVectorConstructorTest.java new file mode 100644 index 0000000..69e22e0 --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/SingleElementVectorConstructorTest.java @@ -0,0 +1,159 @@ +/* + * 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.vector; + +import java.util.HashMap; +import java.util.Map; +import org.apache.ignite.math.Vector; +import org.apache.ignite.math.exceptions.UnsupportedOperationException; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** */ +public class SingleElementVectorConstructorTest { + /** */ + private static final int IMPOSSIBLE_SIZE = -1; + + /** */ + @Test(expected = UnsupportedOperationException.class) + public void mapInvalidArgsTest() { + assertEquals("Expect exception due to invalid args.", IMPOSSIBLE_SIZE, + new SingleElementVector(new HashMap() {{ + put("invalid", 99); + }}).size()); + } + + /** */ + @Test(expected = UnsupportedOperationException.class) + public void mapMissingArgsTest() { + final Map test = new HashMap() {{ + put("size", 1); + + put("paramMissing", "whatever"); + }}; + + assertEquals("Expect exception due to missing args.", + -1, new SingleElementVector(test).size()); + } + + /** */ + @Test(expected = ClassCastException.class) + public void mapInvalidParamTypeTest() { + final Map test = new HashMap() {{ + put("size", "whatever"); + + put("index", 0); + put("value", 1.0); + }}; + + assertEquals("Expect exception due to invalid param type.", IMPOSSIBLE_SIZE, + new SingleElementVector(test).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void mapNullTest() { + //noinspection ConstantConditions + assertEquals("Null map args.", IMPOSSIBLE_SIZE, + new SingleElementVector(null).size()); + } + + /** */ + @Test + public void mapTest() { + assertEquals("Size from array in args.", 99, + new SingleElementVector(new HashMap() {{ + put("size", 99); + put("index", 0); + put("value", 1.0); + }}).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void negativeSizeTest() { + assertEquals("Negative size.", IMPOSSIBLE_SIZE, + new SingleElementVector(-1, 0, 1.0).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void zeroSizeTest() { + assertEquals("Zero size.", IMPOSSIBLE_SIZE, + new SingleElementVector(0, 0, 1.0).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void wrongIndexTest() { + //noinspection ConstantConditions + assertEquals("Wrong index.", IMPOSSIBLE_SIZE, + new SingleElementVector(1, 2, 1.0).size()); + } + + /** */ + @Test + public void basicTest() { + final int[] sizes = new int[] {1, 4, 8}; + + for (int size : sizes) + for (int idx = 0; idx < size; idx++) + basicTest(size, idx); + } + + /** */ + private void basicTest(int size, int idx) { + final Double expVal = (double)(size - idx); + + Vector v = new SingleElementVector(size, idx, expVal); + + assertTrue("Expect value " + expVal + " at index " + idx + " for size " + size, + expVal.equals(v.get(idx))); + + final double delta = 1.0; + + v.set(idx, expVal - delta); + + assertTrue("Expect value " + expVal + " at index " + idx + " for size " + size, + expVal.equals(v.get(idx) + delta)); + + final Double zero = 0.0; + + for (int i = 0; i < size; i++) { + if (i == idx) + continue; + + assertTrue("Expect zero at index " + i + " for size " + size, + zero.equals(v.get(i))); + + boolean eCaught = false; + + try { + v.set(i, 1.0); + } + catch (UnsupportedOperationException uoe) { + eCaught = true; + } + + assertTrue("Expect " + java.lang.UnsupportedOperationException.class.getSimpleName() + + " at index " + i + " for size " + size, eCaught); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/SingleElementVectorViewConstructorTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/SingleElementVectorViewConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/SingleElementVectorViewConstructorTest.java new file mode 100644 index 0000000..957f3b7 --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/SingleElementVectorViewConstructorTest.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.math.impls.vector; + +import org.apache.ignite.math.Vector; +import org.apache.ignite.math.exceptions.UnsupportedOperationException; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** */ +public class SingleElementVectorViewConstructorTest { + /** */ + private static final int IMPOSSIBLE_SIZE = -1; + + /** */ + private static final SampleHelper helper = new SampleHelper(); + + /** */ + @Test(expected = AssertionError.class) + public void nullVecParamTest() { + assertEquals("Expect exception due to null vector param.", IMPOSSIBLE_SIZE, + new SingleElementVectorView(null, helper.idx).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void negativeIdxParamTest() { + assertEquals("Expect exception due to negative index param.", IMPOSSIBLE_SIZE, + new SingleElementVectorView(helper.vec, -1).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void tooLargeIdxParamTest() { + assertEquals("Expect exception due to too large index param.", IMPOSSIBLE_SIZE, + new SingleElementVectorView(helper.vec, helper.vec.size()).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void emptyVecParamTest() { + assertEquals("Expect exception due to empty vector param.", IMPOSSIBLE_SIZE, + new SingleElementVectorView(helper.vecEmpty, 0).size()); + } + + /** */ + @Test + public void basicTest() { + final int[] sizes = new int[] {1, 4, 8}; + + for (int size : sizes) + for (int idx = 0; idx < size; idx++) + basicTest(size, idx); + } + + /** */ + private void basicTest(int size, int idx) { + final Double expVal = (double)(size - idx); + + Vector orig = helper.newSample(size, idx, expVal); + + SingleElementVectorView svv = new SingleElementVectorView(orig, idx); + + assertEquals("Size differs from expected", size, svv.size()); + + assertTrue("Expect value " + expVal + " at index " + idx + " for size " + size, + expVal.equals(svv.get(idx))); + + final double delta = 1.0; + + svv.set(idx, expVal - delta); + + assertTrue("Expect value " + expVal + " at index " + idx + " for size " + size, + expVal.equals(orig.get(idx) + delta)); + + final Double zero = 0.0; + + for (int i = 0; i < size; i++) { + if (i == idx) + continue; + + assertTrue("Expect zero at index " + i + " for size " + size, + zero.equals(svv.get(i))); + + boolean eCaught = false; + + try { + svv.set(i, 1.0); + } + catch (UnsupportedOperationException uoe) { + eCaught = true; + } + + assertTrue("Expect " + UnsupportedOperationException.class.getSimpleName() + + " at index " + i + " for size " + size, eCaught); + } + } + + /** */ + private static class SampleHelper { + /** */ + final double[] data = new double[] {0, 1}; + /** */ + final Vector vec = new DenseLocalOnHeapVector(data); + /** */ + final Vector vecEmpty = new DenseLocalOnHeapVector(new double[] {}); + /** */ + final int idx = 0; + + /** */ + Vector newSample(int size, int idx, double expVal) { + final Vector v = new DenseLocalOnHeapVector(size); + + for (int i = 0; i < size; i++) + v.set(i, i == idx ? expVal : i); + + return v; + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/SparseLocalVectorConstructorTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/SparseLocalVectorConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/SparseLocalVectorConstructorTest.java new file mode 100644 index 0000000..2be4a10 --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/SparseLocalVectorConstructorTest.java @@ -0,0 +1,54 @@ +/* + * 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.vector; + +import org.apache.ignite.math.StorageConstants; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** */ +public class SparseLocalVectorConstructorTest { + /** */ + private static final int IMPOSSIBLE_SIZE = -1; + + /** */ + @Test(expected = AssertionError.class) + public void negativeSizeTest() { + assertEquals("Negative size.", IMPOSSIBLE_SIZE, + new SparseLocalVector(-1, 1).size()); + } + + /** */ + @Test(expected = AssertionError.class) + public void zeroSizeTest() { + assertEquals("0 size.", IMPOSSIBLE_SIZE, + new SparseLocalVector(0, 1).size()); + } + + /** */ + @Test + public void primitiveTest() { + assertEquals("1 size, random access.", 1, + new SparseLocalVector(1, StorageConstants.RANDOM_ACCESS_MODE).size()); + + assertEquals("1 size, sequential access.", 1, + new SparseLocalVector(1, StorageConstants.SEQUENTIAL_ACCESS_MODE).size()); + + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorAttributesTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorAttributesTest.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorAttributesTest.java new file mode 100644 index 0000000..992018a --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorAttributesTest.java @@ -0,0 +1,217 @@ +/* + * 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.vector; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; +import org.apache.ignite.math.Vector; +import org.apache.ignite.math.impls.matrix.DenseLocalOffHeapMatrix; +import org.apache.ignite.math.impls.matrix.DenseLocalOnHeapMatrix; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** */ +public class VectorAttributesTest { + /** */ + private final List attrCfgs = Arrays.asList( + new AttrCfg("isDense", Vector::isDense, + DenseLocalOnHeapVector.class, DenseLocalOffHeapVector.class, RandomVector.class, ConstantVector.class, + SingleElementVector.class), + new AttrCfg("isArrayBased", Vector::isArrayBased, + DenseLocalOnHeapVector.class), + new AttrCfg("isSequentialAccess", Vector::isSequentialAccess, + DenseLocalOnHeapVector.class, DenseLocalOffHeapVector.class, SparseLocalVectorSequentialAccess.class, + RandomVector.class, ConstantVector.class, SingleElementVector.class), + new AttrCfg("guidNotNull", v -> v.guid() == null), // IMPL NOTE this is somewhat artificial + new AttrCfg("isRandomAccess", Vector::isRandomAccess, + DenseLocalOnHeapVector.class, DenseLocalOffHeapVector.class, RandomVector.class, ConstantVector.class, + SingleElementVector.class, SparseLocalVectorSequentialAccess.class, SparseLocalVectorRandomAccess.class), + new AttrCfg("isDistributed", Vector::isDistributed)); + + /** */ + private final List specFixture = Arrays.asList( + new Specification(new DenseLocalOnHeapVector(1)), + new Specification(new DenseLocalOffHeapVector(1)), + new Specification(new DelegatingVector(new DenseLocalOnHeapVector(1)), + DenseLocalOnHeapVector.class, "isDense", "isArrayBased", "isSequentialAccess", + "isRandomAccess", "isDistributed"), + new Specification(new DelegatingVector(new DenseLocalOffHeapVector(1)), + DenseLocalOffHeapVector.class, "isDense", "isArrayBased", "isSequentialAccess", + "isRandomAccess", "isDistributed"), + new Specification(new SparseLocalVectorSequentialAccess(1)), + new Specification(new SparseLocalVectorRandomAccess(1)), + new Specification(new RandomVector(1)), + new Specification(new ConstantVector(1, 1.0)), + new Specification(new FunctionVector(1, idx -> (double)idx)), + new Specification(new SingleElementVector(1, 0, 1.0)), + new Specification(new PivotedVectorView(new DenseLocalOnHeapVector(1), new int[] {0}), + DenseLocalOnHeapVector.class, "isDense", "isArrayBased", "isSequentialAccess", + "isRandomAccess", "isDistributed"), + new Specification(new PivotedVectorView(new DenseLocalOffHeapVector(1), new int[] {0}), + DenseLocalOffHeapVector.class, "isDense", "isArrayBased", "isSequentialAccess", + "isRandomAccess", "isDistributed"), + new Specification(new SingleElementVectorView(new DenseLocalOnHeapVector(1), 0), + DenseLocalOnHeapVector.class, "isDense", "isSequentialAccess", + "isRandomAccess", "isDistributed"), + new Specification(new SingleElementVectorView(new DenseLocalOffHeapVector(1), 0), + DenseLocalOffHeapVector.class, "isDense", "isSequentialAccess", + "isRandomAccess", "isDistributed"), + new Specification(new MatrixVectorView(new DenseLocalOnHeapMatrix(1, 1), 0, 0, 1, 1), + DenseLocalOnHeapVector.class, "isDense", + "isRandomAccess", "isDistributed"), // todo find out why "isSequentialAccess" fails here + new Specification(new MatrixVectorView(new DenseLocalOffHeapMatrix(1, 1), 0, 0, 1, 1), + DenseLocalOffHeapVector.class, "isDense", + "isRandomAccess", "isDistributed")); + + /** */ + @Test + public void isDenseTest() { + assertAttribute("isDense"); + } + + /** */ + @Test + public void isArrayBasedTest() { + assertAttribute("isArrayBased"); + } + + /** */ + @Test + public void isSequentialAccessTest() { + assertAttribute("isSequentialAccess"); + } + + /** */ + @Test + public void guidTest() { + assertAttribute("guidNotNull"); + } + + /** */ + @Test + public void isRandomAccessTest() { + assertAttribute("isRandomAccess"); + } + + /** */ + @Test + public void isDistributedTest() { + assertAttribute("isDistributed"); + } + + /** */ + private void assertAttribute(String name) { + final AttrCfg attr = attrCfg(name); + + for (Specification spec : specFixture) + spec.verify(attr); + } + + /** */ + private AttrCfg attrCfg(String name) { + for (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 Vector v; + /** */ + private final Class underlyingType; + /** */ + private final List attrsFromUnderlying; + /** */ + final String desc; + + /** */ + Specification(Vector v, Class underlyingType, String... attrsFromUnderlying) { + this.v = v; + this.underlyingType = underlyingType; + this.attrsFromUnderlying = Arrays.asList(attrsFromUnderlying); + final Class clazz = v.getClass(); + desc = clazz.getSimpleName() + (clazz.equals(underlyingType) + ? "" : " (underlying type " + underlyingType.getSimpleName() + ")"); + } + + /** */ + Specification(Vector v) { + this(v, v.getClass()); + } + + /** */ + void verify(AttrCfg attr) { + final boolean obtained = attr.obtain.apply(v); + + final Class typeToCheck + = attrsFromUnderlying.contains(attr.name) ? underlyingType : v.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); + } + } + + /** */ + private static class SparseLocalVectorSequentialAccess extends SparseLocalVector { + /** */ + public SparseLocalVectorSequentialAccess() { + // No-op. + } + + /** */ + SparseLocalVectorSequentialAccess(int size) { + super(size, SEQUENTIAL_ACCESS_MODE); + } + } + + /** */ + private static class SparseLocalVectorRandomAccess extends SparseLocalVector { + /** */ + public SparseLocalVectorRandomAccess() { + // No-op. + } + + /** */ + SparseLocalVectorRandomAccess(int size) { + super(size, RANDOM_ACCESS_MODE); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorFoldMapTest.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorFoldMapTest.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorFoldMapTest.java new file mode 100644 index 0000000..67eb8ba --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorFoldMapTest.java @@ -0,0 +1,122 @@ +/* + * 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.vector; + +import java.util.Arrays; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; +import org.apache.ignite.math.Vector; +import org.apache.ignite.math.functions.Functions; +import org.junit.Test; + +import static java.util.function.DoubleUnaryOperator.identity; +import static org.junit.Assert.assertTrue; + +/** See also: {@link AbstractVectorTest} and {@link VectorToMatrixTest}. */ +public class VectorFoldMapTest { + /** */ + @Test + public void mapVectorTest() { + operationVectorTest((operand1, operand2) -> operand1 + operand2, (Vector v1, Vector v2) -> v1.map(v2, Functions.PLUS)); + } + + /** */ + @Test + public void mapDoubleFunctionTest() { + consumeSampleVectors((v, desc) -> operatorTest(v, desc, + (vec) -> vec.map(Functions.INV), (val) -> 1.0 / val)); + } + + /** */ + @Test + public void mapBiFunctionTest() { + consumeSampleVectors((v, desc) -> operatorTest(v, desc, + (vec) -> vec.map(Functions.PLUS, 1.0), (val) -> 1.0 + val)); + } + + /** */ + @Test + public void foldMapTest() { + toDoubleTest( + ref -> Arrays.stream(ref).map(identity()).sum(), + (v) -> v.foldMap(Functions.PLUS, Functions.IDENTITY, 0.0)); + } + + /** */ + @Test + public void foldMapVectorTest() { + toDoubleTest( + ref -> 2.0 * Arrays.stream(ref).sum(), + (v) -> v.foldMap(v, Functions.PLUS, Functions.PLUS, 0.0)); + + } + + /** */ + private void operatorTest(Vector v, String desc, Function op, Function refOp) { + final int size = v.size(); + final double[] ref = new double[size]; + + VectorImplementationsTest.ElementsChecker checker = new VectorImplementationsTest.ElementsChecker(v, ref, desc); + + Vector actual = op.apply(v); + + for (int idx = 0; idx < size; idx++) + ref[idx] = refOp.apply(ref[idx]); + + checker.assertCloseEnough(actual, ref); + } + + /** */ + private void toDoubleTest(Function calcRef, Function calcVec) { + consumeSampleVectors((v, desc) -> { + final int size = v.size(); + final double[] ref = new double[size]; + + new VectorImplementationsTest.ElementsChecker(v, ref, desc); // IMPL NOTE this initialises vector and reference array + + final VectorImplementationsTest.Metric metric = new VectorImplementationsTest.Metric(calcRef.apply(ref), calcVec.apply(v)); + + assertTrue("Not close enough at " + desc + + ", " + metric, metric.closeEnough()); + }); + } + + /** */ + private void operationVectorTest(BiFunction operation, + BiFunction vecOperation) { + consumeSampleVectors((v, desc) -> { + // TODO find out if more elaborate testing scenario is needed or it's okay as is. + final int size = v.size(); + final double[] ref = new double[size]; + + final VectorImplementationsTest.ElementsChecker checker = new VectorImplementationsTest.ElementsChecker(v, ref, desc); + final Vector operand = v.copy(); + + for (int idx = 0; idx < size; idx++) + ref[idx] = operation.apply(ref[idx], ref[idx]); + + checker.assertCloseEnough(vecOperation.apply(v, operand), ref); + }); + } + + /** */ + private void consumeSampleVectors(BiConsumer consumer) { + new VectorImplementationsFixtures().consumeSampleVectors(null, consumer); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorImplementationsFixtures.java ---------------------------------------------------------------------- diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorImplementationsFixtures.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorImplementationsFixtures.java new file mode 100644 index 0000000..5a46218 --- /dev/null +++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorImplementationsFixtures.java @@ -0,0 +1,655 @@ +/* + * 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.vector; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import org.apache.ignite.math.Matrix; +import org.apache.ignite.math.StorageConstants; +import org.apache.ignite.math.Vector; +import org.apache.ignite.math.impls.matrix.DenseLocalOnHeapMatrix; +import org.apache.ignite.math.impls.storage.vector.FunctionVectorStorage; +import org.jetbrains.annotations.NotNull; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** */ +class VectorImplementationsFixtures { + /** */ + private static final List>> suppliers = Arrays.asList( + (Supplier>)DenseLocalOnHeapVectorFixture::new, + (Supplier>)DenseLocalOffHeapVectorFixture::new, + (Supplier>)SparseLocalVectorFixture::new, + (Supplier>)RandomVectorFixture::new, + (Supplier>)ConstantVectorFixture::new, + (Supplier>)DelegatingVectorFixture::new, + (Supplier>)FunctionVectorFixture::new, + (Supplier>)SingleElementVectorFixture::new, + (Supplier>)PivotedVectorViewFixture::new, + (Supplier>)SingleElementVectorViewFixture::new, + (Supplier>)MatrixVectorViewFixture::new, + (Supplier>)SparseLocalOffHeapVectorFixture::new + ); + + /** */ + void consumeSampleVectors(Consumer paramsConsumer, BiConsumer consumer) { + for (Supplier> fixtureSupplier : VectorImplementationsFixtures.suppliers) { + final Iterable fixture = fixtureSupplier.get(); + + for (Vector v : fixture) { + if (paramsConsumer != null) + paramsConsumer.accept(v.size()); + + consumer.accept(v, fixture.toString()); + } + } + } + + /** */ + void selfTest() { + new VectorSizesExtraIterator<>("VectorSizesExtraIterator test", + (size, shallowCp) -> new DenseLocalOnHeapVector(new double[size], shallowCp), + null, "shallow copy", new Boolean[] {false, true, null}).selfTest(); + + new VectorSizesIterator("VectorSizesIterator test", DenseLocalOffHeapVector::new, null).selfTest(); + } + + /** */ + private static class DenseLocalOnHeapVectorFixture extends VectorSizesExtraFixture { + /** */ + DenseLocalOnHeapVectorFixture() { + super("DenseLocalOnHeapVector", + (size, shallowCp) -> new DenseLocalOnHeapVector(new double[size], shallowCp), + "shallow copy", new Boolean[] {false, true, null}); + } + } + + /** */ + private static class DenseLocalOffHeapVectorFixture extends VectorSizesFixture { + /** */ + DenseLocalOffHeapVectorFixture() { + super("DenseLocalOffHeapVector", DenseLocalOffHeapVector::new); + } + } + + /** */ + private static class SparseLocalVectorFixture extends VectorSizesExtraFixture { + /** */ + SparseLocalVectorFixture() { + super("SparseLocalVector", SparseLocalVector::new, "access mode", + new Integer[] {StorageConstants.SEQUENTIAL_ACCESS_MODE, StorageConstants.RANDOM_ACCESS_MODE, null}); + } + } + + /** */ + private static class RandomVectorFixture extends VectorSizesFixture { + /** */ + RandomVectorFixture() { + super("RandomVector", RandomVector::new); + } + } + + /** */ + private static class ConstantVectorFixture extends VectorSizesExtraFixture { + /** */ + ConstantVectorFixture() { + super("ConstantVector", ConstantVector::new, + "value", new Double[] {-1.0, 0.0, 0.5, 1.0, 2.0, null}); + } + } + + /** */ + private static class FunctionVectorFixture extends VectorSizesExtraFixture { + /** */ + FunctionVectorFixture() { + super("FunctionVector", + (size, scale) -> new FunctionVectorForTest(new double[size], scale), + "scale", new Double[] {0.5, 1.0, 2.0, null}); + } + } + + /** */ + private static class SingleElementVectorFixture implements Iterable { + /** */ + private final Supplier> iter; + + /** */ + private final AtomicReference ctxDescrHolder = new AtomicReference<>("Iterator not started."); + + /** */ + SingleElementVectorFixture() { + iter = () -> new TwoParamsIterator("SingleElementVector", + null, ctxDescrHolder::set, + "size", new Integer[] {1, null}, + "value", new Double[] {-1.0, 0.0, 0.5, 1.0, 2.0, null}) { + + /** {@inheritDoc} */ + @Override BiFunction ctor() { + return (size, value) -> new SingleElementVector(size, 0, value); + } + }; + } + + /** {@inheritDoc} */ + @NotNull + @Override public Iterator iterator() { + return iter.get();//( + } + + /** {@inheritDoc} */ + @Override public String toString() { + // IMPL NOTE index within bounds is expected to be guaranteed by proper code in this class + return ctxDescrHolder.get(); + } + } + + /** */ + private static class PivotedVectorViewFixture extends VectorSizesFixture { + /** */ + PivotedVectorViewFixture() { + super("PivotedVectorView", PivotedVectorViewFixture::pivotedVectorView); + } + + /** */ + private static PivotedVectorView pivotedVectorView(int size) { + final DenseLocalOnHeapVector vec = new DenseLocalOnHeapVector(size); + + final int[] pivot = new int[size]; + + for (int idx = 0; idx < size; idx++) + pivot[idx] = size - 1 - idx; + + PivotedVectorView tmp = new PivotedVectorView(vec, pivot); + + final int[] unpivot = new int[size]; + + for (int idx = 0; idx < size; idx++) + unpivot[idx] = tmp.unpivot(idx); + + final int[] idxRecovery = new int[size]; + + for (int idx = 0; idx < size; idx++) + idxRecovery[idx] = idx; + + return new PivotedVectorView(new PivotedVectorView(tmp, unpivot), idxRecovery); + } + } + + /** */ + private static class SingleElementVectorViewFixture implements Iterable { + /** */ + private final Supplier> iter; + + /** */ + private final AtomicReference ctxDescrHolder = new AtomicReference<>("Iterator not started."); + + /** */ + SingleElementVectorViewFixture() { + iter = () -> new TwoParamsIterator("SingleElementVectorView", + null, ctxDescrHolder::set, + "size", new Integer[] {1, null}, + "value", new Double[] {-1.0, 0.0, 0.5, 1.0, 2.0, null}) { + + /** {@inheritDoc} */ + @Override BiFunction ctor() { + return (size, value) -> new SingleElementVectorView(new SingleElementVector(size, 0, value), 0); + } + }; + } + + /** {@inheritDoc} */ + @NotNull + @Override public Iterator iterator() { + return iter.get(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + // IMPL NOTE index within bounds is expected to be guaranteed by proper code in this class + return ctxDescrHolder.get(); + } + } + + /** */ + private static class MatrixVectorViewFixture extends VectorSizesExtraFixture { + /** */ + MatrixVectorViewFixture() { + super("MatrixVectorView", + MatrixVectorViewFixture::newView, + "stride kind", new Integer[] {0, 1, 2, null}); + } + + /** */ + private static Vector newView(int size, int strideKind) { + final Matrix parent = new DenseLocalOnHeapMatrix(size, size); + + return new MatrixVectorView(parent, 0, 0, strideKind != 1 ? 1 : 0, strideKind != 0 ? 1 : 0); + } + } + + /** */ + private static class VectorSizesExtraFixture implements Iterable { + /** */ + private final Supplier> iter; + + /** */ + private final AtomicReference ctxDescrHolder = new AtomicReference<>("Iterator not started."); + + /** */ + VectorSizesExtraFixture(String vectorKind, BiFunction ctor, String extraParamName, + T[] extras) { + iter = () -> new VectorSizesExtraIterator<>(vectorKind, ctor, ctxDescrHolder::set, extraParamName, extras); + } + + /** {@inheritDoc} */ + @NotNull + @Override public Iterator iterator() { + return iter.get(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + // IMPL NOTE index within bounds is expected to be guaranteed by proper code in this class + return ctxDescrHolder.get(); + } + } + + /** */ + private static abstract class VectorSizesFixture implements Iterable { + /** */ + private final Supplier iter; + + /** */ + private final AtomicReference ctxDescrHolder = new AtomicReference<>("Iterator not started."); + + /** */ + VectorSizesFixture(String vectorKind, Function ctor) { + iter = () -> new VectorSizesIterator(vectorKind, ctor, ctxDescrHolder::set); + } + + /** {@inheritDoc} */ + @NotNull + @Override public Iterator iterator() { + return iter.get(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + // IMPL NOTE index within bounds is expected to be guaranteed by proper code in this class + return ctxDescrHolder.get(); + } + } + + /** */ + private static class VectorSizesExtraIterator extends VectorSizesIterator { + /** */ + private final T[] extras; + /** */ + private int extraIdx = 0; + /** */ + private final BiFunction ctor; + /** */ + private final String extraParamName; + + /** + * @param vectorKind Descriptive name to use for context logging. + * @param ctor Constructor for objects to iterate over. + * @param ctxDescrConsumer Context logging consumer. + * @param extraParamName Name of extra parameter to iterate over. + * @param extras Array of extra parameter values to iterate over. + */ + VectorSizesExtraIterator(String vectorKind, BiFunction ctor, + Consumer ctxDescrConsumer, String extraParamName, T[] extras) { + super(vectorKind, null, ctxDescrConsumer); + + this.ctor = ctor; + this.extraParamName = extraParamName; + this.extras = extras; + } + + /** {@inheritDoc} */ + @Override public boolean hasNext() { + return super.hasNext() && hasNextExtra(extraIdx); + } + + /** {@inheritDoc} */ + @Override void nextIdx() { + assert extras[extraIdx] != null + : "Index(es) out of bound at " + VectorSizesExtraIterator.this; + + if (hasNextExtra(extraIdx + 1)) { + extraIdx++; + + return; + } + + extraIdx = 0; + + super.nextIdx(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + // IMPL NOTE index within bounds is expected to be guaranteed by proper code in this class + return "{" + super.toString() + + ", " + extraParamName + "=" + extras[extraIdx] + + '}'; + } + + /** {@inheritDoc} */ + @Override BiFunction ctor() { + return (size, delta) -> ctor.apply(size + delta, extras[extraIdx]); + } + + /** */ + void selfTest() { + final Set extraIdxs = new HashSet<>(); + + int cnt = 0; + + while (hasNext()) { + assertNotNull("Expect not null vector at " + this, next()); + + if (extras[extraIdx] != null) + extraIdxs.add(extraIdx); + + cnt++; + } + + assertEquals("Extra param tested", extraIdxs.size(), extras.length - 1); + + assertEquals("Combinations tested mismatch.", + 7 * 3 * (extras.length - 1), cnt); + } + + /** */ + private boolean hasNextExtra(int idx) { + return extras[idx] != null; + } + } + + /** */ + private static class VectorSizesIterator extends TwoParamsIterator { + /** */ + private final Function ctor; + + /** */ + VectorSizesIterator(String vectorKind, Function ctor, Consumer ctxDescrConsumer) { + super(vectorKind, null, ctxDescrConsumer, + "size", new Integer[] {2, 4, 8, 16, 32, 64, 128, null}, + "size delta", new Integer[] {-1, 0, 1, null}); + + this.ctor = ctor; + } + + /** {@inheritDoc} */ + @Override BiFunction ctor() { + return (size, delta) -> ctor.apply(size + delta); + } + } + + /** */ + private static class TwoParamsIterator implements Iterator { + /** */ + private final T params1[]; + + /** */ + private final U params2[]; + + /** */ + private final String vectorKind; + + /** */ + private final String param1Name; + + /** */ + private final String param2Name; + + /** */ + private final BiFunction ctor; + + /** */ + private final Consumer ctxDescrConsumer; + + /** */ + private int param1Idx = 0; + + /** */ + private int param2Idx = 0; + + /** */ + TwoParamsIterator(String vectorKind, BiFunction ctor, + Consumer ctxDescrConsumer, String param1Name, T[] params1, String param2Name, U[] params2) { + this.param1Name = param1Name; + this.params1 = params1; + + this.param2Name = param2Name; + this.params2 = params2; + + this.vectorKind = vectorKind; + + this.ctor = ctor; + + this.ctxDescrConsumer = ctxDescrConsumer; + } + + /** {@inheritDoc} */ + @Override public boolean hasNext() { + return hasNextParam1(param1Idx) && hasNextParam2(param2Idx); + } + + /** {@inheritDoc} */ + @Override public Vector next() { + if (!hasNext()) + throw new NoSuchElementException(TwoParamsIterator.this.toString()); + + if (ctxDescrConsumer != null) + ctxDescrConsumer.accept(toString()); + + Vector res = ctor().apply(params1[param1Idx], params2[param2Idx]); + + nextIdx(); + + return res; + } + + /** */ + void selfTest() { + final Set sizeIdxs = new HashSet<>(), deltaIdxs = new HashSet<>(); + + int cnt = 0; + + while (hasNext()) { + assertNotNull("Expect not null vector at " + this, next()); + + if (params1[param1Idx] != null) + sizeIdxs.add(param1Idx); + + if (params2[param2Idx] != null) + deltaIdxs.add(param2Idx); + + cnt++; + } + + assertEquals("Sizes tested mismatch.", sizeIdxs.size(), params1.length - 1); + + assertEquals("Deltas tested", deltaIdxs.size(), params2.length - 1); + + assertEquals("Combinations tested mismatch.", + (params1.length - 1) * (params2.length - 1), cnt); + } + + /** IMPL NOTE override in subclasses if needed */ + void nextIdx() { + assert params1[param1Idx] != null && params2[param2Idx] != null + : "Index(es) out of bound at " + TwoParamsIterator.this; + + if (hasNextParam2(param2Idx + 1)) { + param2Idx++; + + return; + } + + param2Idx = 0; + + param1Idx++; + } + + /** {@inheritDoc} */ + @Override public String toString() { + // IMPL NOTE index within bounds is expected to be guaranteed by proper code in this class + return vectorKind + "{" + param1Name + "=" + params1[param1Idx] + + ", " + param2Name + "=" + params2[param2Idx] + + '}'; + } + + /** IMPL NOTE override in subclasses if needed */ + BiFunction ctor() { + return ctor; + } + + /** */ + private boolean hasNextParam1(int idx) { + return params1[idx] != null; + } + + /** */ + private boolean hasNextParam2(int idx) { + return params2[idx] != null; + } + } + + /** Delegating vector with dense local onheap vector */ + private static class DelegatingVectorFixture implements Iterable { + + /** */ + private final Supplier> iter; + + /** */ + private final AtomicReference ctxDescrHolder = new AtomicReference<>("Iterator not started."); + + /** */ + DelegatingVectorFixture() { + iter = () -> new VectorSizesExtraIterator<>("DelegatingVector with DenseLocalOnHeapVector", + (size, shallowCp) -> new DelegatingVector(new DenseLocalOnHeapVector(new double[size], shallowCp)), + ctxDescrHolder::set, "shallow copy", new Boolean[] {false, true, null}); + } + + /** {@inheritDoc} */ + @NotNull + @Override public Iterator iterator() { + return iter.get(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + // IMPL NOTE index within bounds is expected to be guaranteed by proper code in this class + return ctxDescrHolder.get(); + } + } + + /** Subclass tweaked for serialization */ + private static class FunctionVectorForTest extends FunctionVector { + /** */ + double[] arr; + + /** */ + double scale; + + /** */ + public FunctionVectorForTest() { + // No-op. + } + + /** */ + FunctionVectorForTest(double[] arr, double scale) { + super(arr.length, idx -> arr[idx] * scale, (idx, value) -> arr[idx] = value / scale); + + this.arr = arr; + + this.scale = scale; + } + + /** {@inheritDoc} */ + @Override public void writeExternal(ObjectOutput out) throws IOException { + super.writeExternal(out); + + out.writeObject(arr); + + out.writeDouble(scale); + } + + /** {@inheritDoc} */ + @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + super.readExternal(in); + + arr = (double[])in.readObject(); + + scale = in.readDouble(); + + setStorage(new FunctionVectorStorage(arr.length, idx -> arr[idx] * scale, (idx, value) -> arr[idx] = value / scale)); + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + int res = 1; + + res = res * 37 + Double.hashCode(scale); + res = res * 37 + Integer.hashCode(getStorage().size()); + + return res; + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + + if (o == null || getClass() != o.getClass()) + return false; + + FunctionVectorForTest that = (FunctionVectorForTest)o; + + return new Double(scale).equals(that.scale) + && (arr != null ? Arrays.equals(arr, that.arr) : that.arr == null); + } + } + + /** */ + private static class SparseLocalOffHeapVectorFixture extends VectorSizesFixture { + + /** */ + SparseLocalOffHeapVectorFixture() { + super("SparseLocalOffHeapVector", SparseLocalOffHeapVector::new); + } + } +}