From c824e1209fdd979612ccead027889eb6294b4652 Mon Sep 17 00:00:00 2001 From: Jon Bratseth Date: Sun, 28 Jan 2024 18:38:47 +0100 Subject: Minor cleanup --- .../src/main/java/com/yahoo/fs4/MapEncoder.java | 4 +- .../com/yahoo/prelude/cluster/ClusterSearcher.java | 30 +++++++-------- .../yahoo/search/query/ranking/RankProperties.java | 8 +--- vespajlib/abi-spec.json | 4 +- .../com/yahoo/tensor/DirectIndexedAddress.java | 11 +++++- .../java/com/yahoo/tensor/IndexedDoubleTensor.java | 3 -- .../main/java/com/yahoo/tensor/IndexedTensor.java | 4 +- .../main/java/com/yahoo/tensor/MixedTensor.java | 26 ++++++++----- .../main/java/com/yahoo/tensor/PartialAddress.java | 8 ++-- .../src/main/java/com/yahoo/tensor/Tensor.java | 45 +++++++++++----------- .../main/java/com/yahoo/tensor/TensorAddress.java | 38 ++++++++++-------- .../src/main/java/com/yahoo/tensor/TensorType.java | 2 +- .../java/com/yahoo/tensor/functions/Concat.java | 6 +-- .../main/java/com/yahoo/tensor/functions/Join.java | 6 +-- .../src/main/java/com/yahoo/tensor/impl/Label.java | 22 ++++++++--- .../com/yahoo/tensor/impl/TensorAddressAny.java | 26 +++++++++++-- .../com/yahoo/tensor/impl/TensorAddressAny1.java | 6 ++- .../com/yahoo/tensor/impl/TensorAddressAny2.java | 6 ++- .../com/yahoo/tensor/impl/TensorAddressAny3.java | 6 ++- .../com/yahoo/tensor/impl/TensorAddressAny4.java | 6 ++- .../com/yahoo/tensor/impl/TensorAddressAnyN.java | 13 +++++-- .../com/yahoo/tensor/impl/TensorAddressEmpty.java | 9 ++++- .../tensor/impl/TensorAddressAnyTestCase.java | 10 +++-- 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 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 @@ -171,6 +171,21 @@ public class ClusterSearcher extends Searcher { this(schemas, null, null); } + @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 list = properties.get(name); - if (list == null) { - list = new ArrayList<>(); - properties.put(name, list); - } + List 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 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 cellIterator() { return new Iterator<>() { + final Iterator 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 valueIterator() { return new Iterator<>() { + final Iterator 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 mappedDimensions; private final List indexedDimensions; - private final int [] indexedDimensionsSize; + private final int[] indexedDimensionsSize; private ImmutableMap sparseMap; private List 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. *

* A tensor consists of a set of dimension names and a set of cells containing scalar values. - * Each cell is is identified by its address, which consists of a set of dimension-label pairs which defines + * Each cell is identified by its address, 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. *

* The size of the set of dimensions of a tensor is called its rank. @@ -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 { 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 { @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 { 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 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 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 { return TensorAddressAny.ofUnsafe(labels); } - /** Extracts the sparse(non-indexed) dimensions of the address */ - public TensorAddress sparsePartialAddress(TensorType sparseType, List 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 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 { 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 { 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 { 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 extends PrimitiveTensorFunction extends PrimitiveTensorFunction extends PrimitiveTensorFunction extends PrimitiveTensorFunction extends PrimitiveTensorFunction 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); -- cgit v1.2.3