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/18 05:25:42 UTC
[27/54] [abbrv] ignite git commit: IGNITE-5000 Rename Ignite Math
module to Ignite ML module
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorImplementationsTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorImplementationsTest.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorImplementationsTest.java
new file mode 100644
index 0000000..0e61513
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorImplementationsTest.java
@@ -0,0 +1,860 @@
+/*
+ * 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.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.math.ExternalizeTest;
+import org.apache.ignite.math.Vector;
+import org.apache.ignite.math.exceptions.CardinalityException;
+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.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) -> 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));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorIterableTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorIterableTest.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorIterableTest.java
new file mode 100644
index 0000000..7a64c85
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorIterableTest.java
@@ -0,0 +1,376 @@
+/*
+ * 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.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.function.BiConsumer;
+import org.apache.ignite.math.Vector;
+import org.apache.ignite.math.impls.MathTestConstants;
+import org.junit.Test;
+
+import static java.util.Spliterator.ORDERED;
+import static java.util.Spliterator.SIZED;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/** */
+public class VectorIterableTest {
+ /** */
+ @Test
+ public void allTest() {
+ consumeSampleVectors(
+ (v, desc) -> {
+ int expIdx = 0;
+
+ for (Vector.Element e : v.all()) {
+ int actualIdx = e.index();
+
+ assertEquals("Unexpected index for " + desc,
+ expIdx, actualIdx);
+
+ expIdx++;
+ }
+
+ assertEquals("Unexpected amount of elements for " + desc,
+ expIdx, v.size());
+ }
+ );
+ }
+
+ /** */
+ @Test
+ public void allTestBound() {
+ consumeSampleVectors(
+ (v, desc) -> iteratorTestBound(v.all().iterator(), desc)
+ );
+ }
+
+ /** */
+ @Test
+ public void nonZeroesTestBasic() {
+ final int size = 5;
+
+ final double[] nonZeroesOddData = new double[size], nonZeroesEvenData = new double[size];
+
+ for (int idx = 0; idx < size; idx++) {
+ final boolean odd = (idx & 1) == 1;
+
+ nonZeroesOddData[idx] = odd ? 1 : 0;
+
+ nonZeroesEvenData[idx] = odd ? 0 : 1;
+ }
+
+ assertTrue("Arrays failed to initialize.",
+ !isZero(nonZeroesEvenData[0])
+ && isZero(nonZeroesEvenData[1])
+ && isZero(nonZeroesOddData[0])
+ && !isZero(nonZeroesOddData[1]));
+
+ final Vector nonZeroesEvenVec = new DenseLocalOnHeapVector(nonZeroesEvenData),
+ nonZeroesOddVec = new DenseLocalOnHeapVector(nonZeroesOddData);
+
+ assertTrue("Vectors failed to initialize.",
+ !isZero(nonZeroesEvenVec.getElement(0).get())
+ && isZero(nonZeroesEvenVec.getElement(1).get())
+ && isZero(nonZeroesOddVec.getElement(0).get())
+ && !isZero(nonZeroesOddVec.getElement(1).get()));
+
+ assertTrue("Iterator(s) failed to start.",
+ nonZeroesEvenVec.nonZeroes().iterator().next() != null
+ && nonZeroesOddVec.nonZeroes().iterator().next() != null);
+
+ int nonZeroesActual = 0;
+
+ for (Vector.Element e : nonZeroesEvenVec.nonZeroes()) {
+ final int idx = e.index();
+
+ final boolean odd = (idx & 1) == 1;
+
+ final double val = e.get();
+
+ assertTrue("Not an even index " + idx + ", for value " + val, !odd);
+
+ assertTrue("Zero value " + val + " at even index " + idx, !isZero(val));
+
+ nonZeroesActual++;
+ }
+
+ final int nonZeroesOddExp = (size + 1) / 2;
+
+ assertEquals("Unexpected num of iterated odd non-zeroes.", nonZeroesOddExp, nonZeroesActual);
+
+ assertEquals("Unexpected nonZeroElements of odd.", nonZeroesOddExp, nonZeroesEvenVec.nonZeroElements());
+
+ nonZeroesActual = 0;
+
+ for (Vector.Element e : nonZeroesOddVec.nonZeroes()) {
+ final int idx = e.index();
+
+ final boolean odd = (idx & 1) == 1;
+
+ final double val = e.get();
+
+ assertTrue("Not an odd index " + idx + ", for value " + val, odd);
+
+ assertTrue("Zero value " + val + " at even index " + idx, !isZero(val));
+
+ nonZeroesActual++;
+ }
+
+ final int nonZeroesEvenExp = size / 2;
+
+ assertEquals("Unexpected num of iterated even non-zeroes", nonZeroesEvenExp, nonZeroesActual);
+
+ assertEquals("Unexpected nonZeroElements of even", nonZeroesEvenExp, nonZeroesOddVec.nonZeroElements());
+ }
+
+ /** */
+ @Test
+ public void nonZeroesTest() {
+ // todo make RandomVector constructor that accepts a function and use it here
+ // in order to *reliably* test non-zeroes in there
+ consumeSampleVectors(
+ (v, desc) -> consumeSampleVectorsWithZeroes(v, (vec, numZeroes)
+ -> {
+ int numZeroesActual = vec.size();
+
+ for (Vector.Element e : vec.nonZeroes()) {
+ numZeroesActual--;
+
+ assertTrue("Unexpected zero at " + desc + ", index " + e.index(), !isZero(e.get()));
+ }
+
+ assertEquals("Unexpected num zeroes at " + desc, (int)numZeroes, numZeroesActual);
+ }));
+ }
+
+ /** */
+ @Test
+ public void nonZeroesTestBound() {
+ consumeSampleVectors(
+ (v, desc) -> consumeSampleVectorsWithZeroes(v, (vec, numZeroes)
+ -> iteratorTestBound(vec.nonZeroes().iterator(), desc)));
+ }
+
+ /** */
+ @Test
+ public void nonZeroElementsTest() {
+ consumeSampleVectors(
+ (v, desc) -> consumeSampleVectorsWithZeroes(v, (vec, numZeroes)
+ -> assertEquals("Unexpected num zeroes at " + desc,
+ (int)numZeroes, vec.size() - vec.nonZeroElements())));
+ }
+
+ /** */
+ @Test
+ public void allSpliteratorTest() {
+ consumeSampleVectors(
+ (v, desc) -> {
+ final String desc1 = " " + desc;
+
+ Spliterator<Double> spliterator = v.allSpliterator();
+
+ assertNotNull(MathTestConstants.NULL_VAL + desc1, spliterator);
+
+ assertNull(MathTestConstants.NOT_NULL_VAL + desc1, spliterator.trySplit());
+
+ assertTrue(MathTestConstants.UNEXPECTED_VAL + desc1, spliterator.hasCharacteristics(ORDERED | SIZED));
+
+ if (!readOnly(v))
+ fillWithNonZeroes(v);
+
+ spliterator = v.allSpliterator();
+
+ assertNotNull(MathTestConstants.NULL_VAL + desc1, spliterator);
+
+ assertEquals(MathTestConstants.VAL_NOT_EQUALS + desc1, spliterator.estimateSize(), v.size());
+
+ assertEquals(MathTestConstants.VAL_NOT_EQUALS + desc1, spliterator.getExactSizeIfKnown(), v.size());
+
+ assertTrue(MathTestConstants.UNEXPECTED_VAL + desc1, spliterator.hasCharacteristics(ORDERED | SIZED));
+
+ Spliterator<Double> secondHalf = spliterator.trySplit();
+
+ assertNull(MathTestConstants.NOT_NULL_VAL + desc1, secondHalf);
+
+ spliterator.tryAdvance(x -> {
+ });
+ }
+ );
+ }
+
+ /** */
+ @Test
+ public void nonZeroSpliteratorTest() {
+ consumeSampleVectors(
+ (v, desc) -> consumeSampleVectorsWithZeroes(v, (vec, numZeroes)
+ -> {
+ final String desc1 = " Num zeroes " + numZeroes + " " + desc;
+
+ Spliterator<Double> spliterator = vec.nonZeroSpliterator();
+
+ assertNotNull(MathTestConstants.NULL_VAL + desc1, spliterator);
+
+ assertNull(MathTestConstants.NOT_NULL_VAL + desc1, spliterator.trySplit());
+
+ assertTrue(MathTestConstants.UNEXPECTED_VAL + desc1, spliterator.hasCharacteristics(ORDERED | SIZED));
+
+ spliterator = vec.nonZeroSpliterator();
+
+ assertNotNull(MathTestConstants.NULL_VAL + desc1, spliterator);
+
+ assertEquals(MathTestConstants.VAL_NOT_EQUALS + desc1, spliterator.estimateSize(), vec.size() - numZeroes);
+
+ assertEquals(MathTestConstants.VAL_NOT_EQUALS + desc1, spliterator.getExactSizeIfKnown(), vec.size() - numZeroes);
+
+ assertTrue(MathTestConstants.UNEXPECTED_VAL + desc1, spliterator.hasCharacteristics(ORDERED | SIZED));
+
+ Spliterator<Double> secondHalf = spliterator.trySplit();
+
+ assertNull(MathTestConstants.NOT_NULL_VAL + desc1, secondHalf);
+
+ double[] data = new double[vec.size()];
+
+ for (Vector.Element e : vec.all())
+ data[e.index()] = e.get();
+
+ spliterator = vec.nonZeroSpliterator();
+
+ assertNotNull(MathTestConstants.NULL_VAL + desc1, spliterator);
+
+ assertEquals(MathTestConstants.VAL_NOT_EQUALS + desc1, spliterator.estimateSize(),
+ Arrays.stream(data).filter(x -> x != 0d).count());
+
+ assertEquals(MathTestConstants.VAL_NOT_EQUALS + desc1, spliterator.getExactSizeIfKnown(),
+ Arrays.stream(data).filter(x -> x != 0d).count());
+
+ assertTrue(MathTestConstants.UNEXPECTED_VAL + desc1, spliterator.hasCharacteristics(ORDERED | SIZED));
+
+ secondHalf = spliterator.trySplit();
+
+ assertNull(MathTestConstants.NOT_NULL_VAL + desc1, secondHalf);
+
+ if (!spliterator.tryAdvance(x -> {
+ }))
+ fail(MathTestConstants.NO_NEXT_ELEMENT + desc1);
+ }));
+ }
+
+ /** */
+ private void iteratorTestBound(Iterator<Vector.Element> it, String desc) {
+ while (it.hasNext())
+ assertNotNull(it.next());
+
+ boolean expECaught = false;
+
+ try {
+ it.next();
+ }
+ catch (NoSuchElementException e) {
+ expECaught = true;
+ }
+
+ assertTrue("Expected exception missed for " + desc,
+ expECaught);
+ }
+
+ /** */
+ private void consumeSampleVectorsWithZeroes(Vector sample,
+ BiConsumer<Vector, Integer> consumer) {
+ if (readOnly(sample)) {
+ int numZeroes = 0;
+
+ for (Vector.Element e : sample.all())
+ if (isZero(e.get()))
+ numZeroes++;
+
+ consumer.accept(sample, numZeroes);
+
+ return;
+ }
+
+ fillWithNonZeroes(sample);
+
+ consumer.accept(sample, 0);
+
+ final int sampleSize = sample.size();
+
+ if (sampleSize == 0)
+ return;
+
+ for (Vector.Element e : sample.all())
+ e.set(0);
+
+ consumer.accept(sample, sampleSize);
+
+ fillWithNonZeroes(sample);
+
+ for (int testIdx : new int[] {0, sampleSize / 2, sampleSize - 1}) {
+ final Vector.Element e = sample.getElement(testIdx);
+
+ final double backup = e.get();
+
+ e.set(0);
+
+ consumer.accept(sample, 1);
+
+ e.set(backup);
+ }
+
+ if (sampleSize < 3)
+ return;
+
+ sample.getElement(sampleSize / 3).set(0);
+
+ sample.getElement((2 * sampleSize) / 3).set(0);
+
+ consumer.accept(sample, 2);
+ }
+
+ /** */
+ private void fillWithNonZeroes(Vector sample) {
+ int idx = 0;
+
+ for (Vector.Element e : sample.all())
+ e.set(1 + idx++);
+
+ assertEquals("Not all filled with non-zeroes", idx, sample.size());
+ }
+
+ /** */
+ private void consumeSampleVectors(BiConsumer<Vector, String> consumer) {
+ new VectorImplementationsFixtures().consumeSampleVectors(null, consumer);
+ }
+
+ /** */
+ private boolean isZero(double val) {
+ return val == 0.0;
+ }
+
+ /** */
+ private boolean readOnly(Vector v) {
+ return v instanceof RandomVector || v instanceof ConstantVector;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorNormTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorNormTest.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorNormTest.java
new file mode 100644
index 0000000..f1c2928
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorNormTest.java
@@ -0,0 +1,247 @@
+/*
+ * 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.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import org.apache.ignite.math.Vector;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+/** */
+public class VectorNormTest {
+ /** */
+ @Test
+ public void normalizeTest() {
+ normalizeTest(2, (val, len) -> val / len, Vector::normalize);
+ }
+
+ /** */
+ @Test
+ public void normalizePowerTest() {
+ for (double pow : new double[] {0, 0.5, 1, 2, 2.5, Double.POSITIVE_INFINITY})
+ normalizeTest(pow, (val, norm) -> val / norm, (v) -> v.normalize(pow));
+ }
+
+ /** */
+ @Test
+ public void logNormalizeTest() {
+ normalizeTest(2, (val, len) -> Math.log1p(val) / (len * Math.log(2)), Vector::logNormalize);
+ }
+
+ /** */
+ @Test
+ public void logNormalizePowerTest() {
+ for (double pow : new double[] {1.1, 2, 2.5})
+ normalizeTest(pow, (val, norm) -> Math.log1p(val) / (norm * Math.log(pow)), (v) -> v.logNormalize(pow));
+ }
+
+ /** */
+ @Test
+ public void kNormTest() {
+ for (double pow : new double[] {0, 0.5, 1, 2, 2.5, Double.POSITIVE_INFINITY})
+ toDoubleTest(pow, ref -> new Norm(ref, pow).calculate(), v -> v.kNorm(pow));
+ }
+
+ /** */
+ @Test
+ public void getLengthSquaredTest() {
+ toDoubleTest(2.0, ref -> new Norm(ref, 2).sumPowers(), Vector::getLengthSquared);
+ }
+
+ /** */
+ @Test
+ public void getDistanceSquaredTest() {
+ consumeSampleVectors((v, desc) -> {
+ new VectorImplementationsTest.ElementsChecker(v, desc); // IMPL NOTE this initialises vector
+
+ final int size = v.size();
+ final Vector vOnHeap = new DenseLocalOnHeapVector(size);
+ final Vector vOffHeap = new DenseLocalOffHeapVector(size);
+
+ invertValues(v, vOnHeap);
+ invertValues(v, vOffHeap);
+
+ for (int idx = 0; idx < size; idx++) {
+ final double exp = v.get(idx);
+ final int idxMirror = size - 1 - idx;
+
+ assertTrue("On heap vector difference at " + desc + ", idx " + idx,
+ exp - vOnHeap.get(idxMirror) == 0);
+ assertTrue("Off heap vector difference at " + desc + ", idx " + idx,
+ exp - vOffHeap.get(idxMirror) == 0);
+ }
+
+ final double exp = vOnHeap.minus(v).getLengthSquared(); // IMPL NOTE this won't mutate vOnHeap
+ final VectorImplementationsTest.Metric metric = new VectorImplementationsTest.Metric(exp, v.getDistanceSquared(vOnHeap));
+
+ assertTrue("On heap vector not close enough at " + desc + ", " + metric,
+ metric.closeEnough());
+
+ final VectorImplementationsTest.Metric metric1 = new VectorImplementationsTest.Metric(exp, v.getDistanceSquared(vOffHeap));
+
+ assertTrue("Off heap vector not close enough at " + desc + ", " + metric1,
+ metric1.closeEnough());
+ });
+ }
+
+ /** */
+ @Test
+ public void dotTest() {
+ consumeSampleVectors((v, desc) -> {
+ new VectorImplementationsTest.ElementsChecker(v, desc); // IMPL NOTE this initialises vector
+
+ final int size = v.size();
+ final Vector v1 = new DenseLocalOnHeapVector(size);
+
+ invertValues(v, v1);
+
+ final double actual = v.dot(v1);
+
+ double exp = 0;
+
+ for (Vector.Element e : v.all())
+ exp += e.get() * v1.get(e.index());
+
+ final VectorImplementationsTest.Metric metric = new VectorImplementationsTest.Metric(exp, actual);
+
+ assertTrue("Dot product not close enough at " + desc + ", " + metric,
+ metric.closeEnough());
+ });
+ }
+
+ /** */
+ private void invertValues(Vector src, Vector dst) {
+ final int size = src.size();
+
+ for (Vector.Element e : src.all()) {
+ final int idx = size - 1 - e.index();
+ final double val = e.get();
+
+ dst.set(idx, val);
+ }
+ }
+
+ /** */
+ private void toDoubleTest(Double val, 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 double exp = calcRef.apply(ref);
+ final double obtained = calcVec.apply(v);
+ final VectorImplementationsTest.Metric metric = new VectorImplementationsTest.Metric(exp, obtained);
+
+ assertTrue("Not close enough at " + desc
+ + (val == null ? "" : ", value " + val) + ", " + metric, metric.closeEnough());
+ });
+ }
+
+ /** */
+ private void normalizeTest(double pow, BiFunction<Double, Double, Double> operation,
+ Function<Vector, Vector> vecOperation) {
+ consumeSampleVectors((v, desc) -> {
+ final int size = v.size();
+ final double[] ref = new double[size];
+ final boolean nonNegative = pow != (int)pow;
+
+ final VectorImplementationsTest.ElementsChecker checker = new VectorImplementationsTest.ElementsChecker(v, ref, desc + ", pow = " + pow, nonNegative);
+ final double norm = new Norm(ref, pow).calculate();
+
+ for (int idx = 0; idx < size; idx++)
+ ref[idx] = operation.apply(ref[idx], norm);
+
+ checker.assertCloseEnough(vecOperation.apply(v), ref);
+ });
+ }
+
+ /** */
+ private void consumeSampleVectors(BiConsumer<Vector, String> consumer) {
+ new VectorImplementationsFixtures().consumeSampleVectors(null, consumer);
+ }
+
+ /** */
+ private static class Norm {
+ /** */
+ private final double[] arr;
+
+ /** */
+ private final Double pow;
+
+ /** */
+ Norm(double[] arr, double pow) {
+ this.arr = arr;
+ this.pow = pow;
+ }
+
+ /** */
+ double calculate() {
+ if (pow.equals(0.0))
+ return countNonZeroes(); // IMPL NOTE this is beautiful if you think of it
+
+ if (pow.equals(Double.POSITIVE_INFINITY))
+ return maxAbs();
+
+ return Math.pow(sumPowers(), 1 / pow);
+ }
+
+ /** */
+ double sumPowers() {
+ if (pow.equals(0.0))
+ return countNonZeroes();
+
+ double norm = 0;
+
+ for (double val : arr)
+ norm += pow == 1 ? Math.abs(val) : Math.pow(val, pow);
+
+ return norm;
+ }
+
+ /** */
+ private int countNonZeroes() {
+ int cnt = 0;
+
+ final Double zero = 0.0;
+
+ for (double val : arr)
+ if (!zero.equals(val))
+ cnt++;
+
+ return cnt;
+ }
+
+ /** */
+ private double maxAbs() {
+ double res = 0;
+
+ for (double val : arr) {
+ final double abs = Math.abs(val);
+
+ if (abs > res)
+ res = abs;
+ }
+
+ return res;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorToMatrixTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorToMatrixTest.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorToMatrixTest.java
new file mode 100644
index 0000000..adcb2cc
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorToMatrixTest.java
@@ -0,0 +1,291 @@
+package org.apache.ignite.math.impls.vector;
+
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiConsumer;
+import org.apache.ignite.math.Matrix;
+import org.apache.ignite.math.Vector;
+import org.apache.ignite.math.exceptions.UnsupportedOperationException;
+import org.apache.ignite.math.impls.matrix.DenseLocalOffHeapMatrix;
+import org.apache.ignite.math.impls.matrix.DenseLocalOnHeapMatrix;
+import org.apache.ignite.math.impls.matrix.RandomMatrix;
+import org.apache.ignite.math.impls.matrix.SparseLocalOnHeapMatrix;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/** Tests for methods of Vector that involve Matrix. */
+public class VectorToMatrixTest {
+ /** */
+ private static final Map<Class<? extends Vector>, Class<? extends Matrix>> typesMap = typesMap();
+
+ /** */
+ private static final List<Class<? extends Vector>> likeMatrixUnsupported = Arrays.asList(FunctionVector.class,
+ SingleElementVector.class, SingleElementVectorView.class, ConstantVector.class);
+
+ /** */
+ @Test
+ public void testHaveLikeMatrix() throws InstantiationException, IllegalAccessException {
+ for (Class<? extends Vector> key : typesMap.keySet()) {
+ Class<? extends Matrix> val = typesMap.get(key);
+
+ if (val == null && likeMatrixSupported(key))
+ System.out.println("Missing test for implementation of likeMatrix for " + key.getSimpleName());
+ }
+ }
+
+ /** */
+ @Test
+ public void testLikeMatrixUnsupported() throws Exception {
+ consumeSampleVectors((v, desc) -> {
+ if (likeMatrixSupported(v.getClass()))
+ return;
+
+ boolean expECaught = false;
+
+ try {
+ assertNull("Null view instead of exception in " + desc, v.likeMatrix(1, 1));
+ }
+ catch (UnsupportedOperationException uoe) {
+ expECaught = true;
+ }
+
+ assertTrue("Expected exception was not caught in " + desc, expECaught);
+ });
+ }
+
+ /** */
+ @Test
+ public void testLikeMatrix() {
+ consumeSampleVectors((v, desc) -> {
+ if (!availableForTesting(v))
+ return;
+
+ final Matrix matrix = v.likeMatrix(1, 1);
+
+ Class<? extends Vector> key = v.getClass();
+
+ Class<? extends Matrix> expMatrixType = typesMap.get(key);
+
+ assertNotNull("Expect non-null matrix for " + key.getSimpleName() + " in " + desc, matrix);
+
+ Class<? extends Matrix> actualMatrixType = matrix.getClass();
+
+ assertTrue("Expected matrix type " + expMatrixType.getSimpleName()
+ + " should be assignable from actual type " + actualMatrixType.getSimpleName() + " in " + desc,
+ expMatrixType.isAssignableFrom(actualMatrixType));
+
+ for (int rows : new int[] {1, 2})
+ for (int cols : new int[] {1, 2}) {
+ final Matrix actualMatrix = v.likeMatrix(rows, cols);
+
+ String details = "rows " + rows + " cols " + cols;
+
+ assertNotNull("Expect non-null matrix for " + details + " in " + desc,
+ actualMatrix);
+
+ assertEquals("Unexpected number of rows in " + desc, rows, actualMatrix.rowSize());
+
+ assertEquals("Unexpected number of cols in " + desc, cols, actualMatrix.columnSize());
+ }
+ });
+ }
+
+ /** */
+ @Test
+ public void testToMatrix() {
+ consumeSampleVectors((v, desc) -> {
+ if (!availableForTesting(v))
+ return;
+
+ fillWithNonZeroes(v);
+
+ final Matrix matrixRow = v.toMatrix(true);
+
+ final Matrix matrixCol = v.toMatrix(false);
+
+ for (Vector.Element e : v.all())
+ assertToMatrixValue(desc, matrixRow, matrixCol, e.get(), e.index());
+ });
+ }
+
+ /** */
+ @Test
+ public void testToMatrixPlusOne() {
+ consumeSampleVectors((v, desc) -> {
+ if (!availableForTesting(v))
+ return;
+
+ fillWithNonZeroes(v);
+
+ for (double zeroVal : new double[] {-1, 0, 1, 2}) {
+ final Matrix matrixRow = v.toMatrixPlusOne(true, zeroVal);
+
+ final Matrix matrixCol = v.toMatrixPlusOne(false, zeroVal);
+
+ final Metric metricRow0 = new Metric(zeroVal, matrixRow.get(0, 0));
+
+ assertTrue("Not close enough row like " + metricRow0 + " at index 0 in " + desc,
+ metricRow0.closeEnough());
+
+ final Metric metricCol0 = new Metric(zeroVal, matrixCol.get(0, 0));
+
+ assertTrue("Not close enough cols like " + metricCol0 + " at index 0 in " + desc,
+ metricCol0.closeEnough());
+
+ for (Vector.Element e : v.all())
+ assertToMatrixValue(desc, matrixRow, matrixCol, e.get(), e.index() + 1);
+ }
+ });
+ }
+
+ /** */
+ @Test
+ public void testCross() {
+ consumeSampleVectors((v, desc) -> {
+ if (!availableForTesting(v))
+ return;
+
+ fillWithNonZeroes(v);
+
+ for (int delta : new int[] {-1, 0, 1}) {
+ final int size2 = v.size() + delta;
+
+ if (size2 < 1)
+ return;
+
+ final Vector v2 = new DenseLocalOnHeapVector(size2);
+
+ for (Vector.Element e : v2.all())
+ e.set(size2 - e.index());
+
+ assertCross(v, v2, desc);
+ }
+ });
+ }
+
+ /** */
+ private void assertCross(Vector v1, Vector v2, String desc) {
+ assertNotNull(v1);
+ assertNotNull(v2);
+
+ final Matrix res = v1.cross(v2);
+
+ assertNotNull("Cross matrix is expected to be not null in " + desc, res);
+
+ assertEquals("Unexpected number of rows in cross Matrix in " + desc, v1.size(), res.rowSize());
+
+ assertEquals("Unexpected number of cols in cross Matrix in " + desc, v2.size(), res.columnSize());
+
+ for (int row = 0; row < v1.size(); row++)
+ for (int col = 0; col < v2.size(); col++) {
+ final Metric metric = new Metric(v1.get(row) * v2.get(col), res.get(row, col));
+
+ assertTrue("Not close enough cross " + metric + " at row " + row + " at col " + col
+ + " in " + desc, metric.closeEnough());
+ }
+ }
+
+ /** */
+ private void assertToMatrixValue(String desc, Matrix matrixRow, Matrix matrixCol, double exp, int idx) {
+ final Metric metricRow = new Metric(exp, matrixRow.get(0, idx));
+
+ assertTrue("Not close enough row like " + metricRow + " at index " + idx + " in " + desc,
+ metricRow.closeEnough());
+
+ final Metric metricCol = new Metric(exp, matrixCol.get(idx, 0));
+
+ assertTrue("Not close enough cols like " + matrixCol + " at index " + idx + " in " + desc,
+ metricCol.closeEnough());
+ }
+
+ /** */
+ private void fillWithNonZeroes(Vector sample) {
+ if (sample instanceof RandomVector)
+ return;
+
+ for (Vector.Element e : sample.all())
+ e.set(1 + e.index());
+ }
+
+ /** */
+ private boolean availableForTesting(Vector v) {
+ assertNotNull("Error in test: vector is null", v);
+
+ if (!likeMatrixSupported(v.getClass()))
+ return false;
+
+ final boolean availableForTesting = typesMap.get(v.getClass()) != null;
+
+ final Matrix actualLikeMatrix = v.likeMatrix(1, 1);
+
+ assertTrue("Need to enable matrix testing for vector type " + v.getClass().getSimpleName(),
+ availableForTesting || actualLikeMatrix == null);
+
+ return availableForTesting;
+ }
+
+ /** Ignore test for given vector type. */
+ private boolean likeMatrixSupported(Class<? extends Vector> clazz) {
+ for (Class<? extends Vector> ignoredClass : likeMatrixUnsupported)
+ if (ignoredClass.isAssignableFrom(clazz))
+ return false;
+
+ return true;
+ }
+
+ /** */
+ private void consumeSampleVectors(BiConsumer<Vector, String> consumer) {
+ new VectorImplementationsFixtures().consumeSampleVectors(null, consumer);
+ }
+
+ /** */
+ private static Map<Class<? extends Vector>, Class<? extends Matrix>> typesMap() {
+ return new LinkedHashMap<Class<? extends Vector>, Class<? extends Matrix>>() {{
+ put(DenseLocalOnHeapVector.class, DenseLocalOnHeapMatrix.class);
+ put(DenseLocalOffHeapVector.class, DenseLocalOffHeapMatrix.class);
+ put(RandomVector.class, RandomMatrix.class);
+ put(SparseLocalVector.class, SparseLocalOnHeapMatrix.class);
+ put(SingleElementVector.class, null); // todo find out if we need SingleElementMatrix to match, or skip it
+ put(ConstantVector.class, null);
+ put(FunctionVector.class, null);
+ put(PivotedVectorView.class, DenseLocalOnHeapMatrix.class); // IMPL NOTE per fixture
+ put(SingleElementVectorView.class, null);
+ put(MatrixVectorView.class, DenseLocalOnHeapMatrix.class); // IMPL NOTE per fixture
+ put(DelegatingVector.class, DenseLocalOnHeapMatrix.class); // IMPL NOTE per fixture
+ // IMPL NOTE check for presence of all implementations here will be done in testHaveLikeMatrix via Fixture
+ }};
+ }
+
+ /** */
+ 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);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return "Metric{" + "expected=" + exp +
+ ", obtained=" + obtained +
+ '}';
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorViewTest.java
----------------------------------------------------------------------
diff --git a/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorViewTest.java b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorViewTest.java
new file mode 100644
index 0000000..55893d0
--- /dev/null
+++ b/modules/ml/src/test/java/org/apache/ignite/math/impls/vector/VectorViewTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.function.BiConsumer;
+import java.util.stream.IntStream;
+import org.apache.ignite.math.Vector;
+import org.apache.ignite.math.exceptions.UnsupportedOperationException;
+import org.apache.ignite.math.impls.MathTestConstants;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Unit tests for {@link VectorView}.
+ */
+public class VectorViewTest {
+ /** */
+ private static final int OFFSET = 10;
+
+ /** */
+ private static final int VIEW_LENGTH = 80;
+
+ /** */
+ private static final String EXTERNALIZE_TEST_FILE_NAME = "externalizeTest";
+
+ /** */
+ private VectorView testVector;
+
+ /** */
+ private DenseLocalOnHeapVector parentVector;
+
+ /** */
+ private double[] parentData;
+
+ /** */
+ @Before
+ public void setup() {
+ parentVector = new DenseLocalOnHeapVector(MathTestConstants.STORAGE_SIZE);
+
+ IntStream.range(0, MathTestConstants.STORAGE_SIZE).forEach(idx -> parentVector.set(idx, Math.random()));
+
+ parentData = parentVector.getStorage().data().clone();
+
+ testVector = new VectorView(parentVector, OFFSET, VIEW_LENGTH);
+ }
+
+ /** */
+ @AfterClass
+ public static void cleanup() throws IOException {
+ Files.deleteIfExists(Paths.get(EXTERNALIZE_TEST_FILE_NAME));
+ }
+
+ /** */
+ @Test
+ public void testCopy() throws Exception {
+ Vector cp = testVector.copy();
+
+ assertTrue(MathTestConstants.VAL_NOT_EQUALS, cp.equals(testVector));
+ }
+
+ /** */
+ @Test(expected = org.apache.ignite.math.exceptions.UnsupportedOperationException.class)
+ public void testLike() throws Exception {
+ for (int card : new int[] {1, 2, 4, 8, 16, 32, 64, 128})
+ consumeSampleVectors((v, desc) -> {
+ Vector vLike = new VectorView(v, 0, 1).like(card);
+
+ Class<? extends Vector> expType = v.getClass();
+
+ 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("Expected matrix type " + expType.getSimpleName()
+ + " should be assignable from actual type " + actualType.getSimpleName() + " in " + desc,
+ expType.isAssignableFrom(actualType));
+
+ });
+ }
+
+ /** See also {@link VectorToMatrixTest#testLikeMatrix()}. */
+ @Test
+ public void testLikeMatrix() {
+ consumeSampleVectors((v, desc) -> {
+ boolean expECaught = false;
+
+ try {
+ assertNull("Null view instead of exception in " + desc, new VectorView(v, 0, 1).likeMatrix(1, 1));
+ }
+ catch (UnsupportedOperationException uoe) {
+ expECaught = true;
+ }
+
+ assertTrue("Expected exception was not caught in " + desc, expECaught);
+ });
+ }
+
+ /** */
+ @Test
+ public void testWriteReadExternal() throws Exception {
+ assertNotNull("Unexpected null parent data", parentData);
+
+ File f = new File(EXTERNALIZE_TEST_FILE_NAME);
+
+ try {
+ ObjectOutputStream objOutputStream = new ObjectOutputStream(new FileOutputStream(f));
+
+ objOutputStream.writeObject(testVector);
+
+ objOutputStream.close();
+
+ ObjectInputStream objInputStream = new ObjectInputStream(new FileInputStream(f));
+
+ VectorView readVector = (VectorView)objInputStream.readObject();
+
+ objInputStream.close();
+
+ assertTrue(MathTestConstants.VAL_NOT_EQUALS, testVector.equals(readVector));
+ }
+ catch (ClassNotFoundException | IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /** */
+ private void consumeSampleVectors(BiConsumer<Vector, String> consumer) {
+ new VectorImplementationsFixtures().consumeSampleVectors(null, consumer);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/732dfea9/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 9e9d877..b54e407 100644
--- a/pom.xml
+++ b/pom.xml
@@ -935,9 +935,9 @@
</profile>
<profile>
- <id>math</id>
+ <id>ml</id>
<modules>
- <module>modules/math</module>
+ <module>modules/ml</module>
</modules>
</profile>
</profiles>