diff options
author | Henning Baldersheim <balder@yahoo-inc.com> | 2024-01-28 19:28:42 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-28 19:28:42 +0100 |
commit | 6992a234c6e474dbe95e446bd1cdc50bdb452414 (patch) | |
tree | 17abc9faf9e43147ee195b0dbe9259eb361b3a6d | |
parent | 140ed00756d8b45ee622fdd61d2df91dd133133a (diff) | |
parent | c824e1209fdd979612ccead027889eb6294b4652 (diff) |
Merge pull request #30084 from vespa-engine/bratseth/tensor-cleanupv8.294.50
Minor cleanup
23 files changed, 187 insertions, 112 deletions
diff --git a/container-search/src/main/java/com/yahoo/fs4/MapEncoder.java b/container-search/src/main/java/com/yahoo/fs4/MapEncoder.java index 84b2b482403..4f31db0fc86 100644 --- a/container-search/src/main/java/com/yahoo/fs4/MapEncoder.java +++ b/container-search/src/main/java/com/yahoo/fs4/MapEncoder.java @@ -20,7 +20,7 @@ public class MapEncoder { // TODO: Time to refactor - private static byte [] getUtf8(Object value) { + private static byte[] getUtf8(Object value) { if (value == null) { return Utf8.toBytes(""); } else if (value instanceof Tensor) { @@ -62,7 +62,7 @@ public class MapEncoder { public static int encodeMap(String mapName, Map<String,?> map, ByteBuffer buffer) { if (map.isEmpty()) return 0; - byte [] utf8 = Utf8.toBytes(mapName); + byte[] utf8 = Utf8.toBytes(mapName); buffer.putInt(utf8.length); buffer.put(utf8); buffer.putInt(map.size()); diff --git a/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java b/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java index 441c4326355..88cc7ad7b2d 100644 --- a/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java +++ b/container-search/src/main/java/com/yahoo/prelude/cluster/ClusterSearcher.java @@ -172,6 +172,21 @@ public class ClusterSearcher extends Searcher { } @Override + public Result search(Query query, Execution execution) { + validateQueryTimeout(query); + validateQueryCache(query); + Searcher searcher = server; + if (searcher == null) { + return new Result(query, ErrorMessage.createNoBackendsInService("Could not search")); + } + if (query.getTimeLeft() <= 0) { + return new Result(query, ErrorMessage.createTimeout("No time left for searching")); + } + + return doSearch(searcher, query, execution); + } + + @Override public void fill(com.yahoo.search.Result result, String summaryClass, Execution execution) { Query query = result.getQuery(); @@ -192,21 +207,6 @@ public class ClusterSearcher extends Searcher { } } - @Override - public Result search(Query query, Execution execution) { - validateQueryTimeout(query); - validateQueryCache(query); - Searcher searcher = server; - if (searcher == null) { - return new Result(query, ErrorMessage.createNoBackendsInService("Could not search")); - } - if (query.getTimeLeft() <= 0) { - return new Result(query, ErrorMessage.createTimeout("No time left for searching")); - } - - return doSearch(searcher, query, execution); - } - private void validateQueryTimeout(Query query) { if (query.getTimeout() <= maxQueryTimeout) return; diff --git a/container-search/src/main/java/com/yahoo/search/query/ranking/RankProperties.java b/container-search/src/main/java/com/yahoo/search/query/ranking/RankProperties.java index 4ac5375807b..fd0b6543f28 100644 --- a/container-search/src/main/java/com/yahoo/search/query/ranking/RankProperties.java +++ b/container-search/src/main/java/com/yahoo/search/query/ranking/RankProperties.java @@ -38,16 +38,12 @@ public class RankProperties implements Cloneable { /** Adds a property by full name to a value */ public void put(String name, Object value) { - List<Object> list = properties.get(name); - if (list == null) { - list = new ArrayList<>(); - properties.put(name, list); - } + List<Object> list = properties.computeIfAbsent(name, k -> new ArrayList<>()); list.add(value); } /** - * Returns a read-only list of properties properties by full name. + * Returns a read-only list of properties by full name. * If this is not set, null is returned. If this is explicitly set to * have no values, and empty list is returned. */ diff --git a/vespajlib/abi-spec.json b/vespajlib/abi-spec.json index 1f44d90f924..452b2dc0da9 100644 --- a/vespajlib/abi-spec.json +++ b/vespajlib/abi-spec.json @@ -1266,7 +1266,7 @@ "public static com.yahoo.tensor.Tensor from(double)" ], "fields" : [ - "public static final int INVALID_INDEX" + "public static final int invalidIndex" ] }, "com.yahoo.tensor.TensorAddress$Builder" : { @@ -1324,7 +1324,7 @@ "public static java.lang.String labelToString(java.lang.String)", "public com.yahoo.tensor.TensorAddress partialCopy(int[])", "public com.yahoo.tensor.TensorAddress fullAddressOf(java.util.List, int[])", - "public com.yahoo.tensor.TensorAddress sparsePartialAddress(com.yahoo.tensor.TensorType, java.util.List)", + "public com.yahoo.tensor.TensorAddress mappedPartialAddress(com.yahoo.tensor.TensorType, java.util.List)", "public bridge synthetic int compareTo(java.lang.Object)" ], "fields" : [ ] diff --git a/vespajlib/src/main/java/com/yahoo/tensor/DirectIndexedAddress.java b/vespajlib/src/main/java/com/yahoo/tensor/DirectIndexedAddress.java index 37752361876..4379d50520c 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/DirectIndexedAddress.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/DirectIndexedAddress.java @@ -7,19 +7,25 @@ package com.yahoo.tensor; * long stride = addr.getStride(dimension) * i = 0...size_of_dimension * double value = tensor.get(base + i * stride); + * + * @author baldersheim */ public final class DirectIndexedAddress { + private final DimensionSizes sizes; - private final int [] indexes; + private final int[] indexes; private long directIndex; + private DirectIndexedAddress(DimensionSizes sizes) { this.sizes = sizes; indexes = new int[sizes.dimensions()]; directIndex = 0; } + static DirectIndexedAddress of(DimensionSizes sizes) { return new DirectIndexedAddress(sizes); } + /** Sets the current index of a dimension */ public void setIndex(int dimension, int index) { if (index < 0 || index >= sizes.size(dimension)) { @@ -29,10 +35,13 @@ public final class DirectIndexedAddress { directIndex += getStride(dimension) * diff; indexes[dimension] = index; } + /** Retrieve the index that can be used for direct lookup in an indexed tensor. */ public long getDirectIndex() { return directIndex; } + /** returns the stride to be used for the given dimension */ public long getStride(int dimension) { return sizes.productOfDimensionsAfter(dimension); } + } diff --git a/vespajlib/src/main/java/com/yahoo/tensor/IndexedDoubleTensor.java b/vespajlib/src/main/java/com/yahoo/tensor/IndexedDoubleTensor.java index 085f9172095..53f50fc4d02 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/IndexedDoubleTensor.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/IndexedDoubleTensor.java @@ -78,9 +78,6 @@ class IndexedDoubleTensor extends IndexedTensor { @Override public Builder cell(TensorAddress address, double value) { - if (address == null) { - return null; - } values[(int)toValueIndex(address, sizes(), type)] = value; return this; } diff --git a/vespajlib/src/main/java/com/yahoo/tensor/IndexedTensor.java b/vespajlib/src/main/java/com/yahoo/tensor/IndexedTensor.java index a428524612b..fc0473c635a 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/IndexedTensor.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/IndexedTensor.java @@ -172,7 +172,7 @@ public abstract class IndexedTensor implements Tensor { static long toValueIndex(TensorAddress address, DimensionSizes sizes, TensorType type) { long valueIndex = 0; - for (int i = 0, sz = address.size(); i < sz; i++) { + for (int i = 0, size = address.size(); i < size; i++) { long label = address.numericLabel(i); if (label >= sizes.size(i)) throw new IllegalArgumentException(address + " is not within the bounds of " + type); @@ -1058,7 +1058,7 @@ public abstract class IndexedTensor implements Tensor { /** In this case we can reuse the source index computation for the iteration index */ private final static class EqualSizeMultiDimensionIndexes extends MultiDimensionIndexes { - private long lastComputedSourceValueIndex = Tensor.INVALID_INDEX; + private long lastComputedSourceValueIndex = Tensor.invalidIndex; private EqualSizeMultiDimensionIndexes(DimensionSizes sizes, List<Integer> iterateDimensions, long[] initialIndexes, long size) { super(sizes, sizes, iterateDimensions, initialIndexes, size); diff --git a/vespajlib/src/main/java/com/yahoo/tensor/MixedTensor.java b/vespajlib/src/main/java/com/yahoo/tensor/MixedTensor.java index d4469f447cb..65c6677e7e3 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/MixedTensor.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/MixedTensor.java @@ -107,27 +107,30 @@ public class MixedTensor implements Tensor { @Override public Iterator<Cell> cellIterator() { return new Iterator<>() { + final Iterator<DenseSubspace> blockIterator = index.denseSubspaces.iterator(); - DenseSubspace currBlock = null; final int[] labels = new int[index.indexedDimensions.size()]; + DenseSubspace currentBlock = null; int currOffset = index.denseSubspaceSize; int prevOffset = -1; + @Override public boolean hasNext() { return (currOffset < index.denseSubspaceSize || blockIterator.hasNext()); } + @Override public Cell next() { if (currOffset == index.denseSubspaceSize) { - currBlock = blockIterator.next(); + currentBlock = blockIterator.next(); currOffset = 0; } if (currOffset != prevOffset) { // Optimization for index.denseSubspaceSize == 1 index.denseOffsetToAddress(currOffset, labels); } - TensorAddress fullAddr = currBlock.sparseAddress.fullAddressOf(index.type.dimensions(), labels); + TensorAddress fullAddr = currentBlock.sparseAddress.fullAddressOf(index.type.dimensions(), labels); prevOffset = currOffset; - double value = currBlock.cells[currOffset++]; + double value = currentBlock.cells[currOffset++]; return new Cell(fullAddr, value); } }; @@ -140,20 +143,23 @@ public class MixedTensor implements Tensor { @Override public Iterator<Double> valueIterator() { return new Iterator<>() { + final Iterator<DenseSubspace> blockIterator = index.denseSubspaces.iterator(); - double[] currBlock = null; + double[] currentBlock = null; int currOffset = index.denseSubspaceSize; + @Override public boolean hasNext() { return (currOffset < index.denseSubspaceSize || blockIterator.hasNext()); } + @Override public Double next() { if (currOffset == index.denseSubspaceSize) { - currBlock = blockIterator.next().cells; + currentBlock = blockIterator.next().cells; currOffset = 0; } - return currBlock[currOffset++]; + return currentBlock[currOffset++]; } }; } @@ -319,7 +325,7 @@ public class MixedTensor implements Tensor { @Override public Tensor.Builder cell(TensorAddress address, double value) { - TensorAddress sparsePart = address.sparsePartialAddress(index.sparseType, index.type.dimensions()); + TensorAddress sparsePart = address.mappedPartialAddress(index.sparseType, index.type.dimensions()); int denseOffset = index.denseOffsetOf(address); double[] denseSubspace = denseSubspace(sparsePart); denseSubspace[denseOffset] = value; @@ -438,7 +444,7 @@ public class MixedTensor implements Tensor { private final TensorType denseType; private final List<TensorType.Dimension> mappedDimensions; private final List<TensorType.Dimension> indexedDimensions; - private final int [] indexedDimensionsSize; + private final int[] indexedDimensionsSize; private ImmutableMap<TensorAddress, Integer> sparseMap; private List<DenseSubspace> denseSubspaces; @@ -473,7 +479,7 @@ public class MixedTensor implements Tensor { } private DenseSubspace blockOf(TensorAddress address) { - TensorAddress sparsePart = address.sparsePartialAddress(sparseType, type.dimensions()); + TensorAddress sparsePart = address.mappedPartialAddress(sparseType, type.dimensions()); Integer blockNum = sparseMap.get(sparsePart); if (blockNum == null || blockNum >= denseSubspaces.size()) { return null; diff --git a/vespajlib/src/main/java/com/yahoo/tensor/PartialAddress.java b/vespajlib/src/main/java/com/yahoo/tensor/PartialAddress.java index da643d8c173..8852bcd1ff3 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/PartialAddress.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/PartialAddress.java @@ -4,13 +4,13 @@ package com.yahoo.tensor; import com.yahoo.tensor.impl.Label; /** - * An address to a subset of a tensors' cells, specifying a label for some but not necessarily all of the tensors + * An address to a subset of a tensors' cells, specifying a label for some, but not necessarily all, of the tensors * dimensions. * * @author bratseth */ // Implementation notes: -// - These are created in inner (though not inner-most) loops so they are implemented with minimal allocation. +// - These are created in inner (though not innermost) loops, so they are implemented with minimal allocation. // We also avoid non-essential error checking. // - We can add support for string labels later without breaking the API public class PartialAddress { @@ -36,7 +36,7 @@ public class PartialAddress { for (int i = 0; i < dimensionNames.length; i++) if (dimensionNames[i].equals(dimensionName)) return labels[i]; - return Tensor.INVALID_INDEX; + return Tensor.invalidIndex; } /** Returns the label of this dimension, or null if no label is specified for it */ @@ -68,7 +68,7 @@ public class PartialAddress { long[] numericLabels = new long[labels.length]; for (int i = 0; i < type.dimensions().size(); i++) { long label = numericLabel(type.dimensions().get(i).name()); - if (label == Tensor.INVALID_INDEX) + if (label == Tensor.invalidIndex) throw new IllegalArgumentException(type + " dimension names does not match " + this); numericLabels[i] = label; } diff --git a/vespajlib/src/main/java/com/yahoo/tensor/Tensor.java b/vespajlib/src/main/java/com/yahoo/tensor/Tensor.java index d650b88f202..ac9dc4e4eca 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/Tensor.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/Tensor.java @@ -40,7 +40,7 @@ import static com.yahoo.tensor.functions.ScalarFunctions.Hamming; * A multidimensional array which can be used in computations. * <p> * A tensor consists of a set of <i>dimension</i> names and a set of <i>cells</i> containing scalar <i>values</i>. - * Each cell is is identified by its <i>address</i>, which consists of a set of dimension-label pairs which defines + * Each cell is identified by its <i>address</i>, which consists of a set of dimension-label pairs which defines * the location of that cell. Both dimensions and labels are string on the form of an identifier or integer. * <p> * The size of the set of dimensions of a tensor is called its <i>rank</i>. @@ -55,7 +55,9 @@ import static com.yahoo.tensor.functions.ScalarFunctions.Hamming; * @author bratseth */ public interface Tensor { - int INVALID_INDEX = -1; + + /** The constant signaling a nonexisting value in operations addressing tensor values by index. */ + int invalidIndex = -1; // ----------------- Accessors @@ -65,25 +67,24 @@ public interface Tensor { default boolean isEmpty() { return size() == 0; } /** - * Returns the number of cells in this. - * Allows for very large tensors, but if you only handle size in the int range - * prefer sizeAsInt(). - **/ + * Returns the number of cells in this, allowing for very large tensors. + * Prefer sizeAsInt in implementations that cannot handle sizes outside the int range. + */ default long size() { return sizeAsInt(); } /** - * Safe way to get size as an int and detect when not possible. - * Prefer this over size() as - * @return size() as an int + * Returns the size of this as an int or throws an exception if it is too large to fit in an int. + * Prefer this over size() with implementations that only handle sizes in the int range. + * + * @throws IndexOutOfBoundsException if the size is too large to fit in an int */ default int sizeAsInt() { - long sz = size(); - if (sz > Integer.MAX_VALUE) { - throw new IndexOutOfBoundsException("size = " + sz + ", which is too large to fit in an int"); - } - return (int) sz; + long size = size(); + if (size > Integer.MAX_VALUE) + throw new IndexOutOfBoundsException("size = " + size + ", which is too large to fit in an int"); + return (int) size; } /** Returns the value of a cell, or 0.0 if this cell does not exist */ @@ -91,7 +92,8 @@ public interface Tensor { /** Returns true if this cell exists */ boolean has(TensorAddress address); - /** null = no value present. More efficient that if (t.has(key)) t.get(key) */ + + /** Returns the value at this address, or null of it does not exist. */ Double getAsDouble(TensorAddress address); /** @@ -132,7 +134,7 @@ public interface Tensor { /** * Returns a new tensor where existing cells in this tensor have been * modified according to the given operation and cells in the given map. - * Cells in the map outside of existing cells are thus ignored. + * Cells in the map outside existing cells are thus ignored. * * @param op the modifying function * @param cells the cells to modify @@ -151,9 +153,9 @@ public interface Tensor { /** * Returns a new tensor where existing cells in this tensor have been - * removed according to the given set of addresses. Only valid for sparse + * removed according to the given set of addresses. Only valid for mapped * or mixed tensors. For mixed tensors, addresses are assumed to only - * contain the sparse dimensions, as the entire dense subspace is removed. + * contain the mapped dimensions, as the entire indexed subspace is removed. * * @param addresses list of addresses to remove * @return a new tensor where cells have been removed @@ -503,11 +505,10 @@ public interface Tensor { public TensorAddress getKey() { return address; } /** - * Returns the direct index which can be used to locate this cell, or -1 if not available. - * This is for optimizations mapping between tensors where this is possible without creating a - * TensorAddress. + * Returns the direct index which can be used to locate this cell, or Tensor.invalidIndex if not available. + * This is for optimizations mapping between tensors where this is possible without creating a TensorAddress. */ - long getDirectIndex() { return INVALID_INDEX; } + long getDirectIndex() { return invalidIndex; } /** Returns the value as a double */ @Override diff --git a/vespajlib/src/main/java/com/yahoo/tensor/TensorAddress.java b/vespajlib/src/main/java/com/yahoo/tensor/TensorAddress.java index 59a5e2a49b1..5c2c4d77fad 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/TensorAddress.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/TensorAddress.java @@ -32,9 +32,7 @@ public abstract class TensorAddress implements Comparable<TensorAddress> { return TensorAddressAny.of(labels); } - /** - * Returns the number of labels in this - */ + /** Returns the number of labels in this */ public abstract int size(); /** @@ -69,10 +67,10 @@ public abstract class TensorAddress implements Comparable<TensorAddress> { @Override public String toString() { StringBuilder sb = new StringBuilder("cell address ("); - int sz = size(); - if (sz > 0) { + int size = size(); + if (size > 0) { sb.append(label(0)); - for (int i = 1; i < sz; i++) { + for (int i = 1; i < size; i++) { sb.append(',').append(label(i)); } } @@ -113,9 +111,9 @@ public abstract class TensorAddress implements Comparable<TensorAddress> { return TensorAddressAny.ofUnsafe(labels); } - /** Creates a complete address by taking the sparse dimmensions from this and the indexed from the densePart */ - public TensorAddress fullAddressOf(List<TensorType.Dimension> dimensions, int [] densePart) { - int [] labels = new int[dimensions.size()]; + /** Creates a complete address by taking the mapped dimmensions from this and the indexed from the indexedPart */ + public TensorAddress fullAddressOf(List<TensorType.Dimension> dimensions, int[] densePart) { + int[] labels = new int[dimensions.size()]; int mappedIndex = 0; int indexedIndex = 0; for (int i = 0; i < labels.length; i++) { @@ -131,11 +129,17 @@ public abstract class TensorAddress implements Comparable<TensorAddress> { return TensorAddressAny.ofUnsafe(labels); } - /** Extracts the sparse(non-indexed) dimensions of the address */ - public TensorAddress sparsePartialAddress(TensorType sparseType, List<TensorType.Dimension> dimensions) { + /** + * Returns an address containing the mapped dimensions of this. + * + * @param mappedType the type of the mapped subset of the type this is an address of; + * which is also the type of the returned address + * @param dimensions all the dimensions of the type this is an address of + */ + public TensorAddress mappedPartialAddress(TensorType mappedType, List<TensorType.Dimension> dimensions) { if (dimensions.size() != size()) throw new IllegalArgumentException("Tensor type of " + this + " is not the same size as " + this); - TensorAddress.Builder builder = new TensorAddress.Builder(sparseType); + TensorAddress.Builder builder = new TensorAddress.Builder(mappedType); for (int i = 0; i < dimensions.size(); ++i) { TensorType.Dimension dimension = dimensions.get(i); if ( ! dimension.isIndexed()) @@ -150,9 +154,9 @@ public abstract class TensorAddress implements Comparable<TensorAddress> { final TensorType type; final int[] labels; - private static int [] createEmptyLabels(int size) { - int [] labels = new int[size]; - Arrays.fill(labels, Tensor.INVALID_INDEX); + private static int[] createEmptyLabels(int size) { + int[] labels = new int[size]; + Arrays.fill(labels, Tensor.invalidIndex); return labels; } @@ -174,7 +178,7 @@ public abstract class TensorAddress implements Comparable<TensorAddress> { var mappedSubtype = type.mappedSubtype(); if (mappedSubtype.rank() != 1) throw new IllegalArgumentException("Cannot add a label without explicit dimension to a tensor of type " + - type + ": Must have exactly one sparse dimension"); + type + ": Must have exactly one mapped dimension"); add(mappedSubtype.dimensions().get(0).name(), label); return this; } @@ -212,7 +216,7 @@ public abstract class TensorAddress implements Comparable<TensorAddress> { void validate() { for (int i = 0; i < labels.length; i++) - if (labels[i] == Tensor.INVALID_INDEX) + if (labels[i] == Tensor.invalidIndex) throw new IllegalArgumentException("Missing a label for dimension '" + type.dimensions().get(i).name() + "' for " + type); } diff --git a/vespajlib/src/main/java/com/yahoo/tensor/TensorType.java b/vespajlib/src/main/java/com/yahoo/tensor/TensorType.java index 62ed4ad683c..6b81d023a9a 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/TensorType.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/TensorType.java @@ -204,7 +204,7 @@ public class TensorType { for (int i = 0; i < dimensions.size(); i++) if (dimensions.get(i).name().equals(dimension)) return i; - return Tensor.INVALID_INDEX; + return Tensor.invalidIndex; } /* Returns the bound of this dimension if it is present and bound in this, empty otherwise */ diff --git a/vespajlib/src/main/java/com/yahoo/tensor/functions/Concat.java b/vespajlib/src/main/java/com/yahoo/tensor/functions/Concat.java index 37ca7f979a1..dcfba5ecfad 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/functions/Concat.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/functions/Concat.java @@ -172,7 +172,7 @@ public class Concat<NAMETYPE extends Name> extends PrimitiveTensorFunction<NAMET private TensorAddress combineAddresses(TensorAddress a, int[] aToIndexes, TensorAddress b, int[] bToIndexes, TensorType concatType, long concatOffset, String concatDimension) { long[] combinedLabels = new long[concatType.dimensions().size()]; - Arrays.fill(combinedLabels, Tensor.INVALID_INDEX); + Arrays.fill(combinedLabels, Tensor.invalidIndex); int concatDimensionIndex = concatType.indexOfDimension(concatDimension).get(); mapContent(a, combinedLabels, aToIndexes, concatDimensionIndex, concatOffset); // note: This sets a nonsensical value in the concat dimension boolean compatible = mapContent(b, combinedLabels, bToIndexes, concatDimensionIndex, concatOffset); // ... which is overwritten by the right value here @@ -191,7 +191,7 @@ public class Concat<NAMETYPE extends Name> extends PrimitiveTensorFunction<NAMET private int[] mapIndexes(TensorType fromType, TensorType toType) { int[] toIndexes = new int[fromType.dimensions().size()]; for (int i = 0; i < fromType.dimensions().size(); i++) - toIndexes[i] = toType.indexOfDimension(fromType.dimensions().get(i).name()).orElse(Tensor.INVALID_INDEX); + toIndexes[i] = toType.indexOfDimension(fromType.dimensions().get(i).name()).orElse(Tensor.invalidIndex); return toIndexes; } @@ -208,7 +208,7 @@ public class Concat<NAMETYPE extends Name> extends PrimitiveTensorFunction<NAMET to[toIndex] = from.numericLabel(i) + concatOffset; } else { - if (to[toIndex] != Tensor.INVALID_INDEX && to[toIndex] != from.numericLabel(i)) return false; + if (to[toIndex] != Tensor.invalidIndex && to[toIndex] != from.numericLabel(i)) return false; to[toIndex] = from.numericLabel(i); } } 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 047d8ee6ef0..14adcc8f18a 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/functions/Join.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/functions/Join.java @@ -378,7 +378,7 @@ public class Join<NAMETYPE extends Name> extends PrimitiveTensorFunction<NAMETYP private static TensorAddress joinAddresses(TensorAddress a, int[] aToIndexes, TensorAddress b, int[] bToIndexes, TensorType joinedType) { int[] joinedLabels = new int[joinedType.dimensions().size()]; - Arrays.fill(joinedLabels, Tensor.INVALID_INDEX); + Arrays.fill(joinedLabels, Tensor.invalidIndex); mapContent(a, joinedLabels, aToIndexes); boolean compatible = mapContent(b, joinedLabels, bToIndexes); if ( ! compatible) return null; @@ -392,10 +392,10 @@ public class Join<NAMETYPE extends Name> extends PrimitiveTensorFunction<NAMETYP * occupied by a different value */ private static boolean mapContent(TensorAddress from, int[] to, int[] indexMap) { - for (int i = 0, sz = from.size(); i < sz; i++) { + for (int i = 0, size = from.size(); i < size; i++) { int toIndex = indexMap[i]; int label = Convert.safe2Int(from.numericLabel(i)); - if (to[toIndex] != Tensor.INVALID_INDEX && to[toIndex] != label) + if (to[toIndex] != Tensor.invalidIndex && to[toIndex] != label) return false; to[toIndex] = label; } diff --git a/vespajlib/src/main/java/com/yahoo/tensor/impl/Label.java b/vespajlib/src/main/java/com/yahoo/tensor/impl/Label.java index 0ab1454eb58..a09c0223d28 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/impl/Label.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/impl/Label.java @@ -7,16 +7,26 @@ import java.util.Arrays; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +/** + * A label is a value of a mapped dimension of a tensor. + * This class provides a mapping of labels to numbers which allow for more efficient computation with + * mapped tensor dimensions. + * + * @author baldersheim + */ public class Label { - private static final String [] SMALL_INDEXES = createSmallIndexesAsStrings(1000); + + private static final String[] SMALL_INDEXES = createSmallIndexesAsStrings(1000); + private final static Map<String, Integer> string2Enum = new ConcurrentHashMap<>(); + // Index 0 is unused, that is a valid positive number // 1(-1) is reserved for the Tensor.INVALID_INDEX - private static volatile String [] uniqueStrings = {"UNIQUE_UNUSED_MAGIC", "Tensor.INVALID_INDEX"}; + private static volatile String[] uniqueStrings = {"UNIQUE_UNUSED_MAGIC", "Tensor.INVALID_INDEX"}; private static int numUniqeStrings = 2; private static String[] createSmallIndexesAsStrings(int count) { - String [] asStrings = new String[count]; + String[] asStrings = new String[count]; for (int i = 0; i < count; i++) { asStrings[i] = String.valueOf(i); } @@ -46,7 +56,7 @@ public class Label { } public static int toNumber(String s) { - if (s == null) { return Tensor.INVALID_INDEX; } + if (s == null) { return Tensor.invalidIndex; } try { if (validNumericIndex(s)) { return Integer.parseInt(s); @@ -55,14 +65,16 @@ public class Label { } return string2Enum.computeIfAbsent(s, Label::addNewUniqueString); } + public static String fromNumber(int v) { if (v >= 0) { return asNumericString(v); } else { - if (v == Tensor.INVALID_INDEX) { return null; } + if (v == Tensor.invalidIndex) { return null; } return uniqueStrings[-v]; } } + public static String fromNumber(long v) { return fromNumber(Convert.safe2Int(v)); } diff --git a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny.java b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny.java index 31863c99a74..2e70811a67c 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny.java @@ -18,6 +18,7 @@ import static com.yahoo.tensor.impl.Label.fromNumber; * @author baldersheim */ abstract public class TensorAddressAny extends TensorAddress { + @Override public String label(int i) { return fromNumber((int)numericLabel(i)); @@ -26,37 +27,47 @@ abstract public class TensorAddressAny extends TensorAddress { public static TensorAddress of() { return TensorAddressEmpty.empty; } + public static TensorAddress of(String label) { return new TensorAddressAny1(toNumber(label)); } + public static TensorAddress of(String label0, String label1) { return new TensorAddressAny2(toNumber(label0), toNumber(label1)); } + public static TensorAddress of(String label0, String label1, String label2) { return new TensorAddressAny3(toNumber(label0), toNumber(label1), toNumber(label2)); } + public static TensorAddress of(String label0, String label1, String label2, String label3) { return new TensorAddressAny4(toNumber(label0), toNumber(label1), toNumber(label2), toNumber(label3)); } - public static TensorAddress of(String [] labels) { - int [] labelsAsInt = new int[labels.length]; + + public static TensorAddress of(String[] labels) { + int[] labelsAsInt = new int[labels.length]; for (int i = 0; i < labels.length; i++) { labelsAsInt[i] = toNumber(labels[i]); } return ofUnsafe(labelsAsInt); } + public static TensorAddress of(int label) { return new TensorAddressAny1(sanitize(label)); } + public static TensorAddress of(int label0, int label1) { return new TensorAddressAny2(sanitize(label0), sanitize(label1)); } + public static TensorAddress of(int label0, int label1, int label2) { return new TensorAddressAny3(sanitize(label0), sanitize(label1), sanitize(label2)); } + public static TensorAddress of(int label0, int label1, int label2, int label3) { return new TensorAddressAny4(sanitize(label0), sanitize(label1), sanitize(label2), sanitize(label3)); } + public static TensorAddress of(int ... labels) { return switch (labels.length) { case 0 -> of(); @@ -72,6 +83,7 @@ abstract public class TensorAddressAny extends TensorAddress { } }; } + public static TensorAddress of(long label) { return of(safe2Int(label)); } @@ -96,7 +108,7 @@ abstract public class TensorAddressAny extends TensorAddress { case 3 -> ofUnsafe(safe2Int(labels[0]), safe2Int(labels[1]), safe2Int(labels[2])); case 4 -> ofUnsafe(safe2Int(labels[0]), safe2Int(labels[1]), safe2Int(labels[2]), safe2Int(labels[3])); default -> { - int [] labelsAsInt = new int[labels.length]; + int[] labelsAsInt = new int[labels.length]; for (int i = 0; i < labels.length; i++) { labelsAsInt[i] = safe2Int(labels[i]); } @@ -108,15 +120,19 @@ abstract public class TensorAddressAny extends TensorAddress { private static TensorAddress ofUnsafe(int label) { return new TensorAddressAny1(label); } + private static TensorAddress ofUnsafe(int label0, int label1) { return new TensorAddressAny2(label0, label1); } + private static TensorAddress ofUnsafe(int label0, int label1, int label2) { return new TensorAddressAny3(label0, label1, label2); } + private static TensorAddress ofUnsafe(int label0, int label1, int label2, int label3) { return new TensorAddressAny4(label0, label1, label2, label3); } + public static TensorAddress ofUnsafe(int ... labels) { return switch (labels.length) { case 0 -> of(); @@ -127,10 +143,12 @@ abstract public class TensorAddressAny extends TensorAddress { default -> new TensorAddressAnyN(labels); }; } + private static int sanitize(int label) { - if (label < Tensor.INVALID_INDEX) { + if (label < Tensor.invalidIndex) { throw new IndexOutOfBoundsException("cell label " + label + " must be positive"); } return label; } + } diff --git a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny1.java b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny1.java index a2b0d318a50..a9be6173781 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny1.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny1.java @@ -5,11 +5,14 @@ package com.yahoo.tensor.impl; import com.yahoo.tensor.TensorAddress; /** - * Single dimension + * A one-dimensional address. + * * @author baldersheim */ final class TensorAddressAny1 extends TensorAddressAny { + private final int label; + TensorAddressAny1(int label) { this.label = label; } @Override public int size() { return 1; } @@ -34,4 +37,5 @@ final class TensorAddressAny1 extends TensorAddressAny { public boolean equals(Object o) { return (o instanceof TensorAddressAny1 any) && (label == any.label); } + } diff --git a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny2.java b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny2.java index d77a689852f..43f65d495cf 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny2.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny2.java @@ -7,11 +7,14 @@ import com.yahoo.tensor.TensorAddress; import static java.lang.Math.abs; /** - * 2 dimensional address + * A two-dimensional address. + * * @author baldersheim */ final class TensorAddressAny2 extends TensorAddressAny { + private final int label0, label1; + TensorAddressAny2(int label0, int label1) { this.label0 = label0; this.label1 = label1; @@ -46,4 +49,5 @@ final class TensorAddressAny2 extends TensorAddressAny { public boolean equals(Object o) { return (o instanceof TensorAddressAny2 any) && (label0 == any.label0) && (label1 == any.label1); } + } diff --git a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny3.java b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny3.java index 95e14bd375c..c22ff47b3c4 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny3.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny3.java @@ -7,11 +7,14 @@ import com.yahoo.tensor.TensorAddress; import static java.lang.Math.abs; /** - * 3 dimensional address + * A three-dimensional address. + * * @author baldersheim */ final class TensorAddressAny3 extends TensorAddressAny { + private final int label0, label1, label2; + TensorAddressAny3(int label0, int label1, int label2) { this.label0 = label0; this.label1 = label1; @@ -54,4 +57,5 @@ final class TensorAddressAny3 extends TensorAddressAny { (label1 == any.label1) && (label2 == any.label2); } + } diff --git a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny4.java b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny4.java index 8a45483340e..6eb6b9216bf 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny4.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAny4.java @@ -7,11 +7,14 @@ import com.yahoo.tensor.TensorAddress; import static java.lang.Math.abs; /** - * 4 dimensional address + * A four-dimensional address. + * * @author baldersheim */ final class TensorAddressAny4 extends TensorAddressAny { + private final int label0, label1, label2, label3; + TensorAddressAny4(int label0, int label1, int label2, int label3) { this.label0 = label0; this.label1 = label1; @@ -59,4 +62,5 @@ final class TensorAddressAny4 extends TensorAddressAny { (label2 == any.label2) && (label3 == any.label3); } + } diff --git a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAnyN.java b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAnyN.java index acd7ed60722..d5bac62bf18 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAnyN.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressAnyN.java @@ -9,22 +9,26 @@ import java.util.Arrays; import static java.lang.Math.abs; /** - * N dimensional address + * An n-dimensional address. + * * @author baldersheim */ final class TensorAddressAnyN extends TensorAddressAny { - private final int [] labels; - TensorAddressAnyN(int [] labels) { + + private final int[] labels; + + TensorAddressAnyN(int[] labels) { if (labels.length < 1) throw new IllegalArgumentException("Need at least 1 label"); this.labels = labels; } @Override public int size() { return labels.length; } + @Override public long numericLabel(int i) { return labels[i]; } @Override public TensorAddress withLabel(int labelIndex, long label) { - int [] copy = Arrays.copyOf(labels, labels.length); + int[] copy = Arrays.copyOf(labels, labels.length); copy[labelIndex] = Convert.safe2Int(label); return new TensorAddressAnyN(copy); } @@ -45,4 +49,5 @@ final class TensorAddressAnyN extends TensorAddressAny { } return true; } + } diff --git a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressEmpty.java b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressEmpty.java index 2d9cd3eed78..eb7e62e913b 100644 --- a/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressEmpty.java +++ b/vespajlib/src/main/java/com/yahoo/tensor/impl/TensorAddressEmpty.java @@ -5,13 +5,18 @@ package com.yahoo.tensor.impl; import com.yahoo.tensor.TensorAddress; /** - * 0 dimesional/empty address + * A zero-dimensional address. + * * @author baldersheim */ final class TensorAddressEmpty extends TensorAddressAny { + static TensorAddress empty = new TensorAddressEmpty(); + private TensorAddressEmpty() {} + @Override public int size() { return 0; } + @Override public long numericLabel(int i) { throw new IllegalArgumentException("Empty address with no labels"); } @Override @@ -21,6 +26,8 @@ final class TensorAddressEmpty extends TensorAddressAny { @Override public int hashCode() { return 0; } + @Override public boolean equals(Object o) { return o instanceof TensorAddressEmpty; } + } diff --git a/vespajlib/src/test/java/com/yahoo/tensor/impl/TensorAddressAnyTestCase.java b/vespajlib/src/test/java/com/yahoo/tensor/impl/TensorAddressAnyTestCase.java index ae13b95052b..18ff1f6a1d3 100644 --- a/vespajlib/src/test/java/com/yahoo/tensor/impl/TensorAddressAnyTestCase.java +++ b/vespajlib/src/test/java/com/yahoo/tensor/impl/TensorAddressAnyTestCase.java @@ -6,11 +6,15 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; +/** + * @author baldersheim + */ public class TensorAddressAnyTestCase { + @Test void testSize() { for (int i = 0; i < 10; i++) { - int [] indexes = new int [i]; + int[] indexes = new int[i]; assertEquals(i, of(indexes).size()); } } @@ -18,8 +22,8 @@ public class TensorAddressAnyTestCase { @Test void testNumericStringEquality() { for (int i = 0; i < 10; i++) { - int [] numericIndexes = new int [i]; - String [] stringIndexes = new String[i]; + int[] numericIndexes = new int[i]; + String[] stringIndexes = new String[i]; for (int j = 0; j < i; j++) { numericIndexes[j] = j; stringIndexes[j] = String.valueOf(j); |