aboutsummaryrefslogtreecommitdiffstats
path: root/vespajlib
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2016-12-19 22:27:31 +0100
committerGitHub <noreply@github.com>2016-12-19 22:27:31 +0100
commit645c7845a4669e53b9db5b751020bc78d05a41df (patch)
treeab5d5b5c2ea20098bc2da7395b5e4e9435627c67 /vespajlib
parent5ae90e211201d72111e92a6df45d3d0602e8b11a (diff)
Revert "Bratseth/tensor subiterators"
Diffstat (limited to 'vespajlib')
-rw-r--r--vespajlib/src/main/java/com/yahoo/tensor/IndexedTensor.java308
-rw-r--r--vespajlib/src/main/java/com/yahoo/tensor/MappedTensor.java2
-rw-r--r--vespajlib/src/main/java/com/yahoo/tensor/Tensor.java23
-rw-r--r--vespajlib/src/main/java/com/yahoo/tensor/TensorAddress.java129
-rw-r--r--vespajlib/src/main/java/com/yahoo/tensor/TensorType.java5
-rw-r--r--vespajlib/src/main/java/com/yahoo/tensor/functions/Join.java83
-rw-r--r--vespajlib/src/main/java/com/yahoo/tensor/functions/Reduce.java10
-rw-r--r--vespajlib/src/main/java/com/yahoo/tensor/functions/Rename.java4
-rw-r--r--vespajlib/src/main/java/com/yahoo/tensor/serialization/SparseBinaryFormat.java5
-rw-r--r--vespajlib/src/test/java/com/yahoo/tensor/IndexedTensorTestCase.java12
-rw-r--r--vespajlib/src/test/java/com/yahoo/tensor/JoinTestCase.java36
-rw-r--r--vespajlib/src/test/java/com/yahoo/tensor/TensorFunctionBenchmark.java45
-rw-r--r--vespajlib/src/test/java/com/yahoo/tensor/TensorTestCase.java28
13 files changed, 156 insertions, 534 deletions
diff --git a/vespajlib/src/main/java/com/yahoo/tensor/IndexedTensor.java b/vespajlib/src/main/java/com/yahoo/tensor/IndexedTensor.java
index 1ebd6c4179d..4091fd97a16 100644
--- a/vespajlib/src/main/java/com/yahoo/tensor/IndexedTensor.java
+++ b/vespajlib/src/main/java/com/yahoo/tensor/IndexedTensor.java
@@ -12,7 +12,6 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
-import java.util.Set;
/**
* An indexed (dense) tensor backed by a double array.
@@ -61,20 +60,6 @@ public class IndexedTensor implements Tensor {
return new ValueIterator();
}
- /**
- * Returns an iterator over value iterators where the outer iterator is over each unique value of the dimensions
- * given and the inner iterator is over each unique value of the rest of the dimensions, in the same order as
- * other iterator.
- *
- * @param dimensions the names of the dimensions of the superspace
- * @param dimensionSizes the size of each dimension in the space we are returning values for, containing
- * one value per dimension of this tensor (in order). Each size may be the same or smaller
- * than the corresponding size of this tensor
- */
- public Iterator<SubspaceIterator> subspaceIterator(Set<String> dimensions, int[] dimensionSizes) {
- return new SuperspaceIterator(dimensions, dimensionSizes);
- }
-
/**
* Returns the value at the given indexes
*
@@ -97,12 +82,7 @@ public class IndexedTensor implements Tensor {
return Double.NaN;
}
}
-
- /** Returns the value at these indexes */
- private double get(Indexes indexes) {
- return values[toValueIndex(indexes.indexesForReading(), dimensionSizes)];
- }
-
+
private static int toValueIndex(int[] indexes, int[] dimensionSizes) {
if (indexes.length == 1) return indexes[0]; // for speed
if (indexes.length == 0) return 0; // for speed
@@ -112,13 +92,13 @@ public class IndexedTensor implements Tensor {
valueIndex += productOfDimensionsAfter(i, dimensionSizes) * indexes[i];
return valueIndex;
}
-
+
private static int toValueIndex(TensorAddress address, int[] dimensionSizes) {
- if (address.isEmpty()) return 0;
+ if (address.labels().isEmpty()) return 0;
int valueIndex = 0;
- for (int i = 0; i < address.size(); i++)
- valueIndex += productOfDimensionsAfter(i, dimensionSizes) * address.intLabel(i);
+ for (int i = 0; i < address.labels().size(); i++)
+ valueIndex += productOfDimensionsAfter(i, dimensionSizes) * Integer.parseInt(address.labels().get(i));
return valueIndex;
}
@@ -133,11 +113,11 @@ public class IndexedTensor implements Tensor {
public TensorType type() { return type; }
/**
- * Returns the length of this in the nth dimension
+ * Returns the lenght of this in the nth dimension
*
* @throws IndexOutOfBoundsException if the index is larger than the number of dimensions in this tensor minus one
*/
- public int size(int dimension) {
+ public int length(int dimension) {
return dimensionSizes[dimension];
}
@@ -147,15 +127,30 @@ public class IndexedTensor implements Tensor {
return values.length == 0 ? Collections.emptyMap() : Collections.singletonMap(TensorAddress.empty, values[0]);
ImmutableMap.Builder<TensorAddress, Double> builder = new ImmutableMap.Builder<>();
- Indexes indexes = new Indexes(dimensionSizes, values.length);
+ int[] tensorIndexes = new int[dimensionSizes.length];
for (int i = 0; i < values.length; i++) {
- builder.put(indexes.toAddress(), values[i]);
+ builder.put(new TensorAddress(tensorIndexes), values[i]);
if (i < values.length -1)
- indexes.next();
+ next(tensorIndexes);
}
return builder.build();
}
+ private void next(int[] tensorIndexes) {
+ nextRecursively(tensorIndexes.length - 1, tensorIndexes);
+ }
+
+ // TODO: Tail recursion -> loop
+ private void nextRecursively(int dimension, int[] tensorIndexes) {
+ if (tensorIndexes[dimension] + 1 == dimensionSizes[dimension]) {
+ tensorIndexes[dimension] = 0;
+ nextRecursively(dimension - 1, tensorIndexes);
+ }
+ else {
+ tensorIndexes[dimension]++;
+ }
+ }
+
@Override
public int hashCode() { return Arrays.hashCode(values); }
@@ -195,9 +190,9 @@ public class IndexedTensor implements Tensor {
" for " + type);
for (int i = 0; i < dimensionSizes.length; i++ ) {
Optional<Integer> size = type.dimensions().get(i).size();
- if (size.isPresent() && size.get() < dimensionSizes[i])
- throw new IllegalArgumentException("Size of " + type.dimensions() + " is " + dimensionSizes[i] +
- " but cannot be larger than " + size.get());
+ if (size.isPresent() && size.get() != dimensionSizes[i])
+ throw new IllegalArgumentException("Size of " + type.dimensions() + " must be " + size.get() +
+ ", not " + dimensionSizes[i]);
}
return new BoundBuilder(type, dimensionSizes);
@@ -347,9 +342,14 @@ public class IndexedTensor implements Tensor {
@Override
public Builder cell(TensorAddress address, double value) {
- int[] indexes = new int[address.size()];
- for (int i = 0; i < address.size(); i++) {
- indexes[i] = address.intLabel(i);
+ int[] indexes = new int[address.labels().size()];
+ for (int i = 0; i < address.labels().size(); i++) {
+ try {
+ indexes[i] = Integer.parseInt(address.labels().get(i));
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Labels in an indexed tensor must be integers, not '" +
+ address.labels().get(i) + "'");
+ }
}
cell(value, indexes);
return this;
@@ -397,251 +397,71 @@ public class IndexedTensor implements Tensor {
}
- // TODO: Generalize to vector cell iterator?
private final class CellIterator implements Iterator<Map.Entry<TensorAddress, Double>> {
- private int count = 0;
- private final Indexes indexes = new Indexes(dimensionSizes, values.length);
+ private int cursor = 0;
+ private final int[] tensorIndexes = new int[dimensionSizes.length];
@Override
public boolean hasNext() {
- return count < indexes.size();
+ return cursor < values.length;
}
@Override
public Map.Entry<TensorAddress, Double> next() {
- if ( ! hasNext()) throw new NoSuchElementException("No cell at " + indexes);
+ if ( ! hasNext()) throw new NoSuchElementException();
- Map.Entry<TensorAddress, Double> current = new Cell(indexes.toAddress(), get(indexes));
+ Map.Entry<TensorAddress, Double> current = new Cell(new TensorAddress(tensorIndexes), values[cursor]);
- count++;
+ cursor++;
if (hasNext())
- indexes.next();
+ IndexedTensor.this.next(tensorIndexes);
return current;
}
- }
-
- private class Cell implements Map.Entry<TensorAddress, Double> {
-
- private final TensorAddress address;
- private final Double value;
+ private class Cell implements Map.Entry<TensorAddress, Double> {
- private Cell(TensorAddress address, Double value) {
- this.address = address;
- this.value = value;
- }
+ private final TensorAddress address;
+ private final Double value;
+
+ private Cell(TensorAddress address, Double value) {
+ this.address = address;
+ this.value = value;
+ }
+
+ @Override
+ public TensorAddress getKey() { return address; }
- @Override
- public TensorAddress getKey() { return address; }
+ @Override
+ public Double getValue() { return value; }
- @Override
- public Double getValue() { return value; }
+ @Override
+ public Double setValue(Double value) {
+ throw new UnsupportedOperationException("A tensor cannot be modified");
+ }
- @Override
- public Double setValue(Double value) {
- throw new UnsupportedOperationException("A tensor cannot be modified");
}
}
private final class ValueIterator implements Iterator<Double> {
- private int count = 0;
+ private int cursor = 0;
@Override
public boolean hasNext() {
- return count < values.length;
+ return cursor < values.length;
}
@Override
public Double next() {
try {
- return values[count++];
+ return values[cursor++];
}
catch (IndexOutOfBoundsException e) {
- throw new NoSuchElementException("No element at position " + count);
- }
- }
-
- }
-
- private final class SuperspaceIterator implements Iterator<SubspaceIterator> {
-
- private final Indexes superindexes;
-
- /** true at indexes whose dimension subspaces iterate over */
- private final boolean[] subdimensionIndexes;
-
- /**
- * The sizes of the space we'll return values of, one value for each dimension of this tensor,
- * which may be equal to or smaller than the sizes of this tensor
- */
- private final int[] dimensionSizes;
-
- private int count = 0;
-
- private SuperspaceIterator(Set<String> superdimensionNames, int[] dimensionSizes) {
- this.dimensionSizes = dimensionSizes;
-
- boolean[] superdimensionIndexes = new boolean[dimensionSizes.length]; // for outer iterator
- subdimensionIndexes = new boolean [dimensionSizes.length]; // for inner iterator
- for (int i = 0; i < type.dimensions().size(); i++ ) {
- boolean superDimension = superdimensionNames.contains(type.dimensions().get(i).name());
- superdimensionIndexes[i] = superDimension;
- subdimensionIndexes[i] = ! superDimension;
+ throw new NoSuchElementException("No element at position " + cursor);
}
-
- superindexes = new Indexes(dimensionSizes, superdimensionIndexes);
- }
-
- @Override
- public boolean hasNext() {
- return count < superindexes.size();
- }
-
- @Override
- public SubspaceIterator next() {
- if ( ! hasNext()) throw new NoSuchElementException("No cell at " + superindexes);
- SubspaceIterator subspace = new SubspaceIterator(subdimensionIndexes, superindexes.indexesCopy(), dimensionSizes);
- count++;
- if (hasNext())
- superindexes.next();
- return subspace;
- }
-
- }
-
- /**
- * An iterator over a subspace of this tensor. This is exposed to allow clients to query the size.
- */
- public final class SubspaceIterator implements Iterator<Map.Entry<TensorAddress, Double>> {
-
- private final Indexes indexes;
- private int count = 0;
-
- /**
- * Creates a new subspace iterator
- *
- * @param dimensionIndexes a boolean array with a true entry for dimensions we should iterate over and false
- * entries for all other dimensions
- * @param address the address of the first cell of this subspace.
- */
- private SubspaceIterator(boolean[] dimensionIndexes, int[] address, int[] dimensionSizes) {
- this.indexes = new Indexes(dimensionSizes, dimensionIndexes, address);
- }
-
- /** Returns the total number of cells in this subspace */
- public int size() {
- return indexes.size();
- }
-
- @Override
- public boolean hasNext() { return count < indexes.size(); }
-
- @Override
- public Map.Entry<TensorAddress, Double> next() {
- if ( ! hasNext()) throw new NoSuchElementException("No cell at " + indexes);
-
- Map.Entry<TensorAddress, Double> current = new Cell(indexes.toAddress(), get(indexes));
-
- count++;
- if (hasNext())
- indexes.next();
-
- return current;
- }
-
- }
-
- /** An array of indexes into this tensor which are able to find the next index in the value order */
- private static class Indexes {
-
- private final int size;
- private final int[] indexes;
-
- private final int[] dimensionSizes;
-
- /** Only mutate (take next in) the dimension indexes which are true */
- private final boolean[] iteratingDimensions;
-
- private Indexes(int[] dimensionSizes, int size) {
- this(dimensionSizes, trueArray(dimensionSizes.length), size);
- }
-
- private Indexes(int[] dimensionSizes, boolean[] iteratingDimensions) {
- this(dimensionSizes, iteratingDimensions, computeSize(dimensionSizes, iteratingDimensions));
- }
-
- private Indexes(int[] dimensionSizes, boolean[] iteratingDimensionIndexes, int size) {
- this(dimensionSizes, iteratingDimensionIndexes, new int[dimensionSizes.length], size);
- }
-
- private Indexes(int[] dimensionSizes, boolean[] iteratingDimensions, int[] initialIndexes) {
- this(dimensionSizes, iteratingDimensions, initialIndexes, computeSize(dimensionSizes, iteratingDimensions));
- }
-
- private Indexes(int[] dimensionSizes, boolean[] iteratingDimensions, int[] initialIndexes, int size) {
- this.dimensionSizes = dimensionSizes;
- this.iteratingDimensions = iteratingDimensions;
- this.indexes = initialIndexes;
- this.size = size;
- }
-
- private static boolean[] trueArray(int size) {
- boolean[] array = new boolean[size];
- Arrays.fill(array, true);
- return array;
- }
-
- private static int computeSize(int[] dimensionSizes, boolean[] iteratingDimensions) {
- int size = 1;
- for (int dimensionIndex = 0; dimensionIndex < dimensionSizes.length; dimensionIndex++)
- if (iteratingDimensions[dimensionIndex])
- size *= dimensionSizes[dimensionIndex];
- return size;
- }
-
- private static boolean anyTrue(boolean[] values) {
- for (boolean value : values)
- if (value) return true;
- return false;
- }
-
- /** Returns the number of values this will iterate over - i.e the product if the iterating dimension sizes */
- public int size() {
- return size;
- }
-
- private void next() {
- int currentDimension = indexes.length - 1;
- while ( ! iteratingDimensions[currentDimension] ||
- indexes[currentDimension] + 1 == dimensionSizes[currentDimension]) {
- if ( iteratingDimensions[currentDimension])
- indexes[currentDimension--] = 0; // carry over
- else // leave this dimension as-is
- currentDimension--;
- }
- indexes[currentDimension]++;
- }
-
- /** Returns the address of the current position of these indexes */
- private TensorAddress toAddress() {
- // TODO: We may avoid the array copy by issuing a one-time-use address?
- return TensorAddress.of(indexes);
- }
-
- private int[] indexesCopy() {
- return Arrays.copyOf(indexes, indexes.length);
- }
-
- /** Returns a copy of the indexes of this which must not be modified */
- private int[] indexesForReading() { return indexes; }
-
- @Override
- public String toString() {
- return "indexes " + Arrays.toString(indexes);
}
}
diff --git a/vespajlib/src/main/java/com/yahoo/tensor/MappedTensor.java b/vespajlib/src/main/java/com/yahoo/tensor/MappedTensor.java
index 6e169b8347f..f87a97cb44e 100644
--- a/vespajlib/src/main/java/com/yahoo/tensor/MappedTensor.java
+++ b/vespajlib/src/main/java/com/yahoo/tensor/MappedTensor.java
@@ -81,7 +81,7 @@ public class MappedTensor implements Tensor {
@Override
public Builder cell(double value, int... labels) {
- cells.put(TensorAddress.of(labels), value);
+ cells.put(new TensorAddress(labels), value);
return this;
}
diff --git a/vespajlib/src/main/java/com/yahoo/tensor/Tensor.java b/vespajlib/src/main/java/com/yahoo/tensor/Tensor.java
index 6f655fd5860..260c48ace7f 100644
--- a/vespajlib/src/main/java/com/yahoo/tensor/Tensor.java
+++ b/vespajlib/src/main/java/com/yahoo/tensor/Tensor.java
@@ -73,6 +73,8 @@ public interface Tensor {
if (type().dimensions().size() > 0)
throw new IllegalStateException("This tensor is not dimensionless. Dimensions: " + type().dimensions().size());
if (size() == 0) return Double.NaN;
+ if (size() > 1)
+ throw new IllegalStateException("This tensor does not have a single value, it has " + size());
return valueIterator().next();
}
@@ -211,7 +213,9 @@ public interface Tensor {
/** Returns true if the two given tensors are mathematically equivalent, that is whether both have the same content */
static boolean equals(Tensor a, Tensor b) {
- return a == b || a.cells().equals(b.cells());
+ if (a == b) return true;
+ if ( ! a.cells().equals(b.cells())) return false;
+ return true;
}
// ----------------- Factories
@@ -246,8 +250,9 @@ public interface Tensor {
}
interface Builder {
-
+
/** Creates a suitable builder for the given type */
+ // TODO: Create version of this which takes size info and use it when possible
static Builder of(TensorType type) {
boolean containsIndexed = type.dimensions().stream().anyMatch(d -> d.isIndexed());
boolean containsMapped = type.dimensions().stream().anyMatch( d -> ! d.isIndexed());
@@ -258,19 +263,7 @@ public interface Tensor {
else // indexed or empty
return IndexedTensor.Builder.of(type);
}
-
- /** Creates a suitable builder for the given type */
- static Builder of(TensorType type, int[] dimensionSizes) {
- boolean containsIndexed = type.dimensions().stream().anyMatch(d -> d.isIndexed());
- boolean containsMapped = type.dimensions().stream().anyMatch( d -> ! d.isIndexed());
- if (containsIndexed && containsMapped)
- throw new IllegalArgumentException("Combining indexed and mapped dimensions is not supported yet");
- if (containsMapped)
- return MappedTensor.Builder.of(type);
- else // indexed or empty
- return IndexedTensor.Builder.of(type, dimensionSizes);
- }
-
+
/** Returns the type this is building */
TensorType type();
diff --git a/vespajlib/src/main/java/com/yahoo/tensor/TensorAddress.java b/vespajlib/src/main/java/com/yahoo/tensor/TensorAddress.java
index 5224d9632ec..abcaee2dfa5 100644
--- a/vespajlib/src/main/java/com/yahoo/tensor/TensorAddress.java
+++ b/vespajlib/src/main/java/com/yahoo/tensor/TensorAddress.java
@@ -20,73 +20,55 @@ import java.util.Set;
* @author bratseth
*/
@Beta
-public abstract class TensorAddress implements Comparable<TensorAddress> {
+public final class TensorAddress implements Comparable<TensorAddress> {
public static final TensorAddress empty = new TensorAddress.Builder(TensorType.empty).build();
- public static TensorAddress of(String[] labels) {
- return new StringTensorAddress(labels);
+ private final ImmutableList<String> labels;
+
+ public TensorAddress(String ... labels) {
+ this.labels = ImmutableList.copyOf(labels);
}
- public static TensorAddress of(int ... labels) {
- return new IntTensorAddress(labels);
+ public TensorAddress(int ... labels) {
+ ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
+ for (int label : labels)
+ builder.add(String.valueOf(label));
+ this.labels = builder.build();
}
- /** Returns the number of labels in this */
- public abstract int size();
-
- /**
- * Returns the i'th label in this
- *
- * @throws IllegalArgumentException if there is no label at this index
- */
- public abstract String label(int i);
-
- /**
- * Returns the i'th label in this as an int.
- * Prefer this if you know that this is an integer address, but not otherwise.
- *
- * @throws IllegalArgumentException if there is no label at this index
- */
- public abstract int intLabel(int i);
-
- public final boolean isEmpty() { return size() == 0; }
+ /** Returns the labels of this as an immutable list in the order of the dimensions of the tensor type of this */
+ public List<String> labels() { return labels; }
@Override
public int compareTo(TensorAddress other) {
- // TODO: Formal issue (only): Ordering with different address sizes
- for (int i = 0; i < size(); i++) {
- int elementComparison = this.label(i).compareTo(other.label(i));
+ for (int i = 0; i < labels.size(); i++) {
+ int elementComparison = this.labels.get(i).compareTo(other.labels.get(i));
if (elementComparison != 0) return elementComparison;
}
return 0;
}
@Override
- public int hashCode() {
- int result = 1;
- for (int i = 0; i < size(); i++)
- result = 31 * result + label(i).hashCode();
- return result;
+ public int hashCode() { return labels.hashCode(); }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) return true;
+ if ( ! (other instanceof TensorAddress)) return false;
+ return ((TensorAddress)other).labels.equals(this.labels);
}
@Override
- public boolean equals(Object o) {
- if (o == this) return true;
- if ( ! (o instanceof TensorAddress)) return false;
- TensorAddress other = (TensorAddress)o;
- if (other.size() != this.size()) return false;
- for (int i = 0; i < this.size(); i++)
- if ( ! this.label(i).equals(other.label(i)))
- return false;
- return true;
+ public String toString() {
+ return labels.toString();
}
- /** Returns this as a string on the appropriate form given the type */
- public final String toString(TensorType type) {
+ /** Returns this on the appropriate form given the type */
+ public String toString(TensorType type) {
StringBuilder b = new StringBuilder("{");
- for (int i = 0; i < size(); i++) {
- b.append(type.dimensions().get(i).name()).append(":").append(label(i));
+ for (int i = 0; i < labels.size(); i++) {
+ b.append(type.dimensions().get(i).name()).append(":").append(labels.get(i));
b.append(",");
}
if (b.length() > 1)
@@ -95,61 +77,6 @@ public abstract class TensorAddress implements Comparable<TensorAddress> {
return b.toString();
}
- private static final class StringTensorAddress extends TensorAddress {
-
- private final String[] labels;
-
- private StringTensorAddress(String ... labels) {
- this.labels = Arrays.copyOf(labels, labels.length);
- }
-
- @Override
- public int size() { return labels.length; }
-
- @Override
- public String label(int i) { return labels[i]; }
-
- @Override
- public int intLabel(int i) {
- try {
- return Integer.parseInt(labels[i]);
- }
- catch (NumberFormatException e) {
- throw new IllegalArgumentException("Expected an int label in " + this + " at position " + i);
- }
- }
-
- @Override
- public String toString() {
- return Arrays.toString(labels);
- }
-
- }
-
- private static final class IntTensorAddress extends TensorAddress {
-
- private final int[] labels;
-
- private IntTensorAddress(int ... labels) {
- this.labels = Arrays.copyOf(labels, labels.length);
- }
-
- @Override
- public int size() { return labels.length; }
-
- @Override
- public String label(int i) { return String.valueOf(labels[i]); }
-
- @Override
- public int intLabel(int i) { return labels[i]; }
-
- @Override
- public String toString() {
- return Arrays.toString(labels);
- }
-
- }
-
/** Supports building of a tensor address */
public static class Builder {
@@ -190,7 +117,7 @@ public abstract class TensorAddress implements Comparable<TensorAddress> {
if (labels[i] == null)
throw new IllegalArgumentException("Missing a value for dimension " +
type.dimensions().get(i).name() + " for " + type);
- return TensorAddress.of(labels);
+ return new TensorAddress(labels);
}
}
diff --git a/vespajlib/src/main/java/com/yahoo/tensor/TensorType.java b/vespajlib/src/main/java/com/yahoo/tensor/TensorType.java
index e829f4c909b..0c726efc047 100644
--- a/vespajlib/src/main/java/com/yahoo/tensor/TensorType.java
+++ b/vespajlib/src/main/java/com/yahoo/tensor/TensorType.java
@@ -53,9 +53,6 @@ public class TensorType {
return TensorTypeParser.fromSpec(specString);
}
- /** Returns true if all dimensions of this are indexed */
- public boolean isIndexed() { return dimensions().stream().allMatch(d -> d.isIndexed()); }
-
private static final boolean supportsMixedTypes = false;
/**
@@ -179,7 +176,7 @@ public class TensorType {
// both are indexed bound
IndexedBoundDimension thisIb = (IndexedBoundDimension)this;
IndexedBoundDimension otherIb = (IndexedBoundDimension)other.get();
- return thisIb.size().get() < otherIb.size().get() ? thisIb : otherIb;
+ return thisIb.size().get() > otherIb.size().get() ? thisIb : otherIb;
}
@Override
diff --git a/vespajlib/src/main/java/com/yahoo/tensor/functions/Join.java b/vespajlib/src/main/java/com/yahoo/tensor/functions/Join.java
index 6128611302f..19b4ad39af3 100644
--- a/vespajlib/src/main/java/com/yahoo/tensor/functions/Join.java
+++ b/vespajlib/src/main/java/com/yahoo/tensor/functions/Join.java
@@ -2,20 +2,18 @@ package com.yahoo.tensor.functions;
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.yahoo.tensor.IndexedTensor;
+import com.yahoo.tensor.MappedTensor;
import com.yahoo.tensor.Tensor;
import com.yahoo.tensor.TensorAddress;
import com.yahoo.tensor.TensorType;
import com.yahoo.tensor.evaluation.EvaluationContext;
-import java.util.Arrays;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
import java.util.function.DoubleBinaryOperator;
/**
@@ -71,7 +69,7 @@ public class Join extends PrimitiveTensorFunction {
TensorType joinedType = a.type().combineWith(b.type());
// Choose join algorithm
- if (hasSingleIndexedDimension(a) && hasSingleIndexedDimension(b) && a.type().dimensions().get(0).name().equals(b.type().dimensions().get(0).name()))
+ if (a.type().equals(b.type()) && a.type().dimensions().size() == 1 && a.type().dimensions().get(0).isIndexed())
return indexedVectorJoin((IndexedTensor)a, (IndexedTensor)b, joinedType);
else if (joinedType.dimensions().size() == a.type().dimensions().size() && joinedType.dimensions().size() == b.type().dimensions().size())
return singleSpaceJoin(a, b, joinedType);
@@ -83,12 +81,8 @@ public class Join extends PrimitiveTensorFunction {
return generalJoin(a, b, joinedType);
}
- private boolean hasSingleIndexedDimension(Tensor tensor) {
- return tensor.type().dimensions().size() == 1 && tensor.type().dimensions().get(0).isIndexed();
- }
-
private Tensor indexedVectorJoin(IndexedTensor a, IndexedTensor b, TensorType type) {
- int joinedLength = Math.min(a.size(0), b.size(0));
+ int joinedLength = Math.min(a.length(0), b.length(0));
Iterator<Double> aIterator = a.valueIterator();
Iterator<Double> bIterator = b.valueIterator();
IndexedTensor.Builder builder = IndexedTensor.Builder.of(type, new int[] { joinedLength});
@@ -111,42 +105,6 @@ public class Join extends PrimitiveTensorFunction {
/** Join a tensor into a superspace */
private Tensor subspaceJoin(Tensor subspace, Tensor superspace, TensorType joinedType, boolean reversedArgumentOrder) {
- if (subspace.type().isIndexed() && superspace.type().isIndexed())
- return indexedSubspaceJoin((IndexedTensor) subspace, (IndexedTensor) superspace, joinedType, reversedArgumentOrder);
- else
- return generalSubspaceJoin(subspace, superspace, joinedType, reversedArgumentOrder);
- }
-
- private Tensor indexedSubspaceJoin(IndexedTensor subspace, IndexedTensor superspace, TensorType joinedType, boolean reversedArgumentOrder) {
- if (subspace.size() == 0 || superspace.size() == 0) // special case empty here to avoid doing it when finding sizes
- return Tensor.Builder.of(joinedType, new int[joinedType.dimensions().size()]).build();
-
- // Find size of joined tensor
- int[] joinedSizes = new int[joinedType.dimensions().size()];
- for (int i = 0; i < joinedSizes.length; i++) {
- Optional<Integer> subspaceIndex = subspace.type().indexOfDimension(joinedType.dimensions().get(i).name());
- if (subspaceIndex.isPresent())
- joinedSizes[i] = Math.min(superspace.size(i), subspace.size(subspaceIndex.get()));
- else
- joinedSizes[i] = superspace.size(i);
- }
-
- Tensor.Builder builder = Tensor.Builder.of(joinedType, joinedSizes);
-
- // Find dimensions which are only in the supertype
- Set<String> superDimensionNames = new HashSet<>(superspace.type().dimensionNames());
- superDimensionNames.removeAll(subspace.type().dimensionNames());
-
- for (Iterator<IndexedTensor.SubspaceIterator> i = superspace.subspaceIterator(superDimensionNames, joinedSizes); i.hasNext(); ) {
- IndexedTensor.SubspaceIterator subspaceInSuper = i.next();
- joinSubspaces(subspace.valueIterator(), subspace.size(),
- subspaceInSuper, subspaceInSuper.size(),
- reversedArgumentOrder, builder);
- }
- return builder.build();
- }
-
- private Tensor generalSubspaceJoin(Tensor subspace, Tensor superspace, TensorType joinedType, boolean reversedArgumentOrder) {
int[] subspaceIndexes = subspaceIndexes(superspace.type(), subspace.type());
Tensor.Builder builder = Tensor.Builder.of(joinedType);
for (Iterator<Map.Entry<TensorAddress, Double>> i = superspace.cellIterator(); i.hasNext(); ) {
@@ -154,26 +112,13 @@ public class Join extends PrimitiveTensorFunction {
TensorAddress subaddress = mapAddressToSubspace(supercell.getKey(), subspaceIndexes);
double subspaceValue = subspace.get(subaddress);
if ( ! Double.isNaN(subspaceValue))
- builder.cell(supercell.getKey(),
+ builder.cell(supercell.getKey(),
reversedArgumentOrder ? combinator.applyAsDouble(supercell.getValue(), subspaceValue)
: combinator.applyAsDouble(subspaceValue, supercell.getValue()));
}
return builder.build();
}
-
- private void joinSubspaces(Iterator<Double> subspace, int subspaceSize,
- Iterator<Map.Entry<TensorAddress, Double>> superspace, int superspaceSize,
- boolean reversedArgumentOrder, Tensor.Builder builder) {
- int joinedLength = Math.min(subspaceSize, superspaceSize);
- for (int i = 0; i < joinedLength; i++) {
- Double subvalue = subspace.next();
- Map.Entry<TensorAddress, Double> supercell = superspace.next();
- builder.cell(supercell.getKey(),
- reversedArgumentOrder ? combinator.applyAsDouble(supercell.getValue(), subvalue)
- : combinator.applyAsDouble(subvalue, supercell.getValue()));
- }
- }
-
+
/** Returns the indexes in the superspace type which should be retained to create the subspace type */
private int[] subspaceIndexes(TensorType supertype, TensorType subtype) {
int[] subspaceIndexes = new int[subtype.dimensions().size()];
@@ -185,8 +130,8 @@ public class Join extends PrimitiveTensorFunction {
private TensorAddress mapAddressToSubspace(TensorAddress superAddress, int[] subspaceIndexes) {
String[] subspaceLabels = new String[subspaceIndexes.length];
for (int i = 0; i < subspaceIndexes.length; i++)
- subspaceLabels[i] = superAddress.label(subspaceIndexes[i]);
- return TensorAddress.of(subspaceLabels);
+ subspaceLabels[i] = superAddress.labels().get(subspaceIndexes[i]);
+ return new TensorAddress(subspaceLabels);
}
/** Slow join which works for any two tensors */
@@ -224,10 +169,10 @@ public class Join extends PrimitiveTensorFunction {
private TensorAddress combineAddresses(TensorAddress a, int[] aToIndexes, TensorAddress b, int[] bToIndexes,
TensorType joinedType) {
String[] joinedLabels = new String[joinedType.dimensions().size()];
- mapContent(a, joinedLabels, aToIndexes);
- boolean compatible = mapContent(b, joinedLabels, bToIndexes);
+ mapContent(a.labels(), joinedLabels, aToIndexes);
+ boolean compatible = mapContent(b.labels(), joinedLabels, bToIndexes);
if ( ! compatible) return null;
- return TensorAddress.of(joinedLabels);
+ return new TensorAddress(joinedLabels);
}
/**
@@ -236,11 +181,11 @@ public class Join extends PrimitiveTensorFunction {
* @return true if the mapping was successful, false if one of the destination positions was
* occupied by a different value
*/
- private boolean mapContent(TensorAddress from, String[] to, int[] indexMap) {
+ private boolean mapContent(List<String> from, String[] to, int[] indexMap) {
for (int i = 0; i < from.size(); i++) {
int toIndex = indexMap[i];
- if (to[toIndex] != null && ! to[toIndex].equals(from.label(i))) return false;
- to[toIndex] = from.label(i);
+ if (to[toIndex] != null && ! to[toIndex].equals(from.get(i))) return false;
+ to[toIndex] = from.get(i);
}
return true;
}
diff --git a/vespajlib/src/main/java/com/yahoo/tensor/functions/Reduce.java b/vespajlib/src/main/java/com/yahoo/tensor/functions/Reduce.java
index d528b4d3dc5..7595d18fb18 100644
--- a/vespajlib/src/main/java/com/yahoo/tensor/functions/Reduce.java
+++ b/vespajlib/src/main/java/com/yahoo/tensor/functions/Reduce.java
@@ -2,7 +2,9 @@ package com.yahoo.tensor.functions;
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.yahoo.tensor.IndexedTensor;
+import com.yahoo.tensor.MappedTensor;
import com.yahoo.tensor.Tensor;
import com.yahoo.tensor.TensorAddress;
import com.yahoo.tensor.TensorType;
@@ -132,10 +134,10 @@ public class Reduce extends PrimitiveTensorFunction {
String[] reducedLabels = new String[reducedType.dimensions().size()];
int reducedLabelIndex = 0;
- for (int i = 0; i < address.size(); i++)
+ for (int i = 0; i < address.labels().size(); i++)
if ( ! indexesToRemove.contains(i))
- reducedLabels[reducedLabelIndex++] = address.label(i);
- return TensorAddress.of(reducedLabels);
+ reducedLabels[reducedLabelIndex++] = address.labels().get(i);
+ return new TensorAddress(reducedLabels);
}
private Tensor reduceAllGeneral(Tensor argument) {
@@ -147,7 +149,7 @@ public class Reduce extends PrimitiveTensorFunction {
private Tensor reduceIndexedVector(IndexedTensor argument) {
ValueAggregator valueAggregator = ValueAggregator.ofType(aggregator);
- for (int i = 0; i < argument.size(0); i++)
+ for (int i = 0; i < argument.length(0); i++)
valueAggregator.aggregate(argument.get(i));
return Tensor.Builder.of(TensorType.empty).cell((valueAggregator.aggregatedValue())).build();
}
diff --git a/vespajlib/src/main/java/com/yahoo/tensor/functions/Rename.java b/vespajlib/src/main/java/com/yahoo/tensor/functions/Rename.java
index 29dcb218843..aabe38d1824 100644
--- a/vespajlib/src/main/java/com/yahoo/tensor/functions/Rename.java
+++ b/vespajlib/src/main/java/com/yahoo/tensor/functions/Rename.java
@@ -89,8 +89,8 @@ public class Rename extends PrimitiveTensorFunction {
private TensorAddress rename(TensorAddress address, int[] toIndexes) {
String[] reorderedLabels = new String[toIndexes.length];
for (int i = 0; i < toIndexes.length; i++)
- reorderedLabels[toIndexes[i]] = address.label(i);
- return TensorAddress.of(reorderedLabels);
+ reorderedLabels[toIndexes[i]] = address.labels().get(i);
+ return new TensorAddress(reorderedLabels);
}
@Override
diff --git a/vespajlib/src/main/java/com/yahoo/tensor/serialization/SparseBinaryFormat.java b/vespajlib/src/main/java/com/yahoo/tensor/serialization/SparseBinaryFormat.java
index 8e15a994ed9..cb9a93fd233 100644
--- a/vespajlib/src/main/java/com/yahoo/tensor/serialization/SparseBinaryFormat.java
+++ b/vespajlib/src/main/java/com/yahoo/tensor/serialization/SparseBinaryFormat.java
@@ -48,8 +48,9 @@ class SparseBinaryFormat implements BinaryFormat {
}
private static void encodeAddress(GrowableByteBuffer buffer, TensorAddress address) {
- for (int i = 0; i < address.size(); i++)
- encodeString(buffer, address.label(i));
+ for (String label : address.labels()) {
+ encodeString(buffer, label);
+ }
}
private static void encodeString(GrowableByteBuffer buffer, String value) {
diff --git a/vespajlib/src/test/java/com/yahoo/tensor/IndexedTensorTestCase.java b/vespajlib/src/test/java/com/yahoo/tensor/IndexedTensorTestCase.java
index 9183ad68956..5e91679c412 100644
--- a/vespajlib/src/test/java/com/yahoo/tensor/IndexedTensorTestCase.java
+++ b/vespajlib/src/test/java/com/yahoo/tensor/IndexedTensorTestCase.java
@@ -56,10 +56,10 @@ public class IndexedTensorTestCase {
assertEquals(emptyWithDimensions, emptyWithDimensionsFromString);
IndexedTensor emptyWithDimensionsIndexed = (IndexedTensor)emptyWithDimensions;
- assertEquals(0, emptyWithDimensionsIndexed.size(0));
- assertEquals(0, emptyWithDimensionsIndexed.size(1));
+ assertEquals(0, emptyWithDimensionsIndexed.length(0));
+ assertEquals(0, emptyWithDimensionsIndexed.length(1));
}
-
+
@Test
public void testBoundBuilding() {
TensorType type = new TensorType.Builder().indexed("v", vSize)
@@ -108,7 +108,7 @@ public class IndexedTensorTestCase {
for (int y = 0; y < ySize; y++)
for (int x = xSize - 1; x >= 0; x--)
for (int z = 0; z < zSize; z++)
- assertEquals(value(v, w, x, y, z), (int) tensor.get(TensorAddress.of(v, w, x, y, z)));
+ assertEquals(value(v, w, x, y, z), (int) tensor.get(new TensorAddress(v, w, x, y, z)));
// Lookup from cells
Map<TensorAddress, Double> cells = tensor.cells();
@@ -118,7 +118,7 @@ public class IndexedTensorTestCase {
for (int y = 0; y < ySize; y++)
for (int x = xSize - 1; x >= 0; x--)
for (int z = 0; z < zSize; z++)
- assertEquals(value(v, w, x, y, z), cells.get(TensorAddress.of(v, w, x, y, z)).intValue());
+ assertEquals(value(v, w, x, y, z), cells.get(new TensorAddress(v, w, x, y, z)).intValue());
// Lookup from iterator
Map<TensorAddress, Double> cellsOfIterator = new HashMap<>();
@@ -132,7 +132,7 @@ public class IndexedTensorTestCase {
for (int y = 0; y < ySize; y++)
for (int x = xSize - 1; x >= 0; x--)
for (int z = 0; z < zSize; z++)
- assertEquals(value(v, w, x, y, z), cellsOfIterator.get(TensorAddress.of(v, w, x, y, z)).intValue());
+ assertEquals(value(v, w, x, y, z), cellsOfIterator.get(new TensorAddress(v, w, x, y, z)).intValue());
}
diff --git a/vespajlib/src/test/java/com/yahoo/tensor/JoinTestCase.java b/vespajlib/src/test/java/com/yahoo/tensor/JoinTestCase.java
deleted file mode 100644
index 63dd4a4a644..00000000000
--- a/vespajlib/src/test/java/com/yahoo/tensor/JoinTestCase.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.yahoo.tensor;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * @author bratseth
- */
-public class JoinTestCase {
-
- /** Test the indexed subspace join optimization */
- @Test
- public void testJoinIndexedSubspace() {
- Tensor t1, t2;
-
- t1 = Tensor.from("tensor(x[]):{{x:0}:1.0,{x:1}:2.0}");
- t2 = Tensor.from("tensor(x[],y[],z[]):{{x:0,y:0,z:0}:6,{x:0,y:1,z:0}:0.0,{x:1,y:0,z:0}:10,{x:1,y:1,z:0}:0.0}");
- assertEquals(Tensor.from("tensor(x[],y[],z[]):{{x:0,y:0,z:0}:6,{x:0,y:1,z:0}:0.0,{x:1,y:0,z:0}:20.0,{x:1,y:1,z:0}:0.0}"),
- t1.multiply(t2));
- t1 = Tensor.from("tensor(x[]):{{x:0}:1.0,{x:1}:2.0}");
- t2 = Tensor.from("tensor(x[],y[],z[]):{{x:0,y:0,z:0}:6,{x:0,y:1,z:0}:0.0,{x:1,y:0,z:0}:10,{x:1,y:1,z:0}:0.0}");
- assertEquals(Tensor.from("tensor(x[],y[],z[]):{{x:0,y:0,z:0}:6,{x:0,y:1,z:0}:0.0,{x:1,y:0,z:0}:5.0,{x:1,y:1,z:0}:0.0}"),
- t2.divide(t1));
-
- t1 = Tensor.from("tensor(y[]):{{y:0}:1.0,{y:1}:2.0}");
- t2 = Tensor.from("tensor(x[],y[],z[]):{{x:0,y:0,z:0}:6,{x:0,y:1,z:0}:0.0,{x:1,y:0,z:0}:10,{x:1,y:1,z:0}:0.0}");
- assertEquals(Tensor.from("tensor(x[],y[],z[]):{{x:0,y:0,z:0}:6,{x:0,y:1,z:0}:0.0,{x:1,y:0,z:0}:10.0,{x:1,y:1,z:0}:0.0}"),
- t1.multiply(t2));
- t1 = Tensor.from("tensor(y[]):{{y:0}:1.0,{y:1}:2.0}");
- t2 = Tensor.from("tensor(x[],y[],z[]):{{x:0,y:0,z:0}:6,{x:0,y:1,z:0}:0.0,{x:1,y:0,z:0}:10,{x:1,y:1,z:0}:0.0}");
- assertEquals(Tensor.from("tensor(x[],y[],z[]):{{x:0,y:0,z:0}:6,{x:0,y:1,z:0}:0.0,{x:1,y:0,z:0}:10.0,{x:1,y:1,z:0}:0.0}"),
- t2.divide(t1));
- }
-
-}
diff --git a/vespajlib/src/test/java/com/yahoo/tensor/TensorFunctionBenchmark.java b/vespajlib/src/test/java/com/yahoo/tensor/TensorFunctionBenchmark.java
index 9b34780a6fc..bbab92fc16d 100644
--- a/vespajlib/src/test/java/com/yahoo/tensor/TensorFunctionBenchmark.java
+++ b/vespajlib/src/test/java/com/yahoo/tensor/TensorFunctionBenchmark.java
@@ -106,13 +106,11 @@ public class TensorFunctionBenchmark {
// ---------------- Mapped with extra space (sidesteps current special-case optimizations):
// Initial: 450 ms
- // - Now: 350 ms
- time = new TensorFunctionBenchmark().benchmark(20, vectors(100, 300, TensorType.Dimension.Type.mapped), TensorType.Dimension.Type.mapped, true);
- System.out.printf("Mapped vectors, x space time per join: %1$8.3f ms\n", time);
+ //time = new TensorFunctionBenchmark().benchmark(20, vectors(100, 300, TensorType.Dimension.Type.mapped), TensorType.Dimension.Type.mapped, true);
+ //System.out.printf("Mapped vectors, x space time per join: %1$8.3f ms\n", time);
// Initial: 900 ms
- // - Now: 700 ms
- time = new TensorFunctionBenchmark().benchmark(20, matrix(100, 300, TensorType.Dimension.Type.mapped), TensorType.Dimension.Type.mapped, true);
- System.out.printf("Mapped matrix, x space time per join: %1$8.3f ms\n", time);
+ //time = new TensorFunctionBenchmark().benchmark(20, matrix(100, 300, TensorType.Dimension.Type.mapped), TensorType.Dimension.Type.mapped, true);
+ //System.out.printf("Mapped matrix, x space time per join: %1$8.3f ms\n", time);
// ---------------- Mapped:
// Initial: 150 ms
@@ -123,51 +121,40 @@ public class TensorFunctionBenchmark {
System.out.printf("Mapped vectors, time per join: %1$8.3f ms\n", time);
// Initial: 760 ms
// - After special-casing subspace: 13 ms
- // - Now: 7 ms
time = new TensorFunctionBenchmark().benchmark(500, matrix(100, 300, TensorType.Dimension.Type.mapped), TensorType.Dimension.Type.mapped, false);
System.out.printf("Mapped matrix, time per join: %1$8.3f ms\n", time);
// ---------------- Indexed (unbound) with extra space (sidesteps current special-case optimizations):
// Initial: 1900 ms
// - After moving to cell iterators: 1100
- // - Now: 1300
- time = new TensorFunctionBenchmark().benchmark(20, vectors(100, 300, TensorType.Dimension.Type.indexedUnbound), TensorType.Dimension.Type.indexedUnbound, true);
- System.out.printf("Indexed vectors, x space time per join: %1$8.3f ms\n", time);
+ //time = new TensorFunctionBenchmark().benchmark(20, vectors(100, 300, TensorType.Dimension.Type.indexedUnbound), TensorType.Dimension.Type.indexedUnbound, true);
+ //System.out.printf("Indexed vectors, x space time per join: %1$8.3f ms\n", time);
// Initial: 2200 ms
// - After moving to cell iterators: 1300
- // - Now: 1550
- time = new TensorFunctionBenchmark().benchmark(20, matrix(100, 300, TensorType.Dimension.Type.indexedUnbound), TensorType.Dimension.Type.indexedUnbound, true);
- System.out.printf("Indexed matrix, x space time per join: %1$8.3f ms\n", time);
+ //time = new TensorFunctionBenchmark().benchmark(20, matrix(100, 300, TensorType.Dimension.Type.indexedUnbound), TensorType.Dimension.Type.indexedUnbound, true);
+ //System.out.printf("Indexed matrix, x space time per join: %1$8.3f ms\n", time);
// ---------------- Indexed unbound:
// Initial: 718 ms
// - After special casing join: 3.6 ms
// - After special-casing reduce: 0.80 ms
// - After create IndexedTensor without builder: 0.4 ms
- // - After double-array backing: 0.09 ms
- time = new TensorFunctionBenchmark().benchmark(50000, vectors(100, 300, TensorType.Dimension.Type.indexedUnbound), TensorType.Dimension.Type.indexedUnbound, false);
+ // - After double-array backing: 0.1 ms
+ time = new TensorFunctionBenchmark().benchmark(10000, vectors(100, 300, TensorType.Dimension.Type.indexedUnbound), TensorType.Dimension.Type.indexedUnbound, false);
System.out.printf("Indexed unbound vectors, time per join: %1$8.3f ms\n", time);
// Initial: 3500 ms
// - After special-casing subspace: 25 ms
- // - After moving to iterators: 7.7 ms
- // - After indexed subspace join algorithm: 6
- // - After passing sized: 3.7 ms
- // - After creating int tensor address: 2.5 ms
- // - After using int address to get ints directly: 0.93 ms
- time = new TensorFunctionBenchmark().benchmark(5000, matrix(100, 300, TensorType.Dimension.Type.indexedUnbound), TensorType.Dimension.Type.indexedUnbound, false);
+ // - After moving to iterators: 10 ms
+ time = new TensorFunctionBenchmark().benchmark(500, matrix(100, 300, TensorType.Dimension.Type.indexedUnbound), TensorType.Dimension.Type.indexedUnbound, false);
System.out.printf("Indexed unbound matrix, time per join: %1$8.3f ms\n", time);
// ---------------- Indexed bound:
- // Initial: 0.09 ms
- time = new TensorFunctionBenchmark().benchmark(50000, vectors(100, 300, TensorType.Dimension.Type.indexedBound), TensorType.Dimension.Type.indexedBound, false);
+ // Initial: 0.1 ms
+ time = new TensorFunctionBenchmark().benchmark(10000, vectors(100, 300, TensorType.Dimension.Type.indexedBound), TensorType.Dimension.Type.indexedBound, false);
System.out.printf("Indexed bound vectors, time per join: %1$8.3f ms\n", time);
// Initial: 25 ms
- // - After moving to iterators: 7.7 ms
- // - After indexed subspace join algorithm: 6
- // - After passing sized: 3.7 ms
- // - After creating int tensor address: 2.8 ms
- // - After using int address to get ints directly: 0.93 ms
- time = new TensorFunctionBenchmark().benchmark(5000, matrix(100, 300, TensorType.Dimension.Type.indexedBound), TensorType.Dimension.Type.indexedBound, false);
+ // - After moving to iterators: 10 ms
+ time = new TensorFunctionBenchmark().benchmark(500, matrix(100, 300, TensorType.Dimension.Type.indexedBound), TensorType.Dimension.Type.indexedBound, false);
System.out.printf("Indexed bound matrix, time per join: %1$8.3f ms\n", time);
}
diff --git a/vespajlib/src/test/java/com/yahoo/tensor/TensorTestCase.java b/vespajlib/src/test/java/com/yahoo/tensor/TensorTestCase.java
index eaf26fd82cd..aa220e93258 100644
--- a/vespajlib/src/test/java/com/yahoo/tensor/TensorTestCase.java
+++ b/vespajlib/src/test/java/com/yahoo/tensor/TensorTestCase.java
@@ -79,15 +79,11 @@ public class TensorTestCase {
@Test
public void testOptimizedComputation() {
assertEquals("Mapped vector", 42, (int)dotProduct(vector(Type.mapped), vectors(Type.mapped, 2)));
- assertEquals("Indexed unbound vector", 42, (int)dotProduct(vector(3, Type.indexedUnbound), vectors(5, Type.indexedUnbound, 2)));
- assertEquals("Indexed unbound vector", 42, (int)dotProduct(vector(5, Type.indexedUnbound), vectors(3, Type.indexedUnbound, 2)));
- assertEquals("Indexed bound vector", 42, (int)dotProduct(vector(3, Type.indexedBound), vectors(5, Type.indexedBound, 2)));
- assertEquals("Indexed bound vector", 42, (int)dotProduct(vector(5, Type.indexedBound), vectors(3, Type.indexedBound, 2)));
+ assertEquals("Indexed unbound vector", 42, (int)dotProduct(vector(Type.indexedUnbound), vectors(Type.indexedUnbound, 2)));
+ assertEquals("Indexed bound vector", 42, (int)dotProduct(vector(Type.indexedBound), vectors(Type.indexedBound, 2)));
assertEquals("Mapped matrix", 42, (int)dotProduct(vector(Type.mapped), matrix(Type.mapped, 2)));
- assertEquals("Indexed unbound matrix", 42, (int)dotProduct(vector(3, Type.indexedUnbound), matrix(5, Type.indexedUnbound, 2)));
- assertEquals("Indexed unbound matrix", 42, (int)dotProduct(vector(5, Type.indexedUnbound), matrix(3, Type.indexedUnbound, 2)));
- assertEquals("Indexed bound matrix", 42, (int)dotProduct(vector(3, Type.indexedBound), matrix(5, Type.indexedBound, 2)));
- assertEquals("Indexed bound matrix", 42, (int)dotProduct(vector(5, Type.indexedBound), matrix(3, Type.indexedBound, 2)));
+ assertEquals("Indexed unbound matrix", 42, (int)dotProduct(vector(Type.indexedUnbound), matrix(Type.indexedUnbound, 2)));
+ assertEquals("Indexed bound matrix", 42, (int)dotProduct(vector(Type.indexedBound), matrix(Type.indexedBound, 2)));
assertEquals("Mixed vector", 42, (int)dotProduct(vector(Type.mapped), vectors(Type.indexedUnbound, 2)));
assertEquals("Mixed vector", 42, (int)dotProduct(vector(Type.mapped), vectors(Type.indexedUnbound, 2)));
assertEquals("Mixed matrix", 42, (int)dotProduct(vector(Type.mapped), matrix(Type.indexedUnbound, 2)));
@@ -104,7 +100,7 @@ public class TensorTestCase {
Tensor matrixInKSpace = matrix(Type.mapped, 2).get(0).multiply(unitK);
assertEquals("Generic computation implementation", 42, (int)dotProduct(vectorInJSpace, Collections.singletonList(matrixInKSpace)));
}
-
+
private double dotProduct(Tensor tensor, List<Tensor> tensors) {
double sum = 0;
TensorFunction dotProductFunction = new Reduce(new Join(new ConstantTensor(tensor),
@@ -123,17 +119,10 @@ public class TensorTestCase {
private Tensor vector(TensorType.Dimension.Type dimensionType) {
return vectors(dimensionType, 1).get(0);
}
-
- private Tensor vector(int vectorSize, TensorType.Dimension.Type dimensionType) {
- return vectors(vectorSize, dimensionType, 1).get(0);
- }
/** Create a list of vectors having a single dimension x */
private List<Tensor> vectors(TensorType.Dimension.Type dimensionType, int vectorCount) {
- return vectors(3, dimensionType, vectorCount);
- }
-
- private List<Tensor> vectors(int vectorSize, TensorType.Dimension.Type dimensionType, int vectorCount) {
+ int vectorSize = 3;
List<Tensor> tensors = new ArrayList<>();
TensorType type = vectorType(new TensorType.Builder(), "x", dimensionType, vectorSize);
for (int i = 0; i < vectorCount; i++) {
@@ -151,10 +140,7 @@ public class TensorTestCase {
* This matrix contains the same vectors as returned by createVectors, in a single list element for convenience.
*/
private List<Tensor> matrix(TensorType.Dimension.Type dimensionType, int vectorCount) {
- return matrix(3, dimensionType, vectorCount);
- }
-
- private List<Tensor> matrix(int vectorSize, TensorType.Dimension.Type dimensionType, int vectorCount) {
+ int vectorSize = 3;
TensorType.Builder typeBuilder = new TensorType.Builder();
typeBuilder.dimension("i", dimensionType == Type.indexedBound ? Type.indexedUnbound : dimensionType);
vectorType(typeBuilder, "x", dimensionType, vectorSize);