You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2017/04/19 08:45:51 UTC
[10/50] [abbrv] ignite git commit: IGNITE-5000 Rename Ignite Math
module to Ignite ML module added missed licenses renamed packages fixed wrong
ml profile activation
http://git-wip-us.apache.org/repos/asf/ignite/blob/d78e071a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/RandomVectorConstructorTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/RandomVectorConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/RandomVectorConstructorTest.java
new file mode 100644
index 0000000..49e1a50
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/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.ml.math.impls.vector;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.ignite.ml.math.Vector;
+import org.apache.ignite.ml.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 = UnsupportedOperationException.class)
+ public void mapInvalidArgsTest() {
+ assertEquals("Expect exception due to invalid args.", IMPOSSIBLE_SIZE,
+ new RandomVector(new HashMap<String, Object>() {{
+ put("invalid", 99);
+ }}).size());
+ }
+
+ /** */
+ @Test(expected = UnsupportedOperationException.class)
+ public void mapMissingArgsTest() {
+ final Map<String, Object> test = new HashMap<String, Object>() {{
+ put("paramMissing", "whatever");
+ }};
+
+ assertEquals("Expect exception due to missing args.",
+ -1, new RandomVector(test).size());
+ }
+
+ /** */
+ @Test(expected = ClassCastException.class)
+ public void mapInvalidParamTypeTest() {
+ final Map<String, Object> test = new HashMap<String, Object>() {{
+ 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<String, Object>() {{
+ put("size", 99);
+ }}).size());
+
+ final int test = 99;
+
+ assertEquals("Size from args with fastHash false.", test,
+ new RandomVector(new HashMap<String, Object>() {{
+ put("size", test);
+ put("fastHash", false);
+ }}).size());
+
+ assertEquals("Size from args with fastHash true.", test,
+ new RandomVector(new HashMap<String, Object>() {{
+ 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/d78e071a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/SingleElementVectorConstructorTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/SingleElementVectorConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/SingleElementVectorConstructorTest.java
new file mode 100644
index 0000000..db4d5de
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/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.ml.math.impls.vector;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.ignite.ml.math.Vector;
+import org.apache.ignite.ml.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<String, Object>() {{
+ put("invalid", 99);
+ }}).size());
+ }
+
+ /** */
+ @Test(expected = UnsupportedOperationException.class)
+ public void mapMissingArgsTest() {
+ final Map<String, Object> test = new HashMap<String, Object>() {{
+ 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<String, Object> test = new HashMap<String, Object>() {{
+ 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<String, Object>() {{
+ 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/d78e071a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/SingleElementVectorViewConstructorTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/SingleElementVectorViewConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/SingleElementVectorViewConstructorTest.java
new file mode 100644
index 0000000..a693319
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/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.ml.math.impls.vector;
+
+import org.apache.ignite.ml.math.Vector;
+import org.apache.ignite.ml.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/d78e071a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/SparseLocalVectorConstructorTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/SparseLocalVectorConstructorTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/SparseLocalVectorConstructorTest.java
new file mode 100644
index 0000000..912168e
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/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.ml.math.impls.vector;
+
+import org.apache.ignite.ml.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/d78e071a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/VectorAttributesTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/VectorAttributesTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/VectorAttributesTest.java
new file mode 100644
index 0000000..e2f6a40
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/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.ml.math.impls.vector;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Function;
+import org.apache.ignite.ml.math.Vector;
+import org.apache.ignite.ml.math.impls.matrix.DenseLocalOffHeapMatrix;
+import org.apache.ignite.ml.math.impls.matrix.DenseLocalOnHeapMatrix;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/** */
+public class VectorAttributesTest {
+ /** */
+ private final List<AttrCfg> 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<Specification> 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<? extends Vector> underlyingType;
+ /** */
+ private final List<String> attrsFromUnderlying;
+ /** */
+ final String desc;
+
+ /** */
+ Specification(Vector v, Class<? extends Vector> underlyingType, String... attrsFromUnderlying) {
+ this.v = v;
+ this.underlyingType = underlyingType;
+ this.attrsFromUnderlying = Arrays.asList(attrsFromUnderlying);
+ final Class<? extends Vector> 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<? extends Vector> 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<Vector, Boolean> obtain;
+ /** */
+ final List<Class> trueInTypes;
+
+ /** */
+ AttrCfg(String name, Function<Vector, Boolean> 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/d78e071a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/VectorFoldMapTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/VectorFoldMapTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/VectorFoldMapTest.java
new file mode 100644
index 0000000..676bb17
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/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.ml.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.ml.math.Vector;
+import org.apache.ignite.ml.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<Vector, Vector> op, Function<Double, Double> 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<double[], Double> calcRef, Function<Vector, Double> 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<Double, Double, Double> operation,
+ BiFunction<Vector, Vector, Vector> 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<Vector, String> consumer) {
+ new VectorImplementationsFixtures().consumeSampleVectors(null, consumer);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d78e071a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/VectorImplementationsFixtures.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/VectorImplementationsFixtures.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/VectorImplementationsFixtures.java
new file mode 100644
index 0000000..be3bb22
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/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.ml.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.ml.math.Matrix;
+import org.apache.ignite.ml.math.StorageConstants;
+import org.apache.ignite.ml.math.Vector;
+import org.apache.ignite.ml.math.impls.matrix.DenseLocalOnHeapMatrix;
+import org.apache.ignite.ml.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<Supplier<Iterable<Vector>>> suppliers = Arrays.asList(
+ (Supplier<Iterable<Vector>>)DenseLocalOnHeapVectorFixture::new,
+ (Supplier<Iterable<Vector>>)DenseLocalOffHeapVectorFixture::new,
+ (Supplier<Iterable<Vector>>)SparseLocalVectorFixture::new,
+ (Supplier<Iterable<Vector>>)RandomVectorFixture::new,
+ (Supplier<Iterable<Vector>>)ConstantVectorFixture::new,
+ (Supplier<Iterable<Vector>>)DelegatingVectorFixture::new,
+ (Supplier<Iterable<Vector>>)FunctionVectorFixture::new,
+ (Supplier<Iterable<Vector>>)SingleElementVectorFixture::new,
+ (Supplier<Iterable<Vector>>)PivotedVectorViewFixture::new,
+ (Supplier<Iterable<Vector>>)SingleElementVectorViewFixture::new,
+ (Supplier<Iterable<Vector>>)MatrixVectorViewFixture::new,
+ (Supplier<Iterable<Vector>>)SparseLocalOffHeapVectorFixture::new
+ );
+
+ /** */
+ void consumeSampleVectors(Consumer<Integer> paramsConsumer, BiConsumer<Vector, String> consumer) {
+ for (Supplier<Iterable<Vector>> fixtureSupplier : VectorImplementationsFixtures.suppliers) {
+ final Iterable<Vector> 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<Boolean> {
+ /** */
+ 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<Integer> {
+ /** */
+ 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<Double> {
+ /** */
+ 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<Double> {
+ /** */
+ 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<Vector> {
+ /** */
+ private final Supplier<TwoParamsIterator<Integer, Double>> iter;
+
+ /** */
+ private final AtomicReference<String> ctxDescrHolder = new AtomicReference<>("Iterator not started.");
+
+ /** */
+ SingleElementVectorFixture() {
+ iter = () -> new TwoParamsIterator<Integer, Double>("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<Integer, Double, Vector> ctor() {
+ return (size, value) -> new SingleElementVector(size, 0, value);
+ }
+ };
+ }
+
+ /** {@inheritDoc} */
+ @NotNull
+ @Override public Iterator<Vector> 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<Vector> {
+ /** */
+ private final Supplier<TwoParamsIterator<Integer, Double>> iter;
+
+ /** */
+ private final AtomicReference<String> ctxDescrHolder = new AtomicReference<>("Iterator not started.");
+
+ /** */
+ SingleElementVectorViewFixture() {
+ iter = () -> new TwoParamsIterator<Integer, Double>("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<Integer, Double, Vector> ctor() {
+ return (size, value) -> new SingleElementVectorView(new SingleElementVector(size, 0, value), 0);
+ }
+ };
+ }
+
+ /** {@inheritDoc} */
+ @NotNull
+ @Override public Iterator<Vector> 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<Integer> {
+ /** */
+ 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<T> implements Iterable<Vector> {
+ /** */
+ private final Supplier<VectorSizesExtraIterator<T>> iter;
+
+ /** */
+ private final AtomicReference<String> ctxDescrHolder = new AtomicReference<>("Iterator not started.");
+
+ /** */
+ VectorSizesExtraFixture(String vectorKind, BiFunction<Integer, T, Vector> ctor, String extraParamName,
+ T[] extras) {
+ iter = () -> new VectorSizesExtraIterator<>(vectorKind, ctor, ctxDescrHolder::set, extraParamName, extras);
+ }
+
+ /** {@inheritDoc} */
+ @NotNull
+ @Override public Iterator<Vector> 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<Vector> {
+ /** */
+ private final Supplier<VectorSizesIterator> iter;
+
+ /** */
+ private final AtomicReference<String> ctxDescrHolder = new AtomicReference<>("Iterator not started.");
+
+ /** */
+ VectorSizesFixture(String vectorKind, Function<Integer, Vector> ctor) {
+ iter = () -> new VectorSizesIterator(vectorKind, ctor, ctxDescrHolder::set);
+ }
+
+ /** {@inheritDoc} */
+ @NotNull
+ @Override public Iterator<Vector> 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<T> extends VectorSizesIterator {
+ /** */
+ private final T[] extras;
+ /** */
+ private int extraIdx = 0;
+ /** */
+ private final BiFunction<Integer, T, Vector> 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<Integer, T, Vector> ctor,
+ Consumer<String> 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<Integer, Integer, Vector> ctor() {
+ return (size, delta) -> ctor.apply(size + delta, extras[extraIdx]);
+ }
+
+ /** */
+ void selfTest() {
+ final Set<Integer> 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<Integer, Integer> {
+ /** */
+ private final Function<Integer, Vector> ctor;
+
+ /** */
+ VectorSizesIterator(String vectorKind, Function<Integer, Vector> ctor, Consumer<String> 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<Integer, Integer, Vector> ctor() {
+ return (size, delta) -> ctor.apply(size + delta);
+ }
+ }
+
+ /** */
+ private static class TwoParamsIterator<T, U> implements Iterator<Vector> {
+ /** */
+ private final T params1[];
+
+ /** */
+ private final U params2[];
+
+ /** */
+ private final String vectorKind;
+
+ /** */
+ private final String param1Name;
+
+ /** */
+ private final String param2Name;
+
+ /** */
+ private final BiFunction<T, U, Vector> ctor;
+
+ /** */
+ private final Consumer<String> ctxDescrConsumer;
+
+ /** */
+ private int param1Idx = 0;
+
+ /** */
+ private int param2Idx = 0;
+
+ /** */
+ TwoParamsIterator(String vectorKind, BiFunction<T, U, Vector> ctor,
+ Consumer<String> 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<Integer> 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<T, U, Vector> 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<Vector> {
+
+ /** */
+ private final Supplier<VectorSizesExtraIterator<Boolean>> iter;
+
+ /** */
+ private final AtomicReference<String> 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<Vector> 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);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/d78e071a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/VectorImplementationsTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/VectorImplementationsTest.java b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/VectorImplementationsTest.java
new file mode 100644
index 0000000..48dcc36
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/ml/math/impls/vector/VectorImplementationsTest.java
@@ -0,0 +1,861 @@
+/*
+ * 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.vector;
+
+import java.util.Arrays;
+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 org.apache.ignite.IgniteException;
+import org.apache.ignite.ml.math.ExternalizeTest;
+import org.apache.ignite.ml.math.Vector;
+import org.apache.ignite.ml.math.exceptions.CardinalityException;
+import org.apache.ignite.ml.math.exceptions.UnsupportedOperationException;
+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.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/** See also: {@link AbstractVectorTest} and {@link VectorToMatrixTest}. */
+public class VectorImplementationsTest { // todo split this to smaller cohesive test classes
+ /** */
+ @Test
+ public void vectorImplementationsFixturesTest() {
+ new VectorImplementationsFixtures().selfTest();
+ }
+
+ /** */
+ @Test
+ public void setGetTest() {
+ consumeSampleVectors((v, desc) -> mutateAtIdxTest(v, desc, (vec, idx, val) -> {
+ vec.set(idx, val);
+
+ return val;
+ }));
+ }
+
+ /** */
+ @Test
+ public void setXTest() {
+ consumeSampleVectors((v, desc) -> mutateAtIdxTest(v, desc, (vec, idx, val) -> {
+ vec.setX(idx, val);
+
+ return val;
+ }));
+ }
+
+ /** */
+ @Test
+ public void incrementTest() {
+ consumeSampleVectors((v, desc) -> mutateAtIdxTest(v, desc, (vec, idx, val) -> {
+ double old = vec.get(idx);
+
+ vec.increment(idx, val);
+
+ return old + val;
+ }));
+ }
+
+ /** */
+ @Test
+ public void incrementXTest() {
+ consumeSampleVectors((v, desc) -> mutateAtIdxTest(v, desc, (vec, idx, val) -> {
+ double old = vec.getX(idx);
+
+ vec.incrementX(idx, val);
+
+ return old + val;
+ }));
+ }
+
+ /** */
+ @Test
+ public void operateXOutOfBoundsTest() {
+ consumeSampleVectors((v, desc) -> {
+ if (v instanceof DenseLocalOffHeapVector || v instanceof SparseLocalVector || v instanceof SparseLocalOffHeapVector)
+ return; // todo find out if it's OK to skip by instances here
+
+ boolean expECaught = false;
+
+ try {
+ v.getX(-1);
+ }
+ catch (ArrayIndexOutOfBoundsException | IgniteException e) {
+ expECaught = true;
+ }
+
+ if (!getXOutOfBoundsOK(v))
+ assertTrue("Expect exception at negative index getX in " + desc, expECaught);
+
+ expECaught = false;
+
+ try {
+ v.setX(-1, 0);
+ }
+ catch (ArrayIndexOutOfBoundsException | IgniteException e) {
+ expECaught = true;
+ }
+
+ assertTrue("Expect exception at negative index setX in " + desc, expECaught);
+
+ expECaught = false;
+
+ try {
+ v.incrementX(-1, 1);
+ }
+ catch (ArrayIndexOutOfBoundsException | IgniteException e) {
+ expECaught = true;
+ }
+
+ assertTrue("Expect exception at negative index incrementX in " + desc, expECaught);
+
+ expECaught = false;
+
+ try {
+ v.getX(v.size());
+ }
+ catch (ArrayIndexOutOfBoundsException | IgniteException e) {
+ expECaught = true;
+ }
+
+ if (!getXOutOfBoundsOK(v))
+ assertTrue("Expect exception at too large index getX in " + desc, expECaught);
+
+ expECaught = false;
+
+ try {
+ v.setX(v.size(), 1);
+ }
+ catch (ArrayIndexOutOfBoundsException | IgniteException e) {
+ expECaught = true;
+ }
+
+ assertTrue("Expect exception at too large index setX in " + desc, expECaught);
+
+ expECaught = false;
+
+ try {
+ v.incrementX(v.size(), 1);
+ }
+ catch (ArrayIndexOutOfBoundsException | IgniteException e) {
+ expECaught = true;
+ }
+
+ assertTrue("Expect exception at too large index incrementX in " + desc, expECaught);
+ });
+ }
+
+ /** */
+ @Test
+ public void sizeTest() {
+ final AtomicReference<Integer> expSize = new AtomicReference<>(0);
+
+ consumeSampleVectors(
+ expSize::set,
+ (v, desc) -> Assert.assertEquals("Expected size for " + desc,
+ (int)expSize.get(), v.size())
+ );
+ }
+
+ /** */
+ @Test
+ public void getElementTest() {
+ consumeSampleVectors((v, desc) -> new ElementsChecker(v, desc).assertCloseEnough(v));
+ }
+
+ /** */
+ @Test
+ public void copyTest() {
+ consumeSampleVectors((v, desc) -> new ElementsChecker(v, desc).assertCloseEnough(v.copy()));
+ }
+
+ /** */
+ @Test
+ public void divideTest() {
+ operationTest((val, operand) -> val / operand, Vector::divide);
+ }
+
+ /** */
+ @Test
+ public void likeTest() {
+ for (int card : new int[] {1, 2, 4, 8, 16, 32, 64, 128})
+ consumeSampleVectors((v, desc) -> {
+ Class<? extends Vector> expType = expLikeType(v);
+
+ if (expType == null) {
+ try {
+ v.like(card);
+ }
+ catch (UnsupportedOperationException uoe) {
+ return;
+ }
+
+ fail("Expected exception wasn't caught for " + desc);
+
+ return;
+ }
+
+ Vector vLike = v.like(card);
+
+ assertNotNull("Expect non-null like vector for " + expType.getSimpleName() + " in " + desc, vLike);
+ assertEquals("Expect size equal to cardinality at " + desc, card, vLike.size());
+
+ Class<? extends Vector> actualType = vLike.getClass();
+
+ assertTrue("Actual vector type " + actualType.getSimpleName()
+ + " should be assignable from expected type " + expType.getSimpleName() + " in " + desc,
+ actualType.isAssignableFrom(expType));
+ });
+ }
+
+ /** */
+ @Test
+ public void minusTest() {
+ operationVectorTest((operand1, operand2) -> operand1 - operand2, Vector::minus);
+ }
+
+ /** */
+ @Test
+ public void plusVectorTest() {
+ operationVectorTest((operand1, operand2) -> operand1 + operand2, Vector::plus);
+ }
+
+ /** */
+ @Test
+ public void plusDoubleTest() {
+ operationTest((val, operand) -> val + operand, Vector::plus);
+ }
+
+ /** */
+ @Test
+ public void timesVectorTest() {
+ operationVectorTest((operand1, operand2) -> operand1 * operand2, Vector::times);
+ }
+
+ /** */
+ @Test
+ public void timesDoubleTest() {
+ operationTest((val, operand) -> val * operand, Vector::times);
+ }
+
+ /** */
+ @Test
+ public void viewPartTest() {
+ consumeSampleVectors((v, desc) -> {
+ final int size = v.size();
+ final double[] ref = new double[size];
+ final int delta = size > 32 ? 3 : 1; // IMPL NOTE this is for faster test execution
+
+ final ElementsChecker checker = new ElementsChecker(v, ref, desc);
+
+ for (int off = 0; off < size; off += delta)
+ for (int len = 1; len < size - off; len += delta)
+ checker.assertCloseEnough(v.viewPart(off, len), Arrays.copyOfRange(ref, off, off + len));
+ });
+ }
+
+ /** */
+ @Test
+ public void sumTest() {
+ toDoubleTest(
+ ref -> Arrays.stream(ref).sum(),
+ Vector::sum);
+ }
+
+ /** */
+ @Test
+ public void minValueTest() {
+ toDoubleTest(
+ ref -> Arrays.stream(ref).min().getAsDouble(),
+ Vector::minValue);
+ }
+
+ /** */
+ @Test
+ public void maxValueTest() {
+ toDoubleTest(
+ ref -> Arrays.stream(ref).max().getAsDouble(),
+ Vector::maxValue);
+ }
+
+ /** */
+ @Test
+ public void sortTest() {
+ consumeSampleVectors((v, desc) -> {
+ if (readOnly(v) || !v.isArrayBased()) {
+ boolean expECaught = false;
+
+ try {
+ v.sort();
+ }
+ catch (UnsupportedOperationException uoe) {
+ expECaught = true;
+ }
+
+ assertTrue("Expected exception was not caught for sort in " + desc, expECaught);
+
+ return;
+ }
+
+ final int size = v.size();
+ final double[] ref = new double[size];
+
+ new ElementsChecker(v, ref, desc).assertCloseEnough(v.sort(), Arrays.stream(ref).sorted().toArray());
+ });
+ }
+
+ /** */
+ @Test
+ public void metaAttributesTest() {
+ consumeSampleVectors((v, desc) -> {
+ assertNotNull("Null meta storage in " + desc, v.getMetaStorage());
+
+ final String key = "test key";
+ final String val = "test value";
+ final String details = "key [" + key + "] for " + desc;
+
+ v.setAttribute(key, val);
+ assertTrue("Expect to have meta attribute for " + details, v.hasAttribute(key));
+ assertEquals("Unexpected meta attribute value for " + details, val, v.getAttribute(key));
+
+ v.removeAttribute(key);
+ assertFalse("Expect not to have meta attribute for " + details, v.hasAttribute(key));
+ assertNull("Unexpected meta attribute value for " + details, v.getAttribute(key));
+ });
+ }
+
+ /** */
+ @Test
+ public void assignDoubleTest() {
+ consumeSampleVectors((v, desc) -> {
+ if (readOnly(v))
+ return;
+
+ for (double val : new double[] {0, -1, 0, 1}) {
+ v.assign(val);
+
+ for (int idx = 0; idx < v.size(); idx++) {
+ final Metric metric = new Metric(val, v.get(idx));
+
+ assertTrue("Not close enough at index " + idx + ", val " + val + ", " + metric
+ + ", " + desc, metric.closeEnough());
+ }
+ }
+ });
+ }
+
+ /** */
+ @Test
+ public void assignDoubleArrTest() {
+ consumeSampleVectors((v, desc) -> {
+ if (readOnly(v))
+ return;
+
+ final int size = v.size();
+ final double[] ref = new double[size];
+
+ final ElementsChecker checker = new ElementsChecker(v, ref, desc);
+
+ for (int idx = 0; idx < size; idx++)
+ ref[idx] = -ref[idx];
+
+ v.assign(ref);
+
+ checker.assertCloseEnough(v, ref);
+
+ assignDoubleArrWrongCardinality(v, desc);
+ });
+ }
+
+ /** */
+ @Test
+ public void assignVectorTest() {
+ consumeSampleVectors((v, desc) -> {
+ if (readOnly(v))
+ return;
+
+ final int size = v.size();
+ final double[] ref = new double[size];
+
+ final ElementsChecker checker = new ElementsChecker(v, ref, desc);
+
+ for (int idx = 0; idx < size; idx++)
+ ref[idx] = -ref[idx];
+
+ v.assign(new DenseLocalOnHeapVector(ref));
+
+ checker.assertCloseEnough(v, ref);
+
+ assignVectorWrongCardinality(v, desc);
+ });
+ }
+
+ /** */
+ @Test
+ public void assignFunctionTest() {
+ consumeSampleVectors((v, desc) -> {
+ if (readOnly(v))
+ return;
+
+ final int size = v.size();
+ final double[] ref = new double[size];
+
+ final ElementsChecker checker = new ElementsChecker(v, ref, desc);
+
+ for (int idx = 0; idx < size; idx++)
+ ref[idx] = -ref[idx];
+
+ v.assign((idx) -> ref[idx]);
+
+ checker.assertCloseEnough(v, ref);
+ });
+ }
+
+ /** */
+ @Test
+ public void minElementTest() {
+ consumeSampleVectors((v, desc) -> {
+ final ElementsChecker checker = new ElementsChecker(v, desc);
+
+ final Vector.Element minE = v.minElement();
+
+ final int minEIdx = minE.index();
+
+ assertTrue("Unexpected index from minElement " + minEIdx + ", " + desc,
+ minEIdx >= 0 && minEIdx < v.size());
+
+ final Metric metric = new Metric(minE.get(), v.minValue());
+
+ assertTrue("Not close enough minElement at index " + minEIdx + ", " + metric
+ + ", " + desc, metric.closeEnough());
+
+ checker.assertNewMinElement(v);
+ });
+ }
+
+ /** */
+ @Test
+ public void maxElementTest() {
+ consumeSampleVectors((v, desc) -> {
+ final ElementsChecker checker = new ElementsChecker(v, desc);
+
+ final Vector.Element maxE = v.maxElement();
+
+ final int minEIdx = maxE.index();
+
+ assertTrue("Unexpected index from minElement " + minEIdx + ", " + desc,
+ minEIdx >= 0 && minEIdx < v.size());
+
+ final Metric metric = new Metric(maxE.get(), v.maxValue());
+
+ assertTrue("Not close enough maxElement at index " + minEIdx + ", " + metric
+ + ", " + desc, metric.closeEnough());
+
+ checker.assertNewMaxElement(v);
+ });
+ }
+
+ /** */
+ @Test
+ public void externalizeTest() {
+ (new ExternalizeTest<Vector>() {
+ /** {@inheritDoc} */
+ @Override public void externalizeTest() {
+ consumeSampleVectors((v, desc) -> {
+ if (v instanceof SparseLocalOffHeapVector)
+ return; //TODO: wait till SparseLocalOffHeapVector externalization support.
+
+ externalizeTest(v);
+ });
+ }
+ }).externalizeTest();
+ }
+
+ /** */
+ @Test
+ public void hashCodeTest() {
+ consumeSampleVectors((v, desc) -> assertTrue("Zero hash code for " + desc, v.hashCode() != 0));
+ }
+
+ /** */
+ private boolean getXOutOfBoundsOK(Vector v) {
+ // todo find out if this is indeed OK
+ return v instanceof RandomVector || v instanceof ConstantVector
+ || v instanceof SingleElementVector || v instanceof SingleElementVectorView;
+ }
+
+ /** */
+ private void mutateAtIdxTest(Vector v, String desc, MutateAtIdx operation) {
+ if (readOnly(v)) {
+ if (v.size() < 1)
+ return;
+
+ boolean expECaught = false;
+
+ try {
+ operation.apply(v, 0, 1);
+ }
+ catch (UnsupportedOperationException uoe) {
+ expECaught = true;
+ }
+
+ assertTrue("Expect exception at attempt to mutate element in " + desc, expECaught);
+
+ return;
+ }
+
+ for (double val : new double[] {0, -1, 0, 1})
+ for (int idx = 0; idx < v.size(); idx++) {
+ double exp = operation.apply(v, idx, val);
+
+ final Metric metric = new Metric(exp, v.get(idx));
+
+ assertTrue("Not close enough at index " + idx + ", val " + val + ", " + metric
+ + ", " + desc, metric.closeEnough());
+ }
+ }
+
+ /** */
+ private Class<? extends Vector> expLikeType(Vector v) {
+ Class<? extends Vector> clazz = v.getClass();
+
+ if (clazz.isAssignableFrom(PivotedVectorView.class) || clazz.isAssignableFrom(SingleElementVectorView.class))
+ return null;
+
+ if (clazz.isAssignableFrom(MatrixVectorView.class) || clazz.isAssignableFrom(DelegatingVector.class))
+ return DenseLocalOnHeapVector.class; // IMPL NOTE per fixture
+
+ return clazz;
+ }
+
+ /** */
+ private void toDoubleTest(Function<double[], Double> calcRef, Function<Vector, Double> calcVec) {
+ consumeSampleVectors((v, desc) -> {
+ final int size = v.size();
+ final double[] ref = new double[size];
+
+ new ElementsChecker(v, ref, desc); // IMPL NOTE this initialises vector and reference array
+
+ final Metric metric = new Metric(calcRef.apply(ref), calcVec.apply(v));
+
+ assertTrue("Not close enough at " + desc
+ + ", " + metric, metric.closeEnough());
+ });
+ }
+
+ /** */
+ private void operationVectorTest(BiFunction<Double, Double, Double> operation,
+ BiFunction<Vector, Vector, Vector> 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 ElementsChecker checker = new 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);
+
+ assertWrongCardinality(v, desc, vecOperation);
+ });
+ }
+
+ /** */
+ private void assignDoubleArrWrongCardinality(Vector v, String desc) {
+ boolean expECaught = false;
+
+ try {
+ v.assign(new double[v.size() + 1]);
+ }
+ catch (CardinalityException ce) {
+ expECaught = true;
+ }
+
+ assertTrue("Expect exception at too large size in " + desc, expECaught);
+
+ if (v.size() < 2)
+ return;
+
+ expECaught = false;
+
+ try {
+ v.assign(new double[v.size() - 1]);
+ }
+ catch (CardinalityException ce) {
+ expECaught = true;
+ }
+
+ assertTrue("Expect exception at too small size in " + desc, expECaught);
+ }
+
+ /** */
+ private void assignVectorWrongCardinality(Vector v, String desc) {
+ boolean expECaught = false;
+
+ try {
+ v.assign(new DenseLocalOnHeapVector(v.size() + 1));
+ }
+ catch (CardinalityException ce) {
+ expECaught = true;
+ }
+
+ assertTrue("Expect exception at too large size in " + desc, expECaught);
+
+ if (v.size() < 2)
+ return;
+
+ expECaught = false;
+
+ try {
+ v.assign(new DenseLocalOnHeapVector(v.size() - 1));
+ }
+ catch (CardinalityException ce) {
+ expECaught = true;
+ }
+
+ assertTrue("Expect exception at too small size in " + desc, expECaught);
+ }
+
+ /** */
+ private void assertWrongCardinality(
+ Vector v, String desc, BiFunction<Vector, Vector, Vector> vecOperation) {
+ boolean expECaught = false;
+
+ try {
+ vecOperation.apply(v, new DenseLocalOnHeapVector(v.size() + 1));
+ }
+ catch (CardinalityException ce) {
+ expECaught = true;
+ }
+
+ assertTrue("Expect exception at too large size in " + desc, expECaught);
+
+ if (v.size() < 2)
+ return;
+
+ expECaught = false;
+
+ try {
+ vecOperation.apply(v, new DenseLocalOnHeapVector(v.size() - 1));
+ }
+ catch (CardinalityException ce) {
+ expECaught = true;
+ }
+
+ assertTrue("Expect exception at too small size in " + desc, expECaught);
+ }
+
+ /** */
+ private void operationTest(BiFunction<Double, Double, Double> operation,
+ BiFunction<Vector, Double, Vector> vecOperation) {
+ for (double val : new double[] {0, 0.1, 1, 2, 10})
+ consumeSampleVectors((v, desc) -> {
+ final int size = v.size();
+ final double[] ref = new double[size];
+
+ final ElementsChecker checker = new ElementsChecker(v, ref, "val " + val + ", " + desc);
+
+ for (int idx = 0; idx < size; idx++)
+ ref[idx] = operation.apply(ref[idx], val);
+
+ checker.assertCloseEnough(vecOperation.apply(v, val), ref);
+ });
+ }
+
+ /** */
+ private void consumeSampleVectors(BiConsumer<Vector, String> consumer) {
+ consumeSampleVectors(null, consumer);
+ }
+
+ /** */
+ private void consumeSampleVectors(Consumer<Integer> paramsConsumer, BiConsumer<Vector, String> consumer) {
+ new VectorImplementationsFixtures().consumeSampleVectors(paramsConsumer, consumer);
+ }
+
+ /** */
+ private static boolean readOnly(Vector v) {
+ return v instanceof RandomVector || v instanceof ConstantVector;
+ }
+
+ /** */
+ private interface MutateAtIdx {
+ /** */
+ double apply(Vector v, int idx, double val);
+ }
+
+ /** */
+ static class ElementsChecker {
+ /** */
+ private final String fixtureDesc;
+
+ /** */
+ private final double[] refReadOnly;
+
+ /** */
+ private final boolean nonNegative;
+
+ /** */
+ ElementsChecker(Vector v, double[] ref, String fixtureDesc, boolean nonNegative) {
+ this.fixtureDesc = fixtureDesc;
+
+ this.nonNegative = nonNegative;
+
+ refReadOnly = readOnly(v) && ref == null ? new double[v.size()] : null;
+
+ init(v, ref);
+ }
+
+ /** */
+ ElementsChecker(Vector v, double[] ref, String fixtureDesc) {
+ this(v, ref, fixtureDesc, false);
+ }
+
+ /** */
+ ElementsChecker(Vector v, String fixtureDesc) {
+ this(v, null, fixtureDesc);
+ }
+
+ /** */
+ void assertCloseEnough(Vector obtained, double[] exp) {
+ final int size = obtained.size();
+
+ for (int i = 0; i < size; i++) {
+ final Vector.Element e = obtained.getElement(i);
+
+ if (refReadOnly != null && exp == null)
+ exp = refReadOnly;
+
+ final Metric metric = new Metric(exp == null ? generated(i) : exp[i], e.get());
+
+ assertEquals("Unexpected vector index at " + fixtureDesc, i, e.index());
+ assertTrue("Not close enough at index " + i + ", size " + size + ", " + metric
+ + ", " + fixtureDesc, metric.closeEnough());
+ }
+ }
+
+ /** */
+ void assertCloseEnough(Vector obtained) {
+ assertCloseEnough(obtained, null);
+ }
+
+ /** */
+ void assertNewMinElement(Vector v) {
+ if (readOnly(v))
+ return;
+
+ int exp = v.size() / 2;
+
+ v.set(exp, -(v.size() * 2 + 1));
+
+ assertEquals("Unexpected minElement index at " + fixtureDesc, exp, v.minElement().index());
+ }
+
+ /** */
+ void assertNewMaxElement(Vector v) {
+ if (readOnly(v))
+ return;
+
+ int exp = v.size() / 2;
+
+ v.set(exp, v.size() * 2 + 1);
+
+ assertEquals("Unexpected minElement index at " + fixtureDesc, exp, v.maxElement().index());
+ }
+
+ /** */
+ private void init(Vector v, double[] ref) {
+ if (readOnly(v)) {
+ initReadonly(v, ref);
+
+ return;
+ }
+
+ for (Vector.Element e : v.all()) {
+ int idx = e.index();
+
+ // IMPL NOTE introduce negative values because their absence
+ // blocked catching an ugly bug in AbstractVector#kNorm
+ int val = generated(idx);
+
+ e.set(val);
+
+ if (ref != null)
+ ref[idx] = val;
+ }
+ }
+
+ /** */
+ private void initReadonly(Vector v, double[] ref) {
+ if (refReadOnly != null)
+ for (Vector.Element e : v.all())
+ refReadOnly[e.index()] = e.get();
+
+ if (ref != null)
+ for (Vector.Element e : v.all())
+ ref[e.index()] = e.get();
+ }
+
+ /** */
+ private int generated(int idx) {
+ return nonNegative || (idx & 1) == 0 ? idx : -idx;
+ }
+ }
+
+ /** */
+ 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));
+ }
+ }
+}