To access the scalar element, the number of coordinates provided must be equal to the number + * of dimensions of this array (i.e. its rank). For example: + * + *
{@code
+ * BooleanNdArray matrix = NdArrays.ofBooleans(shape(2, 2)); // matrix rank = 2
+ * matrix.getBoolean(0, 1); // succeeds, returns false
+ * matrix.getBoolean(0); // throws IllegalRankException
+ *
+ * BooleanNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.getBoolean(); // succeeds, returns false
+ * }
+ *
+ * @param coordinates coordinates of the scalar to resolve
+ * @return value of that scalar
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ boolean getBoolean(long... coordinates);
+
+ /**
+ * Assigns the boolean value of the scalar found at the given coordinates.
+ *
+ * To access the scalar element, the number of coordinates provided must be equal to the number + * of dimensions of this array (i.e. its rank). For example: + * + *
{@code
+ * BooleanNdArray matrix = NdArrays.ofBooleans(shape(2, 2)); // matrix rank = 2
+ * matrix.setBoolean(true, 0, 1); // succeeds
+ * matrix.setBoolean(true, 0); // throws IllegalRankException
+ *
+ * BooleanNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.setBoolean(true); // succeeds
+ * }
+ *
+ * @param value the value to assign
+ * @param coordinates coordinates of the scalar to assign
+ * @return this array
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ BooleanNdArray setBoolean(boolean value, long... coordinates);
+
+ @Override
+ BooleanNdArray withShape(Shape shape);
+
+ @Override
+ BooleanNdArray slice(Index... indices);
+
+ @Override
+ BooleanNdArray get(long... coordinates);
+
+ @Override
+ BooleanNdArray set(NdArrayTo access the scalar element, the number of coordinates provided must be equal to the number + * of dimensions of this array (i.e. its rank). For example: + * + *
{@code
+ * ByteNdArray matrix = NdArrays.ofBytes(shape(2, 2)); // matrix rank = 2
+ * matrix.getByte(0, 1); // succeeds, returns 0
+ * matrix.getByte(0); // throws IllegalRankException
+ *
+ * ByteNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.getByte(); // succeeds, returns 0
+ * }
+ *
+ * @param coordinates coordinates of the scalar to resolve
+ * @return value of that scalar
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ byte getByte(long... coordinates);
+
+ /**
+ * Assigns the byte value of the scalar found at the given coordinates.
+ *
+ * To access the scalar element, the number of coordinates provided must be equal to the number + * of dimensions of this array (i.e. its rank). For example: + * + *
{@code
+ * ByteNdArray matrix = NdArrays.ofBytes(shape(2, 2)); // matrix rank = 2
+ * matrix.setByte(10, 0, 1); // succeeds
+ * matrix.setByte(10, 0); // throws IllegalRankException
+ *
+ * ByteNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.setByte(10); // succeeds
+ * }
+ *
+ * @param value the value to assign
+ * @param coordinates coordinates of the scalar to assign
+ * @return this array
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ ByteNdArray setByte(byte value, long... coordinates);
+
+ @Override
+ ByteNdArray withShape(Shape shape);
+
+ @Override
+ ByteNdArray slice(Index... indices);
+
+ @Override
+ ByteNdArray get(long... coordinates);
+
+ @Override
+ ByteNdArray set(NdArrayTo access the scalar element, the number of coordinates provided must be equal to the number + * of dimensions of this array (i.e. its rank). For example: + * + *
{@code
+ * DoubleNdArray matrix = NdArrays.ofDoubles(shape(2, 2)); // matrix rank = 2
+ * matrix.getDouble(0, 1); // succeeds, returns 0.0
+ * matrix.getDouble(0); // throws IllegalRankException
+ *
+ * DoubleNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.getDouble(); // succeeds, returns 0.0
+ * }
+ *
+ * @param coordinates coordinates of the scalar to resolve
+ * @return value of that scalar
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ double getDouble(long... coordinates);
+
+ /**
+ * Assigns the double value of the scalar found at the given coordinates.
+ *
+ * To access the scalar element, the number of coordinates provided must be equal to the number + * of dimensions of this array (i.e. its rank). For example: + * + *
{@code
+ * DoubleNdArray matrix = NdArrays.ofDoubles(shape(2, 2)); // matrix rank = 2
+ * matrix.setDouble(10.0, 0, 1); // succeeds
+ * matrix.setDouble(10.0, 0); // throws IllegalRankException
+ *
+ * DoubleNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.setDouble(10.0); // succeeds
+ * }
+ *
+ * @param value value to assign
+ * @param coordinates coordinates of the scalar to assign
+ * @return this array
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ DoubleNdArray setDouble(double value, long... coordinates);
+
+ /**
+ * Retrieve all scalar values of this array as a stream of doubles.
+ *
+ * For {@code rank() > 1} arrays, all vectors of the last dimension are collated so that the
+ * scalar values are returned in sequential order.
+ *
+ * @return scalar values as a stream
+ */
+ default DoubleStream streamOfDoubles() {
+ return StreamSupport.stream(scalars().spliterator(), false)
+ .mapToDouble(DoubleNdArray::getDouble);
+ }
+
+ @Override
+ DoubleNdArray withShape(Shape shape);
+
+ @Override
+ DoubleNdArray slice(Index... indices);
+
+ @Override
+ DoubleNdArray get(long... coordinates);
+
+ @Override
+ DoubleNdArray set(NdArray To access the scalar element, the number of coordinates provided must be equal to the number
+ * of dimensions of this array (i.e. its rank). For example:
+ *
+ * To access the scalar element, the number of coordinates provided must be equal to the number
+ * of dimensions of this array (i.e. its rank). For example:
+ *
+ * To access the scalar element, the number of coordinates provided must be equal to the number
+ * of dimensions of this array (i.e. its rank). For example:
+ *
+ * To access the scalar element, the number of coordinates provided must be equal to the number
+ * of dimensions of this array (i.e. its rank). For example:
+ *
+ * For {@code rank() > 1} arrays, all vectors of the last dimension are collated so that the
+ * scalar values are returned in sequential order.
+ *
+ * @return scalar values as a stream
+ */
+ default IntStream streamOfInts() {
+ return StreamSupport.stream(scalars().spliterator(), false).mapToInt(IntNdArray::getInt);
+ }
+
+ @Override
+ IntNdArray withShape(Shape shape);
+
+ @Override
+ IntNdArray slice(Index... indices);
+
+ @Override
+ IntNdArray get(long... coordinates);
+
+ @Override
+ IntNdArray set(NdArray To access the scalar element, the number of coordinates provided must be equal to the number
+ * of dimensions of this array (i.e. its rank). For example:
+ *
+ * To access the scalar element, the number of coordinates provided must be equal to the number
+ * of dimensions of this array (i.e. its rank). For example:
+ *
+ * For {@code rank() > 1} arrays, all vectors of the last dimension are collated so that the
+ * scalar values are returned in sequential order.
+ *
+ * @return scalar values as a stream
+ */
+ default LongStream streamOfLongs() {
+ return StreamSupport.stream(scalars().spliterator(), false).mapToLong(LongNdArray::getLong);
+ }
+
+ @Override
+ LongNdArray withShape(Shape shape);
+
+ @Override
+ LongNdArray slice(Index... indices);
+
+ @Override
+ LongNdArray get(long... coordinates);
+
+ @Override
+ LongNdArray set(NdArray The `NdArray` interface creates an abstraction between the physical storage of a data record,
+ * which can be linear or segmented, and its logical representation. In general, they achieve better
+ * performances than standard multi-dimensional arrays in Java by mapping directly linear data
+ * segments in memory.
+ *
+ * Like {@link DataBuffer}, {@code NdArray} instances support 64-bits indexing so they can be
+ * used to map very large data records. They also support special coordinates that allow traversing
+ * their values in any direction or to select only a subset of them.
+ *
+ * Example of usage:
+ *
+ * Logically, the N-dimensional array can be flatten in a single vector, where the scalars of
+ * the {@code (n - 1)}th element precedes those of the {@code (n)}th element, for a total of
+ * {@link #size()} values.
+ *
+ * For example, given a {@code n x m} matrix on the {@code [x, y]} axes, elements are iterated
+ * in the following order:
+ *
+ * x0y0, x0y1, ..., x0ym-1,
+ * x1y0, x1y1, ..., xn-1ym-1
+ *
+ * The returned sequence can then be iterated to visit each elements, either by calling {@link
+ * NdArraySequence#forEach(Consumer)} or {@link NdArraySequence#forEachIndexed(BiConsumer)}.
+ *
+ * This is equivalent to call {@code elements(shape().numDimensions() - 1)}
+ *
+ * @return an {@code NdArray} sequence
+ */
+ NdArraySequence extends NdArray The provided {@code shape} must comply to the following characteristics:
+ *
+ * Any changes applied to the returned view affect the data of this array as well, as there is
+ * no copy involved.
+ *
+ * @param shape the new shape to apply
+ * @return a new array viewing the data according to the new shape, or this array if shapes are
+ * the same
+ * @throws IllegalArgumentException if the provided {@code shape} is not compliant
+ * @throws UnsupportedOperationException if this array does not support this operation
+ */
+ NdArray Slices allow to traverse an N-dimensional array in any of its axis and/or to filter only
+ * elements of interest. For example, for a given matrix on the {@code [x, y]} axes, it is
+ * possible to iterate elements at {@code y=0} for all {@code x}.
+ *
+ * Any changes applied to the returned slice affect the data of this array as well, as there is
+ * no copy involved.
+ *
+ * Example of usage:
+ *
+ * Elements of any of the dimensions of this array can be retrieved. For example, if the number
+ * of coordinates is equal to the number of dimensions of this array, then a rank-0 (scalar) array
+ * is returned, which value can then be obtained by calling `array.getObject()`.
+ *
+ * Any changes applied to the returned elements affect the data of this array as well, as there
+ * is no copy involved.
+ *
+ * Note that invoking this method is an equivalent and more efficient way to slice this array
+ * on single scalar, i.e. {@code array.get(x, y, z)} is equal to {@code array.slice(at(x), at(y),
+ * at(z))}
+ *
+ * @param coordinates coordinates of the element to access, none will return this array
+ * @return the element at this index
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ */
+ NdArray The number of coordinates provided can be anywhere between 0 and rank - 1. For example:
+ *
+ * To access the scalar element, the number of coordinates provided must be equal to the number
+ * of dimensions of this array (i.e. its rank). For example:
+ *
+ * To access the scalar element, the number of coordinates provided must be equal to the number
+ * of dimensions of this array (i.e. its rank). For example:
+ *
+ * For {@code rank() > 1} arrays, all vectors of the last dimension are collated so that the
+ * scalar values are returned in sequential order.
+ *
+ * @return scalar values as a stream
+ */
+ default Stream The {@link #shape()} of the destination array must be equal to the shape of this array, or
+ * an exception is thrown. After the copy, the content of both arrays can be altered
+ * independently, without affecting each other.
+ *
+ * @param dst array to receive a copy of the content of this array
+ * @return this array
+ * @throws IllegalArgumentException if the shape of {@code dst} is not equal to the shape of this
+ * array
+ */
+ NdArray The size of the buffer must be equal or greater to the {@link #size()} of this array, or an
+ * exception is thrown. After the copy, content of the buffer and of the array can be altered
+ * independently, without affecting each other.
+ *
+ * Note: in version 0.4.0 and earlier, this method was named {@code read(DataBuffer The size of the buffer must be equal or greater to the {@link #size()} of this array, or an
+ * exception is thrown. After the copy, content of the buffer and of the array can be altered
+ * independently, without affecting each other.
+ *
+ * Note: in version 0.4.0 and earlier, this method was named {@code write(DataBuffer An array is equal to another object if this object is another {@link NdArray} of the same
+ * shape, type and the elements are equal and in the same order. For example:
+ *
+ * Note that the computation required to verify equality between two arrays can be expensive in
+ * some cases and therefore, it is recommended to not use this method in a critical path where
+ * performances matter.
+ *
+ * @param obj object to compare this array with
+ * @return true if this array is equal to the provided object
+ */
+ @Override
+ boolean equals(Object obj);
+}
diff --git a/tensorflow-ndarray/src/main/java/org/tensorflow/ndarray/NdArraySequence.java b/tensorflow-ndarray/src/main/java/org/tensorflow/ndarray/NdArraySequence.java
new file mode 100644
index 00000000000..bda82cec383
--- /dev/null
+++ b/tensorflow-ndarray/src/main/java/org/tensorflow/ndarray/NdArraySequence.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =======================================================================
+ */
+
+package org.tensorflow.ndarray;
+
+import java.util.function.BiConsumer;
+import org.tensorflow.ndarray.buffer.DataBufferWindow;
+
+/**
+ * A sequence of elements of an N-dimensional array.
+ *
+ * An {@code NdArraySequence} is used to traverse an {@code NdArray} in a given dimension and
+ * visit each of its elements. For example, given a {@code n x m} matrix on the {@code [x, y]} axes,
+ * elements are iterated in the following order:
+ *
+ * x0y0, x0y1, ..., x0ym-1,
+ * x1y0, x1y1, ..., xn-1ym-1
+ *
+ * @param Important: the consumer method should not keep a reference to the coordinates as they
+ * might be mutable and reused during the iteration to improve performance.
+ *
+ * @param consumer method to invoke for each elements
+ */
+ void forEachIndexed(BiConsumer Unlike conventional Java collections, elements of a {@code NdArraySequence} are transient,
+ * i.e. new {@code NdArray} instances are allocated for each iteration. To improve performance,
+ * the same instance can be recycled to view all elements of this sequence, using a {@link
+ * DataBufferWindow}.
+ *
+ * In some cases though, it might be preferable to disable such optimizations to ensure that
+ * each element returned is a new slice of the original array. For example, if one or more
+ * elements visited must live beyond the scope of the sequence iteration, {@code asSlices()} makes
+ * sure that all elements returned by the sequence are unique instances.
+ *
+ * Modifying the data of the returned vector will also impact the values in the array passed in
+ * parameter.
+ *
+ * @param values vector values
+ * @return new byte vector
+ * @throws IllegalArgumentException if values is null
+ */
+ public static ByteNdArray vectorOf(byte... values) {
+ if (values == null) {
+ throw new IllegalArgumentException("Values cannot be null");
+ }
+ return wrap(Shape.of(values.length), DataBuffers.of(values, false, false));
+ }
+
+ /**
+ * Creates an N-dimensional array of bytes of the given shape.
+ *
+ * All values are initialized to zeros.
+ *
+ * @param shape shape of the array
+ * @return new byte N-dimensional array
+ * @throws IllegalArgumentException if shape is null or has unknown dimensions
+ */
+ public static ByteNdArray ofBytes(Shape shape) {
+ if (shape == null) {
+ throw new IllegalArgumentException("Shape cannot be null");
+ }
+ return wrap(shape, DataBuffers.ofBytes(shape.size()));
+ }
+
+ /**
+ * Wraps a buffer in a byte N-dimensional array of a given shape.
+ *
+ * @param shape shape of the array
+ * @param buffer buffer to wrap
+ * @return new byte N-dimensional array
+ * @throws IllegalArgumentException if shape is null, has unknown dimensions or has size bigger in
+ * the buffer size
+ */
+ public static ByteNdArray wrap(Shape shape, ByteDataBuffer buffer) {
+ return ByteDenseNdArray.create(buffer, shape);
+ }
+
+ /**
+ * Creates a Sparse array of byte values with a default value of zero
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non-default values.
+ * @param values A 1-D ByteNdArray of shape {@code [N]}, which supplies the values for each
+ * element in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter
+ * {@code values=[18, 3]} specifies that element {@code [1,3,1]} of the sparse NdArray has a
+ * value of {@code 18}, and element {@code [2,4,0]} of the NdArray has a value of {@code 3}.
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the byte sparse array.
+ */
+ public static ByteSparseNdArray sparseOf(LongNdArray indices, ByteNdArray values, Shape shape) {
+ return ByteSparseNdArray.create(indices, values, DimensionalSpace.create(shape));
+ }
+
+ /**
+ * Creates a Sparse array of byte values
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non default values.
+ * @param values A 1-D ByteNdArray of shape {@code [N]}, which supplies the values for each
+ * element in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter
+ * {@code values=[18, 3]} specifies that element {@code [1,3,1]} of the sparse NdArray has a
+ * value of {@code 18}, and element {@code [2,4,0]} of the NdArray has a value of {@code 3}.
+ * @param defaultValue Scalar value to set for indices not specified in 'indices'
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the byte sparse array.
+ */
+ public static ByteSparseNdArray sparseOf(
+ LongNdArray indices, ByteNdArray values, byte defaultValue, Shape shape) {
+ return ByteSparseNdArray.create(indices, values, defaultValue, DimensionalSpace.create(shape));
+ }
+
+ // LONG ARRAYS
+
+ /**
+ * Creates long scalar (rank 0) initialized with the given value.
+ *
+ * @param value scalar value
+ * @return new long scalar
+ */
+ public static LongNdArray scalarOf(long value) {
+ return ofLongs(Shape.scalar()).setLong(value);
+ }
+
+ /**
+ * Creates a long vector (rank 1) initialized with the given values.
+ *
+ * Modifying the data of the returned vector will also impact the values in the array passed in
+ * parameter.
+ *
+ * @param values vector values
+ * @return new long vector
+ * @throws IllegalArgumentException if values is null
+ */
+ public static LongNdArray vectorOf(long... values) {
+ if (values == null) {
+ throw new IllegalArgumentException();
+ }
+ return wrap(Shape.of(values.length), DataBuffers.of(values, false, false));
+ }
+
+ /**
+ * Creates an N-dimensional array of longs of the given shape.
+ *
+ * All values are initialized to zeros.
+ *
+ * @param shape shape of the array
+ * @return new long N-dimensional array
+ * @throws IllegalArgumentException if shape is null or has unknown dimensions
+ */
+ public static LongNdArray ofLongs(Shape shape) {
+ return wrap(shape, DataBuffers.ofLongs(shape.size()));
+ }
+
+ /**
+ * Wraps a buffer in a long N-dimensional array of a given shape.
+ *
+ * @param shape shape of the array
+ * @param buffer buffer to wrap
+ * @return new long N-dimensional array
+ * @throws IllegalArgumentException if shape is null, has unknown dimensions or has size bigger in
+ * the buffer size
+ */
+ public static LongNdArray wrap(Shape shape, LongDataBuffer buffer) {
+ return LongDenseNdArray.create(buffer, shape);
+ }
+
+ /**
+ * Creates a Sparse array of long values with a default value of zero
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non-default values.
+ * @param values A 1-D LongNdArray of shape {@code [N]}, which supplies the values for each
+ * element in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter
+ * {@code values=[18L, 3L]} specifies that element {@code [1,3,1]} of the sparse NdArray has a
+ * value of {@code 18L}, and element {@code [2,4,0]} of the NdArray has a value of {@code 3L}.
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the long sparse array.
+ */
+ public static LongSparseNdArray sparseOf(LongNdArray indices, LongNdArray values, Shape shape) {
+ return LongSparseNdArray.create(indices, values, DimensionalSpace.create(shape));
+ }
+
+ /**
+ * Creates a Sparse array of long values with a default value of zero
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non-default values.
+ * @param values A 1-D LongNdArray of shape {@code [N]}, which supplies the values for each
+ * element in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter
+ * {@code values=[18L, 3L]} specifies that element {@code [1,3,1]} of the sparse NdArray has a
+ * value of {@code 18L}, and element {@code [2,4,0]} of the NdArray has a value of {@code 3L}.
+ * @param defaultValue Scalar value to set for indices not specified in 'indices'
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the long sparse array.
+ */
+ public static LongSparseNdArray sparseOf(
+ LongNdArray indices, LongNdArray values, long defaultValue, Shape shape) {
+ return LongSparseNdArray.create(indices, values, defaultValue, DimensionalSpace.create(shape));
+ }
+
+ // INT ARRAYS
+
+ /**
+ * Creates long scalar (rank 0) initialized with the given value.
+ *
+ * @param value scalar value
+ * @return new long scalar
+ */
+ public static IntNdArray scalarOf(int value) {
+ return ofInts(Shape.scalar()).setInt(value);
+ }
+
+ /**
+ * Creates a int vector (rank 1) initialized with the given values.
+ *
+ * Modifying the data of the returned vector will also impact the values in the array passed in
+ * parameter.
+ *
+ * @param values vector values
+ * @return new int vector
+ * @throws IllegalArgumentException if values is null
+ */
+ public static IntNdArray vectorOf(int... values) {
+ if (values == null) {
+ throw new IllegalArgumentException();
+ }
+ return wrap(Shape.of(values.length), DataBuffers.of(values, false, false));
+ }
+
+ /**
+ * Creates an N-dimensional array of ints of the given shape.
+ *
+ * All values are initialized to zeros.
+ *
+ * @param shape shape of the array
+ * @return new int N-dimensional array
+ * @throws IllegalArgumentException if shape is null or has unknown dimensions
+ */
+ public static IntNdArray ofInts(Shape shape) {
+ return wrap(shape, DataBuffers.ofInts(shape.size()));
+ }
+
+ /**
+ * Wraps a buffer in an int N-dimensional array of a given shape.
+ *
+ * @param shape shape of the array
+ * @param buffer buffer to wrap
+ * @return new int N-dimensional array
+ * @throws IllegalArgumentException if shape is null, has unknown dimensions or has size bigger in
+ * the buffer size
+ */
+ public static IntNdArray wrap(Shape shape, IntDataBuffer buffer) {
+ return IntDenseNdArray.create(buffer, shape);
+ }
+
+ /**
+ * Creates a Sparse array of int values with a default value of zero.
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non-default values.
+ * @param values A 1-D IntNdArray of shape {@code [N]}, which supplies the values for each element
+ * in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter {@code
+ * values=[18, 3]} specifies that element {@code [1,3,1]} of the sparse NdArray has a value of
+ * {@code 18}, and element {@code [2,4,0]} of the NdArray has a value of {@code 3}.
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the int sparse array.
+ */
+ public static IntSparseNdArray sparseOf(LongNdArray indices, IntNdArray values, Shape shape) {
+ return IntSparseNdArray.create(indices, values, DimensionalSpace.create(shape));
+ }
+
+ /**
+ * Creates a Sparse array of int values
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non-default values.
+ * @param values A 1-D IntNdArray of shape {@code [N]}, which supplies the values for each element
+ * in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter {@code
+ * values=[18, 3]} specifies that element {@code [1,3,1]} of the sparse NdArray has a value of
+ * {@code 18}, and element {@code [2,4,0]} of the NdArray has a value of {@code 3}.
+ * @param defaultValue Scalar value to set for indices not specified in 'indices'
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the int sparse array.
+ */
+ public static IntSparseNdArray sparseOf(
+ LongNdArray indices, IntNdArray values, int defaultValue, Shape shape) {
+ return IntSparseNdArray.create(indices, values, defaultValue, DimensionalSpace.create(shape));
+ }
+
+ // SHORT ARRAYS
+
+ /**
+ * Creates short scalar (rank 0) initialized with the given value.
+ *
+ * @param value scalar value
+ * @return new short scalar
+ */
+ public static ShortNdArray scalarOf(short value) {
+ return ofShorts(Shape.scalar()).setShort(value);
+ }
+
+ /**
+ * Creates a short vector (rank 1) initialized with the given values.
+ *
+ * Modifying the data of the returned vector will also impact the values in the array passed in
+ * parameter.
+ *
+ * @param values vector values
+ * @return new short vector
+ * @throws IllegalArgumentException if values is null
+ */
+ public static ShortNdArray vectorOf(short... values) {
+ if (values == null) {
+ throw new IllegalArgumentException();
+ }
+ return wrap(Shape.of(values.length), DataBuffers.of(values, false, false));
+ }
+
+ /**
+ * Creates an N-dimensional array of shorts of the given shape.
+ *
+ * All values are initialized to zeros.
+ *
+ * @param shape shape of the array
+ * @return new short N-dimensional array
+ * @throws IllegalArgumentException if shape is null or has unknown dimensions
+ */
+ public static ShortNdArray ofShorts(Shape shape) {
+ return wrap(shape, DataBuffers.ofShorts(shape.size()));
+ }
+
+ /**
+ * Wraps a buffer in a short N-dimensional array of a given shape.
+ *
+ * @param shape shape of the array
+ * @param buffer buffer to wrap
+ * @return new short N-dimensional array
+ * @throws IllegalArgumentException if shape is null, has unknown dimensions or has size bigger in
+ * the buffer size
+ */
+ public static ShortNdArray wrap(Shape shape, ShortDataBuffer buffer) {
+ return ShortDenseNdArray.create(buffer, shape);
+ }
+
+ /**
+ * Creates a Sparse array of short values with a default value of zero
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non-default values.
+ * @param values A 1-D ShortNdArray of shape {@code [N]}, which supplies the values for each
+ * element in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter
+ * {@code values=[18, 3]} specifies that element {@code [1,3,1]} of the sparse NdArray has a
+ * value of {@code 18}, and element {@code [2,4,0]} of the NdArray has a value of {@code 3}.
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the short sparse array.
+ */
+ public static ShortSparseNdArray sparseOf(LongNdArray indices, ShortNdArray values, Shape shape) {
+ return ShortSparseNdArray.create(indices, values, DimensionalSpace.create(shape));
+ }
+
+ /**
+ * Creates a Sparse array of short values
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non-default values.
+ * @param values A 1-D ShortNdArray of shape {@code [N]}, which supplies the values for each
+ * element in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter
+ * {@code values=[18, 3]} specifies that element {@code [1,3,1]} of the sparse NdArray has a
+ * value of {@code 18}, and element {@code [2,4,0]} of the NdArray has a value of {@code 3}.
+ * @param defaultValue Scalar value to set for indices not specified in 'indices'
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the short sparse array.
+ */
+ public static ShortSparseNdArray sparseOf(
+ LongNdArray indices, ShortNdArray values, short defaultValue, Shape shape) {
+ return ShortSparseNdArray.create(indices, values, defaultValue, DimensionalSpace.create(shape));
+ }
+
+ // FLOAT ARRAYS
+
+ /**
+ * Creates float scalar (rank 0) initialized with the given value.
+ *
+ * @param value scalar value
+ * @return new float scalar
+ */
+ public static FloatNdArray scalarOf(float value) {
+ return ofFloats(Shape.scalar()).setFloat(value);
+ }
+
+ /**
+ * Creates a float vector (rank 1) initialized with the given values.
+ *
+ * Modifying the data of the returned vector will also impact the values in the array passed in
+ * parameter.
+ *
+ * @param values vector values
+ * @return new float vector
+ * @throws IllegalArgumentException if values is null
+ */
+ public static FloatNdArray vectorOf(float... values) {
+ if (values == null) {
+ throw new IllegalArgumentException();
+ }
+ return wrap(Shape.of(values.length), DataBuffers.of(values, false, false));
+ }
+
+ /**
+ * Creates an N-dimensional array of floats of the given shape.
+ *
+ * All values are initialized to zeros.
+ *
+ * @param shape shape of the array
+ * @return new float N-dimensional array
+ * @throws IllegalArgumentException if shape is null or has unknown dimensions
+ */
+ public static FloatNdArray ofFloats(Shape shape) {
+ return wrap(shape, DataBuffers.ofFloats(shape.size()));
+ }
+
+ /**
+ * Wraps a buffer in a float N-dimensional array of a given shape.
+ *
+ * @param shape shape of the array
+ * @param buffer buffer to wrap
+ * @return new float N-dimensional array
+ * @throws IllegalArgumentException if shape is null, has unknown dimensions or has size bigger in
+ * the buffer size
+ */
+ public static FloatNdArray wrap(Shape shape, FloatDataBuffer buffer) {
+ return FloatDenseNdArray.create(buffer, shape);
+ }
+
+ /**
+ * Creates a Sparse array of float values with a default value of zero
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non-default values.
+ * @param values A 1-D FloatNdArray of shape {@code [N]}, which supplies the values for each
+ * element in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter
+ * {@code values=[18f, 3.8f]} specifies that element {@code [1,3,1]} of the sparse NdArray has
+ * a value of {@code 18f}, and element {@code [2,4,0]} of the NdArray has a value of {@code
+ * 3.8f}.
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the float sparse array.
+ */
+ public static FloatSparseNdArray sparseOf(LongNdArray indices, FloatNdArray values, Shape shape) {
+ return FloatSparseNdArray.create(indices, values, DimensionalSpace.create(shape));
+ }
+
+ /**
+ * Creates a Sparse array of float values
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non-default values.
+ * @param values A 1-D FloatNdArray of shape {@code [N]}, which supplies the values for each
+ * element in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter
+ * {@code values=[18f, 3.8f]} specifies that element {@code [1,3,1]} of the sparse NdArray has
+ * a value of {@code 18f}, and element {@code [2,4,0]} of the NdArray has a value of {@code
+ * 3.8f}.
+ * @param defaultValue Scalar value to set for indices not specified in 'indices'
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the float sparse array.
+ */
+ public static FloatSparseNdArray sparseOf(
+ LongNdArray indices, FloatNdArray values, float defaultValue, Shape shape) {
+ return FloatSparseNdArray.create(indices, values, defaultValue, DimensionalSpace.create(shape));
+ }
+
+ // DOUBLE ARRAYS
+
+ /**
+ * Creates double scalar (rank 0) initialized with the given value.
+ *
+ * @param value scalar value
+ * @return new double scalar
+ */
+ public static DoubleNdArray scalarOf(double value) {
+ return ofDoubles(Shape.scalar()).setDouble(value);
+ }
+
+ /**
+ * Creates a double vector (rank 1) initialized with the given values.
+ *
+ * Modifying the data of the returned vector will also impact the values in the array passed in
+ * parameter.
+ *
+ * @param values vector values
+ * @return new double vector
+ * @throws IllegalArgumentException if values is null
+ */
+ public static DoubleNdArray vectorOf(double... values) {
+ if (values == null) {
+ throw new IllegalArgumentException();
+ }
+ return wrap(Shape.of(values.length), DataBuffers.of(values, false, false));
+ }
+
+ /**
+ * Creates an N-dimensional array of doubles of the given shape.
+ *
+ * All values are initialized to zeros.
+ *
+ * @param shape shape of the array
+ * @return new double N-dimensional array
+ * @throws IllegalArgumentException if shape is null or has unknown dimensions
+ */
+ public static DoubleNdArray ofDoubles(Shape shape) {
+ return wrap(shape, DataBuffers.ofDoubles(shape.size()));
+ }
+
+ /**
+ * Wraps a buffer in a double N-dimensional array of a given shape.
+ *
+ * @param shape shape of the array
+ * @param buffer buffer to wrap
+ * @return new double N-dimensional array
+ * @throws IllegalArgumentException if shape is null, has unknown dimensions or has size bigger in
+ * the buffer size
+ */
+ public static DoubleNdArray wrap(Shape shape, DoubleDataBuffer buffer) {
+ return DoubleDenseNdArray.create(buffer, shape);
+ }
+
+ /**
+ * Creates a Sparse array of double values with a default value of zero
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non-default values.
+ * @param values A 1-D DoubleNdArray of shape {@code [N]}, which supplies the values for each
+ * element in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter
+ * {@code values=[18, 3.8]} specifies that element {@code [1,3,1]} of the sparse NdArray has a
+ * value of {@code 18}, and element {@code [2,4,0]} of the NdArray has a value of {@code 3.8}.
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the float sparse array.
+ */
+ public static DoubleSparseNdArray sparseOf(
+ LongNdArray indices, DoubleNdArray values, Shape shape) {
+ return DoubleSparseNdArray.create(indices, values, DimensionalSpace.create(shape));
+ }
+
+ /**
+ * Creates a Sparse array of double values
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non-default values.
+ * @param values A 1-D DoubleNdArray of shape {@code [N]}, which supplies the values for each
+ * element in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter
+ * {@code values=[18, 3.8]} specifies that element {@code [1,3,1]} of the sparse NdArray has a
+ * value of {@code 18}, and element {@code [2,4,0]} of the NdArray has a value of {@code 3.8}.
+ * @param defaultValue Scalar value to set for indices not specified in 'indices'
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the float sparse array.
+ */
+ public static DoubleSparseNdArray sparseOf(
+ LongNdArray indices, DoubleNdArray values, double defaultValue, Shape shape) {
+ return DoubleSparseNdArray.create(
+ indices, values, defaultValue, DimensionalSpace.create(shape));
+ }
+
+ // BOOLEAN ARRAYS
+
+ /**
+ * Creates boolean scalar (rank 0) initialized with the given value.
+ *
+ * @param value scalar value
+ * @return new boolean scalar
+ */
+ public static BooleanNdArray scalarOf(boolean value) {
+ return ofBooleans(Shape.scalar()).setBoolean(value);
+ }
+
+ /**
+ * Creates a boolean vector (rank 1) initialized with the given values.
+ *
+ * Modifying the data of the returned vector will also impact the values in the array passed in
+ * parameter.
+ *
+ * @param values vector values
+ * @return new boolean vector
+ * @throws IllegalArgumentException if values is null
+ */
+ public static BooleanNdArray vectorOf(boolean... values) {
+ if (values == null) {
+ throw new IllegalArgumentException();
+ }
+ return wrap(Shape.of(values.length), DataBuffers.of(values, false, false));
+ }
+
+ /**
+ * Creates an N-dimensional array of booleans of the given shape.
+ *
+ * All values are initialized to zeros.
+ *
+ * @param shape shape of the array
+ * @return new boolean N-dimensional array
+ * @throws IllegalArgumentException if shape is null or has unknown dimensions
+ */
+ public static BooleanNdArray ofBooleans(Shape shape) {
+ return wrap(shape, DataBuffers.ofBooleans(shape.size()));
+ }
+
+ /**
+ * Wraps a buffer in a boolean N-dimensional array of a given shape.
+ *
+ * @param shape shape of the array
+ * @param buffer buffer to wrap
+ * @return new boolean N-dimensional array
+ * @throws IllegalArgumentException if shape is null, has unknown dimensions or has size bigger in
+ * the buffer size
+ */
+ public static BooleanNdArray wrap(Shape shape, BooleanDataBuffer buffer) {
+ return BooleanDenseNdArray.create(buffer, shape);
+ }
+
+ /**
+ * Creates a Sparse array of boolean values with a default value of 'false'
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non-default values.
+ * @param values A 1-D BooleanNdArray of shape {@code [N]}, which supplies the values for each
+ * element in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter
+ * {@code values=[true, true]} specifies that element {@code [1,3,1]} of the sparse NdArray
+ * has a value of true, and element {@code [2,4,0]} of the NdArray has a value of true. All
+ * other values are false.
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the float sparse array.
+ */
+ public static BooleanSparseNdArray sparseOf(
+ LongNdArray indices, BooleanNdArray values, Shape shape) {
+ return BooleanSparseNdArray.create(indices, values, DimensionalSpace.create(shape));
+ }
+
+ /**
+ * Creates a Sparse array of boolean values
+ *
+ * @param indices A 2-D LongNdArray of shape {@code [N, ndims]}, that specifies the indices of the
+ * elements in the sparse array that contain non-default values (elements are zero-indexed).
+ * For example, {@code indices=[[1,3,1], [2,4,0]]} specifies that the elements with indexes of
+ * {@code [1,3,1]} and {@code [2,4,0]} have non-default values.
+ * @param values A 1-D BooleanNdArray of shape {@code [N]}, which supplies the values for each
+ * element in indices. For example, given {@code indices=[[1,3,1], [2,4,0]]}, the parameter
+ * {@code values=[true, true]} specifies that element {@code [1,3,1]} of the sparse NdArray
+ * has a value of true, and element {@code [2,4,0]} of the NdArray has a value of true. All
+ * other values are false.
+ * @param defaultValue Scalar value to set for indices not specified in 'indices'
+ * @param shape the shape of the dense array represented by this sparse array.
+ * @return the float sparse array.
+ */
+ public static BooleanSparseNdArray sparseOf(
+ LongNdArray indices, BooleanNdArray values, boolean defaultValue, Shape shape) {
+ return BooleanSparseNdArray.create(
+ indices, values, defaultValue, DimensionalSpace.create(shape));
+ }
+
+ // OBJECT ARRAYS
+
+ /**
+ * Creates scalar (rank 0) initialized with the given value.
+ *
+ * @param value scalar value
+ * @param Modifying the data of the returned vector will also impact the values in the array passed in
+ * parameter.
+ *
+ * @param values vector values
+ * @param All values are initialized to zeros.
+ *
+ * @param clazz class of the data to be stored in this array
+ * @param shape shape of the array
+ * @param A {@code Shape} defines sizes along its axes. It may contain an unknown size for one of the
+ * axes or may be totally unknown, in which case not even the number of axes is known. If the size
+ * of an axis is unknown, {@link Shape#UNKNOWN_SIZE} should be used as its size.
+ */
+public final class Shape {
+
+ /** The size of an unknown axis or the total unknown size for an unknown Shape. */
+ public static long UNKNOWN_SIZE = -1L;
+
+ /**
+ * Creates a Shape representing an unknown number of dimensions.
+ *
+ * @return A Shape for which {@link Shape#isUnknown()} is true, never null.
+ */
+ public static Shape unknown() {
+ return new Shape(null);
+ }
+
+ /**
+ * Creates a Shape representing a scalar value.
+ *
+ * @return A Shape without dimensions for which {@link Shape#isScalar()} is true, never null.
+ */
+ public static Shape scalar() {
+ return new Shape(new long[0]);
+ }
+
+ /**
+ * Create a Shape representing a scalar or an N-dimensional value.
+ *
+ * Creates a Shape representing a scalar or an N-dimensional value (N being at least 1), with
+ * the provided size for each dimension. A -1 indicates that the size of the corresponding
+ * dimension is unknown. If no sizes are provided, a Shape representing a scalar is created. For
+ * example:
+ *
+ * If {@link Shape#isUnknown()} is true or {@link Shape#hasUnknownDimension()} is true, {@link
+ * Shape#UNKNOWN_SIZE} is returned.
+ *
+ * @return The total number of elements a Tensor with this shape would have if it can be
+ * calculated, else {@link Shape#UNKNOWN_SIZE}.
+ */
+ public long size() {
+ if (size == null) {
+ size = computeSize(dimensionSizes);
+ }
+ return size;
+ }
+
+ /**
+ * The size of the dimension with the given index.
+ *
+ * If {@link Shape#isUnknown()} is true or the size of the dimension with the given index has
+ * an unknown size, {@link Shape#UNKNOWN_SIZE} is returned.
+ *
+ * @param i the index of the dimension to get the size for. If this Shape has a known number of
+ * dimensions, it must be < {@link Shape#numDimensions()}. The index may be negative, in
+ * which case the position is counted from the end of the shape. E.g.: {@code size(-1)}
+ * returns the size of the last dimension, {@code size(-2)} the size of the second to last
+ * dimension etc.
+ * @return The size of the dimension with the given index if known, {@link Shape#UNKNOWN_SIZE}
+ * otherwise.
+ * @deprecated Renamed to {@link #get(int)}.
+ */
+ @Deprecated
+ public long size(int i) {
+ return get(i);
+ }
+
+ /**
+ * The size of the dimension with the given index.
+ *
+ * If {@link Shape#isUnknown()} is true or the size of the dimension with the given index has
+ * an unknown size, {@link Shape#UNKNOWN_SIZE} is returned.
+ *
+ * @param i the index of the dimension to get the size for. If this Shape has a known number of
+ * dimensions, it must be < {@link Shape#numDimensions()}. The index may be negative, in
+ * which case the position is counted from the end of the shape. E.g.: {@code size(-1)}
+ * returns the size of the last dimension, {@code size(-2)} the size of the second to last
+ * dimension etc.
+ * @return The size of the dimension with the given index if known, {@link Shape#UNKNOWN_SIZE}
+ * otherwise.
+ */
+ public long get(int i) {
+ if (dimensionSizes == null) {
+ return UNKNOWN_SIZE;
+ } else if (i >= 0) {
+ return dimensionSizes[i];
+ } else {
+ return dimensionSizes[dimensionSizes.length + i];
+ }
+ }
+
+ /**
+ * Returns the number of dimensions of this Shape. -1 if unknown, 0 for a scalar, 1 for a vector,
+ * 2 for a matrix etc.
+ */
+ public int numDimensions() {
+ return dimensionSizes != null ? dimensionSizes.length : -1;
+ }
+
+ /** Returns whether one or more dimensions of this Shape have an unknown size. */
+ public boolean hasUnknownDimension() {
+ if (dimensionSizes == null) {
+ return true;
+ }
+ for (long dimSize : dimensionSizes) {
+ if (dimSize == UNKNOWN_SIZE) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Returns whether this Shape represents a scalar. */
+ public boolean isScalar() {
+ return dimensionSizes != null && dimensionSizes.length == 0;
+ }
+
+ /** Returns whether this Shape is the shape of a vector. */
+ public boolean isVector() {
+ return dimensionSizes != null && dimensionSizes.length == 1;
+ }
+
+ /** Returns whether this Shape is the shape of a matrix */
+ public boolean isMatrix() {
+ return dimensionSizes != null && dimensionSizes.length == 2;
+ }
+
+ /** Returns whether the number of dimensions of this Shape is unknown. */
+ public boolean isUnknown() {
+ return dimensionSizes == null;
+ }
+
+ /**
+ * Returns a defensive copy of the this Shape's axes. Changes to the returned array to not change
+ * this Shape's state. Returns null if {@link Shape#isUnknown()} is true.
+ */
+ public long[] asArray() {
+ if (this.dimensionSizes == null) {
+ return null;
+ } else {
+ return Arrays.copyOf(dimensionSizes, dimensionSizes.length);
+ }
+ }
+
+ /**
+ * Returns a defensive copy of the this Shape's axes. Changes to the returned list do not change
+ * this Shape's state. Returns null if {@link Shape#isUnknown()} is true.
+ */
+ public List
+ *
+ * If either Shape has unknown dimensions (even if they are the same in both) or if either
+ * shape has an unknown number of dimensions (even if both return {@code true} for {@link
+ * Shape#isUnknown()}), they are not considered equal! However, a shape will always equal itself,
+ * even if it is unknown or contains unknown dimensions.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ // Shapes are equivalent if all of their dimensions are equals
+ if (obj instanceof Shape) {
+ Shape otherShape = (Shape) obj;
+ if (otherShape.hasUnknownDimension()) {
+ return false;
+ }
+ return Arrays.equals(dimensionSizes, otherShape.dimensionSizes);
+ }
+ return false;
+ }
+
+ /** Succinct description of the Shape meant for debugging. */
+ @Override
+ public String toString() {
+ return Arrays.toString(dimensionSizes);
+ }
+
+ private Shape(long[] dimensionSizes) {
+ this.dimensionSizes = dimensionSizes;
+ }
+
+ private final long[] dimensionSizes;
+ private Long size;
+
+ /**
+ * Returns a 1-dimensional Shape with first dimension matching the first dimension of this Shape.
+ */
+ public Shape head() {
+ return take(1);
+ }
+
+ /**
+ * Returns an n-dimensional Shape with the dimensions matching the first n dimensions of this
+ * shape
+ *
+ * @param n the number of leading dimensions to get, must be <= than {@link
+ * Shape#numDimensions()}
+ * @return an n-dimensional Shape with the first n dimensions matching the first n dimensions of
+ * this Shape
+ */
+ public Shape take(int n) {
+ if (n > numDimensions()) {
+ throw new ArrayIndexOutOfBoundsException(
+ "Cannot take " + n + " dimensions, shape has only " + numDimensions() + ".");
+ }
+ long[] newDimensions = new long[n];
+ System.arraycopy(dimensionSizes, 0, newDimensions, 0, n);
+ return Shape.of(newDimensions);
+ }
+
+ /** Returns a new Shape, with this Shape's first dimension removed. */
+ public Shape tail() {
+ if (dimensionSizes.length < 2) {
+ return Shape.of();
+ }
+ return Shape.of(Arrays.copyOfRange(dimensionSizes, 1, dimensionSizes.length));
+ }
+
+ /**
+ * Returns an n-dimensional Shape with the dimensions matching the last n dimensions of this
+ * Shape.
+ *
+ * @param n the number of trailing dimensions to get, must be <= than {@link
+ * Shape#numDimensions()}
+ * @return an n-dimensional shape with the dimensions matching the last n dimensions of this
+ * Shape, never null
+ */
+ public Shape takeLast(int n) {
+ if (n > numDimensions()) {
+ throw new ArrayIndexOutOfBoundsException(
+ "Cannot take last " + n + " dimensions, shape has only " + numDimensions() + ".");
+ }
+ long[] newDimensions = new long[n];
+ System.arraycopy(dimensionSizes, numDimensions() - n, newDimensions, 0, n);
+ return Shape.of(newDimensions);
+ }
+
+ /**
+ * Return a {@code end - begin} dimensional shape with dimensions matching this Shape from {@code
+ * begin} to {@code end}.
+ *
+ * @param begin Where to start the sub-shape.
+ * @param end Where to end the sub-shape, exclusive.
+ * @return the sub-shape bounded by begin and end.
+ */
+ public Shape subShape(int begin, int end) {
+ if (end > numDimensions()) {
+ throw new ArrayIndexOutOfBoundsException(
+ "End index "
+ + end
+ + " out of bounds: shape only has "
+ + numDimensions()
+ + " dimensions.");
+ }
+ if (begin < 0) {
+ throw new ArrayIndexOutOfBoundsException(
+ "Begin index " + begin + " out of bounds: cannot be less than 0.");
+ }
+
+ long[] newDimensions = new long[end - begin];
+ System.arraycopy(dimensionSizes, begin, newDimensions, 0, end - begin);
+ return Shape.of(newDimensions);
+ }
+
+ /**
+ * Returns a new Shape, with a new first dimension added. In order for this call to succeed,
+ * {@link Shape#isUnknown()} must be {@code false}.
+ *
+ * @param firstDimension the dimension to prepend
+ * @return a new shape with the given dimension first, followed by this Shape's dimensions, never
+ * null
+ */
+ public Shape prepend(long firstDimension) {
+ long[] newDimensions = new long[dimensionSizes.length + 1];
+ newDimensions[0] = firstDimension;
+ System.arraycopy(dimensionSizes, 0, newDimensions, 1, dimensionSizes.length);
+
+ return Shape.of(newDimensions);
+ }
+
+ /**
+ * Returns a new Shape, with a new last dimension added. In order for this call to succeed, {@link
+ * Shape#isUnknown()} must be {@code false}.
+ *
+ * @param lastDimension the dimension to append
+ * @return a new Shape with this Shape's dimensions followed by the given dimension, never null
+ */
+ public Shape append(long lastDimension) {
+ long[] newDimensions = new long[dimensionSizes.length + 1];
+ newDimensions[newDimensions.length - 1] = lastDimension;
+ System.arraycopy(dimensionSizes, 0, newDimensions, 0, dimensionSizes.length);
+
+ return Shape.of(newDimensions);
+ }
+
+ /**
+ * Returns a new Shape, with another Shape's dimensions prepended. For both this Shape and the
+ * other Shape, {@link Shape#isUnknown()} must return false. E.g. {@code
+ * Shape.of(3,4).prepend(Shape.of(1,2)) => Shape.of(1,2,3,4) }
+ *
+ * @param other another Shape, must not be {@code null}, must not be unknown
+ * @return A new Shape consisting of the given Shape's dimensions followed by this Shape's
+ * dimensions, never null
+ */
+ public Shape prepend(Shape other) {
+ long[] newDimensions = new long[other.dimensionSizes.length + dimensionSizes.length];
+ System.arraycopy(other.dimensionSizes, 0, newDimensions, 0, other.dimensionSizes.length);
+ System.arraycopy(
+ dimensionSizes, 0, newDimensions, other.dimensionSizes.length, dimensionSizes.length);
+ return Shape.of(newDimensions);
+ }
+
+ /**
+ * Returns a new Shape, with another Shapes' dimensions appended. For both this Shape and the
+ * other Shape, {@link Shape#isUnknown()} must return false. E.g. @code
+ * Shape.of(3,4).append(Shape.of(1,2)) => Shape.of(3,4,1,2) }
+ *
+ * @param other another Shape, must not be {@code null}, must not be unknown
+ * @return A new Shape consisting of this Shape's dimensions followed by the given Shape's
+ * dimensions
+ */
+ public Shape append(Shape other) {
+ long[] newDimensions = new long[dimensionSizes.length + other.dimensionSizes.length];
+ System.arraycopy(dimensionSizes, 0, newDimensions, 0, dimensionSizes.length);
+ System.arraycopy(
+ other.dimensionSizes, 0, newDimensions, dimensionSizes.length, other.dimensionSizes.length);
+ return Shape.of(newDimensions);
+ }
+
+ private static long computeSize(long[] dimensionSizes) {
+ if (dimensionSizes == null) {
+ return UNKNOWN_SIZE;
+ }
+ long computedSize = 1L;
+ for (long dimensionSize : dimensionSizes) {
+ if (dimensionSize == UNKNOWN_SIZE) {
+ return UNKNOWN_SIZE;
+ }
+ computedSize *= dimensionSize;
+ }
+ return computedSize;
+ }
+
+ /**
+ * Determines whether another shape is compatible with this one.
+ *
+ *
+ *
+ * Two possibly-partially-defined shapes are compatible if there exists a fully-defined shape
+ * that both shapes can represent. Thus, compatibility allows the shape inference code to reason
+ * about partially-defined shapes. For example:
+ *
+ * The compatibility relation is reflexive and symmetric, but not transitive. For example,
+ * Compatibility is not the same as broadcasting. Compatible shapes must have the same number
+ * of dimensions and for each dimension pair, one dimension has to equal the other dimensions or
+ * at least one of the dimensions in the pair has to be UNKNOWN_SIZE.
+ *
+ * Broadcasting allows different dimensions, but paired dimensions have to either be equal, or
+ * one dimension must be 1. If one shape has less dimensions than another shape, the smaller shape
+ * is "stretched" with dimensions of 1.
+ *
+ * @param shape The other shape
+ * @return true, if the two shapes are compatible.
+ */
+ public boolean isCompatibleWith(Shape shape) {
+ if (!this.isUnknown() && !shape.isUnknown()) {
+ if (numDimensions() != shape.numDimensions()) {
+ return false;
+ }
+ for (int i = 0; i < numDimensions(); i++) {
+ if (!isCompatible(get(i), shape.get(i))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Test to see if two shape dimensions are compatible.
+ *
+ * The dimensions are compatible if either dimension is For example, given a 3x3x2 matrix, the return value will be 18.
+ *
+ * @return number of values in this element
+ */
+ default long size() {
+ return shape().size();
+ }
+}
diff --git a/tensorflow-ndarray/src/main/java/org/tensorflow/ndarray/ShortNdArray.java b/tensorflow-ndarray/src/main/java/org/tensorflow/ndarray/ShortNdArray.java
new file mode 100644
index 00000000000..1cf837cd15e
--- /dev/null
+++ b/tensorflow-ndarray/src/main/java/org/tensorflow/ndarray/ShortNdArray.java
@@ -0,0 +1,115 @@
+/*
+Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+=======================================================================
+*/
+package org.tensorflow.ndarray;
+
+import org.tensorflow.ndarray.buffer.DataBuffer;
+import org.tensorflow.ndarray.buffer.ShortDataBuffer;
+import org.tensorflow.ndarray.index.Index;
+
+/** An {@link NdArray} of shorts. */
+public interface ShortNdArray extends NdArray To access the scalar element, the number of coordinates provided must be equal to the number
+ * of dimensions of this array (i.e. its rank). For example:
+ *
+ * To access the scalar element, the number of coordinates provided must be equal to the number
+ * of dimensions of this array (i.e. its rank). For example:
+ *
+ * Indices are a A 2-D long array of shape {@code [N, ndims]}, that specifies the indices of
+ * the elements in the sparse array that contain nonzero values (elements are zero-indexed).
+ *
+ * For example, {@code indices=[[1,3], [2,4]]} specifies that the elements with indexes of
+ * coordinates {@code [1,3]} and {@code [2,4]} have nonzero values.
+ *
+ * @return the Indices
+ */
+ LongNdArray getIndices();
+
+ /**
+ * Gets the values.
+ *
+ * Values are a 1-D array of any type and shape {@code [N]}, that supplies the values for each
+ * element in indices.
+ *
+ * For example, given {@code indices=[[1,3], [2,4]]}, and {@code values=[18, 3.6]} specifies
+ * that element {@code [1,3]} of the sparse array has a value of {@code 18}, and element {@code
+ * [2,4]} of the sparse array has a value of {@code 3.6}.
+ *
+ * @return the values
+ */
+ U getValues();
+}
diff --git a/tensorflow-ndarray/src/main/java/org/tensorflow/ndarray/StdArrays.java b/tensorflow-ndarray/src/main/java/org/tensorflow/ndarray/StdArrays.java
new file mode 100644
index 00000000000..3ec5ec77df8
--- /dev/null
+++ b/tensorflow-ndarray/src/main/java/org/tensorflow/ndarray/StdArrays.java
@@ -0,0 +1,3898 @@
+package org.tensorflow.ndarray;
+
+import java.lang.reflect.Array;
+import org.tensorflow.ndarray.buffer.DataBuffers;
+
+/** Utility class for working with {@link NdArray} instances mixed with standard Java arrays. */
+public final class StdArrays {
+
+ /**
+ * Copy an array of ints in a new {@link IntNdArray}
+ *
+ * @param array source array
+ * @return the {@code IntNdArray} copy
+ */
+ public static IntNdArray ndCopyOf(int[] array) {
+ IntNdArray ndArray = NdArrays.ofInts(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 2-dimensional array of ints in a new {@link IntNdArray}
+ *
+ * @param array source array
+ * @return the {@code IntNdArray} copy
+ */
+ public static IntNdArray ndCopyOf(int[][] array) {
+ IntNdArray ndArray = NdArrays.ofInts(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 3-dimensional array of ints in a new {@link IntNdArray}
+ *
+ * @param array source array
+ * @return the {@code IntNdArray} copy
+ */
+ public static IntNdArray ndCopyOf(int[][][] array) {
+ IntNdArray ndArray = NdArrays.ofInts(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 4-dimensional array of ints in a new {@link IntNdArray}
+ *
+ * @param array source array
+ * @return the {@code IntNdArray} copy
+ */
+ public static IntNdArray ndCopyOf(int[][][][] array) {
+ IntNdArray ndArray = NdArrays.ofInts(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 5-dimensional array of ints in a new {@link IntNdArray}
+ *
+ * @param array source array
+ * @return the {@code IntNdArray} copy
+ */
+ public static IntNdArray ndCopyOf(int[][][][][] array) {
+ IntNdArray ndArray = NdArrays.ofInts(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 6-dimensional array of ints in a new {@link IntNdArray}
+ *
+ * @param array source array
+ * @return the {@code IntNdArray} copy
+ */
+ public static IntNdArray ndCopyOf(int[][][][][][] array) {
+ IntNdArray ndArray = NdArrays.ofInts(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy an array of longs in a new {@link LongNdArray}
+ *
+ * @param array source array
+ * @return the {@code LongNdArray} copy
+ */
+ public static LongNdArray ndCopyOf(long[] array) {
+ LongNdArray ndArray = NdArrays.ofLongs(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 2-dimensional array of longs in a new {@link LongNdArray}
+ *
+ * @param array source array
+ * @return the {@code LongNdArray} copy
+ */
+ public static LongNdArray ndCopyOf(long[][] array) {
+ LongNdArray ndArray = NdArrays.ofLongs(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 3-dimensional array of longs in a new {@link LongNdArray}
+ *
+ * @param array source array
+ * @return the {@code LongNdArray} copy
+ */
+ public static LongNdArray ndCopyOf(long[][][] array) {
+ LongNdArray ndArray = NdArrays.ofLongs(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 4-dimensional array of longs in a new {@link LongNdArray}
+ *
+ * @param array source array
+ * @return the {@code LongNdArray} copy
+ */
+ public static LongNdArray ndCopyOf(long[][][][] array) {
+ LongNdArray ndArray = NdArrays.ofLongs(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 5-dimensional array of longs in a new {@link LongNdArray}
+ *
+ * @param array source array
+ * @return the {@code LongNdArray} copy
+ */
+ public static LongNdArray ndCopyOf(long[][][][][] array) {
+ LongNdArray ndArray = NdArrays.ofLongs(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 6-dimensional array of longs in a new {@link LongNdArray}
+ *
+ * @param array source array
+ * @return the {@code LongNdArray} copy
+ */
+ public static LongNdArray ndCopyOf(long[][][][][][] array) {
+ LongNdArray ndArray = NdArrays.ofLongs(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy an array of floats in a new {@link FloatNdArray}
+ *
+ * @param array source array
+ * @return the {@code FloatNdArray} copy
+ */
+ public static FloatNdArray ndCopyOf(float[] array) {
+ FloatNdArray ndArray = NdArrays.ofFloats(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 2-dimensional array of floats in a new {@link FloatNdArray}
+ *
+ * @param array source array
+ * @return the {@code FloatNdArray} copy
+ */
+ public static FloatNdArray ndCopyOf(float[][] array) {
+ FloatNdArray ndArray = NdArrays.ofFloats(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 3-dimensional array of floats in a new {@link FloatNdArray}
+ *
+ * @param array source array
+ * @return the {@code FloatNdArray} copy
+ */
+ public static FloatNdArray ndCopyOf(float[][][] array) {
+ FloatNdArray ndArray = NdArrays.ofFloats(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 4-dimensional array of floats in a new {@link FloatNdArray}
+ *
+ * @param array source array
+ * @return the {@code FloatNdArray} copy
+ */
+ public static FloatNdArray ndCopyOf(float[][][][] array) {
+ FloatNdArray ndArray = NdArrays.ofFloats(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 5-dimensional array of floats in a new {@link FloatNdArray}
+ *
+ * @param array source array
+ * @return the {@code FloatNdArray} copy
+ */
+ public static FloatNdArray ndCopyOf(float[][][][][] array) {
+ FloatNdArray ndArray = NdArrays.ofFloats(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 6-dimensional array of floats in a new {@link FloatNdArray}
+ *
+ * @param array source array
+ * @return the {@code FloatNdArray} copy
+ */
+ public static FloatNdArray ndCopyOf(float[][][][][][] array) {
+ FloatNdArray ndArray = NdArrays.ofFloats(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy an array of doubles in a new {@link DoubleNdArray}
+ *
+ * @param array source array
+ * @return the {@code DoubleNdArray} copy
+ */
+ public static DoubleNdArray ndCopyOf(double[] array) {
+ DoubleNdArray ndArray = NdArrays.ofDoubles(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 2-dimensional array of doubles in a new {@link DoubleNdArray}
+ *
+ * @param array source array
+ * @return the {@code DoubleNdArray} copy
+ */
+ public static DoubleNdArray ndCopyOf(double[][] array) {
+ DoubleNdArray ndArray = NdArrays.ofDoubles(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 3-dimensional array of doubles in a new {@link DoubleNdArray}
+ *
+ * @param array source array
+ * @return the {@code DoubleNdArray} copy
+ */
+ public static DoubleNdArray ndCopyOf(double[][][] array) {
+ DoubleNdArray ndArray = NdArrays.ofDoubles(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 4-dimensional array of doubles in a new {@link DoubleNdArray}
+ *
+ * @param array source array
+ * @return the {@code DoubleNdArray} copy
+ */
+ public static DoubleNdArray ndCopyOf(double[][][][] array) {
+ DoubleNdArray ndArray = NdArrays.ofDoubles(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 5-dimensional array of doubles in a new {@link DoubleNdArray}
+ *
+ * @param array source array
+ * @return the {@code DoubleNdArray} copy
+ */
+ public static DoubleNdArray ndCopyOf(double[][][][][] array) {
+ DoubleNdArray ndArray = NdArrays.ofDoubles(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 6-dimensional array of doubles in a new {@link DoubleNdArray}
+ *
+ * @param array source array
+ * @return the {@code DoubleNdArray} copy
+ */
+ public static DoubleNdArray ndCopyOf(double[][][][][][] array) {
+ DoubleNdArray ndArray = NdArrays.ofDoubles(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy an array of bytes in a new {@link ByteNdArray}
+ *
+ * @param array source array
+ * @return the {@code ByteNdArray} copy
+ */
+ public static ByteNdArray ndCopyOf(byte[] array) {
+ ByteNdArray ndArray = NdArrays.ofBytes(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 2-dimensional array of bytes in a new {@link ByteNdArray}
+ *
+ * @param array source array
+ * @return the {@code ByteNdArray} copy
+ */
+ public static ByteNdArray ndCopyOf(byte[][] array) {
+ ByteNdArray ndArray = NdArrays.ofBytes(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 3-dimensional array of bytes in a new {@link ByteNdArray}
+ *
+ * @param array source array
+ * @return the {@code ByteNdArray} copy
+ */
+ public static ByteNdArray ndCopyOf(byte[][][] array) {
+ ByteNdArray ndArray = NdArrays.ofBytes(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 4-dimensional array of bytes in a new {@link ByteNdArray}
+ *
+ * @param array source array
+ * @return the {@code ByteNdArray} copy
+ */
+ public static ByteNdArray ndCopyOf(byte[][][][] array) {
+ ByteNdArray ndArray = NdArrays.ofBytes(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 5-dimensional array of bytes in a new {@link ByteNdArray}
+ *
+ * @param array source array
+ * @return the {@code ByteNdArray} copy
+ */
+ public static ByteNdArray ndCopyOf(byte[][][][][] array) {
+ ByteNdArray ndArray = NdArrays.ofBytes(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 6-dimensional array of bytes in a new {@link ByteNdArray}
+ *
+ * @param array source array
+ * @return the {@code ByteNdArray} copy
+ */
+ public static ByteNdArray ndCopyOf(byte[][][][][][] array) {
+ ByteNdArray ndArray = NdArrays.ofBytes(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy an array of shorts in a new {@link ShortNdArray}
+ *
+ * @param array source array
+ * @return the {@code ShortNdArray} copy
+ */
+ public static ShortNdArray ndCopyOf(short[] array) {
+ ShortNdArray ndArray = NdArrays.ofShorts(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 2-dimensional array of shorts in a new {@link ShortNdArray}
+ *
+ * @param array source array
+ * @return the {@code ShortNdArray} copy
+ */
+ public static ShortNdArray ndCopyOf(short[][] array) {
+ ShortNdArray ndArray = NdArrays.ofShorts(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 3-dimensional array of shorts in a new {@link ShortNdArray}
+ *
+ * @param array source array
+ * @return the {@code ShortNdArray} copy
+ */
+ public static ShortNdArray ndCopyOf(short[][][] array) {
+ ShortNdArray ndArray = NdArrays.ofShorts(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 4-dimensional array of shorts in a new {@link ShortNdArray}
+ *
+ * @param array source array
+ * @return the {@code ShortNdArray} copy
+ */
+ public static ShortNdArray ndCopyOf(short[][][][] array) {
+ ShortNdArray ndArray = NdArrays.ofShorts(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 5-dimensional array of shorts in a new {@link ShortNdArray}
+ *
+ * @param array source array
+ * @return the {@code ShortNdArray} copy
+ */
+ public static ShortNdArray ndCopyOf(short[][][][][] array) {
+ ShortNdArray ndArray = NdArrays.ofShorts(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 6-dimensional array of shorts in a new {@link ShortNdArray}
+ *
+ * @param array source array
+ * @return the {@code ShortNdArray} copy
+ */
+ public static ShortNdArray ndCopyOf(short[][][][][][] array) {
+ ShortNdArray ndArray = NdArrays.ofShorts(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy an array of booleans in a new {@link BooleanNdArray}
+ *
+ * @param array source array
+ * @return the {@code BooleanNdArray} copy
+ */
+ public static BooleanNdArray ndCopyOf(boolean[] array) {
+ BooleanNdArray ndArray = NdArrays.ofBooleans(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 2-dimensional array of booleans in a new {@link BooleanNdArray}
+ *
+ * @param array source array
+ * @return the {@code BooleanNdArray} copy
+ */
+ public static BooleanNdArray ndCopyOf(boolean[][] array) {
+ BooleanNdArray ndArray = NdArrays.ofBooleans(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 3-dimensional array of booleans in a new {@link BooleanNdArray}
+ *
+ * @param array source array
+ * @return the {@code BooleanNdArray} copy
+ */
+ public static BooleanNdArray ndCopyOf(boolean[][][] array) {
+ BooleanNdArray ndArray = NdArrays.ofBooleans(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 4-dimensional array of booleans in a new {@link BooleanNdArray}
+ *
+ * @param array source array
+ * @return the {@code BooleanNdArray} copy
+ */
+ public static BooleanNdArray ndCopyOf(boolean[][][][] array) {
+ BooleanNdArray ndArray = NdArrays.ofBooleans(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 5-dimensional array of booleans in a new {@link BooleanNdArray}
+ *
+ * @param array source array
+ * @return the {@code BooleanNdArray} copy
+ */
+ public static BooleanNdArray ndCopyOf(boolean[][][][][] array) {
+ BooleanNdArray ndArray = NdArrays.ofBooleans(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy a 6-dimensional array of booleans in a new {@link BooleanNdArray}
+ *
+ * @param array source array
+ * @return the {@code BooleanNdArray} copy
+ */
+ public static BooleanNdArray ndCopyOf(boolean[][][][][][] array) {
+ BooleanNdArray ndArray = NdArrays.ofBooleans(shapeOf(array));
+ copyTo(array, ndArray);
+ return ndArray;
+ }
+
+ /**
+ * Copy an array of objects in a new {@link NdArray}
+ *
+ * @param array source array
+ * @param This method transfers values from this buffer into the given destination array. If there are
+ * fewer values in the buffer than are required to satisfy the request, that is, if {@code
+ * dst.length > size()}, then no values are transferred and a BufferUnderflowException is thrown.
+ *
+ * Otherwise, this method copies {@code n = dst.length} values from this buffer into the given
+ * array.
+ *
+ * @param dst the array into which values are to be written
+ * @return this buffer
+ * @throws BufferUnderflowException if there are not enough values to copy from this buffer
+ */
+ default BooleanDataBuffer read(boolean[] dst) {
+ return read(dst, 0, dst.length);
+ }
+
+ /**
+ * Bulk get method, using boolean arrays.
+ *
+ * This method transfers values from this buffer into the given destination array. If there are
+ * fewer values in the buffer than are required to satisfy the request, that is, if {@code length
+ * > size()}, then no values are transferred and a BufferUnderflowException is thrown.
+ *
+ * Otherwise, this method copies {@code n = length} values from this buffer into the given
+ * array starting at the given offset.
+ *
+ * @param dst the array into which values are to be written
+ * @param offset the offset within the array of the first value to be written; must be
+ * non-negative and no larger than {@code dst.length}
+ * @param length the maximum number of values to be written to the given array; must be
+ * non-negative and no larger than {@code dst.length - offset}
+ * @return this buffer
+ * @throws BufferUnderflowException if there are fewer than length values remaining in this buffer
+ * @throws IndexOutOfBoundsException if the preconditions on the offset and length parameters do
+ * not hold
+ */
+ BooleanDataBuffer read(boolean[] dst, int offset, int length);
+
+ /**
+ * Bulk put method, using boolean arrays.
+ *
+ * This method transfers the values in the given source array into this buffer. If there are
+ * more values in the source array than in this buffer, that is, if {@code src.length > size()},
+ * then no values are transferred and a BufferOverflowException is thrown.
+ *
+ * Otherwise, this method copies {@code n = src.length} values from the given array.
+ *
+ * @param src the source array from which values are to be read
+ * @return this buffer
+ * @throws BufferOverflowException if there is insufficient space in this buffer for the values in
+ * the source array
+ * @throws ReadOnlyBufferException if this buffer is read-only
+ */
+ default BooleanDataBuffer write(boolean[] src) {
+ return write(src, 0, src.length);
+ }
+
+ /**
+ * Bulk put method, using boolean arrays.
+ *
+ * This method transfers the values in the given source array into this buffer. If there are
+ * more values in the source array than in this buffer, that is, if {@code length > size()}, then
+ * no values are transferred and a BufferOverflowException is thrown.
+ *
+ * Otherwise, this method copies {@code n = length} values from the given array into this
+ * buffer, starting at the given offset.
+ *
+ * @param src the source array from which values are to be read
+ * @param offset the offset within the array of the first value to be read; must be non-negative
+ * and no larger than {@code src.length}
+ * @param length the number of values to be read from the given array; must be non-negative and no
+ * larger than {@code src.length - offset}
+ * @return this buffer
+ * @throws BufferOverflowException if there is insufficient space in this buffer for the values in
+ * the source array
+ * @throws IndexOutOfBoundsException if the preconditions on the offset and length parameters do
+ * not hold
+ * @throws ReadOnlyBufferException if this buffer is read-only
+ */
+ BooleanDataBuffer write(boolean[] src, int offset, int length);
+
+ @Override
+ default Boolean getObject(long index) {
+ return getBoolean(index);
+ }
+
+ @Override
+ default BooleanDataBuffer setObject(Boolean value, long index) {
+ return setBoolean(value, index);
+ }
+
+ @Override
+ BooleanDataBuffer copyTo(DataBuffer This method transfers values from this buffer into the given destination array. If there are
+ * fewer values in the buffer than are required to satisfy the request, that is, if {@code
+ * dst.length > size()}, then no values are transferred and a BufferUnderflowException is thrown.
+ *
+ * Otherwise, this method copies {@code n = dst.length} values from this buffer into the given
+ * array.
+ *
+ * @param dst the array into which values are to be written
+ * @return this buffer
+ * @throws BufferUnderflowException if there are not enough values to copy from this buffer
+ */
+ default ByteDataBuffer read(byte[] dst) {
+ return read(dst, 0, dst.length);
+ }
+
+ /**
+ * Bulk get method, using byte arrays.
+ *
+ * This method transfers values from this buffer into the given destination array. If there are
+ * fewer values in the buffer than are required to satisfy the request, that is, if {@code length
+ * > size()}, then no values are transferred and a BufferUnderflowException is thrown.
+ *
+ * Otherwise, this method copies {@code n = length} values from this buffer into the given
+ * array starting at the given offset.
+ *
+ * @param dst the array into which values are to be written
+ * @param offset the offset within the array of the first value to be written; must be
+ * non-negative and no larger than {@code dst.length}
+ * @param length the maximum number of values to be written to the given array; must be
+ * non-negative and no larger than {@code dst.length - offset}
+ * @return this buffer
+ * @throws BufferUnderflowException if there are fewer than length values remaining in this buffer
+ * @throws IndexOutOfBoundsException if the preconditions on the offset and length parameters do
+ * not hold
+ */
+ ByteDataBuffer read(byte[] dst, int offset, int length);
+
+ /**
+ * Bulk put method, using byte arrays.
+ *
+ * This method transfers the values in the given source array into this buffer. If there are
+ * more values in the source array than in this buffer, that is, if {@code src.length > size()},
+ * then no values are transferred and a BufferOverflowException is thrown.
+ *
+ * Otherwise, this method copies {@code n = src.length} values from the given array.
+ *
+ * @param src the source array from which values are to be read
+ * @return this buffer
+ * @throws BufferOverflowException if there is insufficient space in this buffer for the values in
+ * the source array
+ * @throws ReadOnlyBufferException if this buffer is read-only
+ */
+ default ByteDataBuffer write(byte[] src) {
+ return write(src, 0, src.length);
+ }
+
+ /**
+ * Bulk put method, using byte arrays.
+ *
+ * This method transfers the values in the given source array into this buffer. If there are
+ * more values in the source array than in this buffer, that is, if {@code length > size()}, then
+ * no values are transferred and a BufferOverflowException is thrown.
+ *
+ * Otherwise, this method copies {@code n = length} values from the given array into this
+ * buffer, starting at the given offset.
+ *
+ * @param src the source array from which values are to be read
+ * @param offset the offset within the array of the first value to be read; must be non-negative
+ * and no larger than {@code src.length}
+ * @param length the number of values to be read from the given array; must be non-negative and no
+ * larger than {@code src.length - offset}
+ * @return this buffer
+ * @throws BufferOverflowException if there is insufficient space in this buffer for the values in
+ * the source array
+ * @throws IndexOutOfBoundsException if the preconditions on the offset and length parameters do
+ * not hold
+ * @throws ReadOnlyBufferException if this buffer is read-only
+ */
+ ByteDataBuffer write(byte[] src, int offset, int length);
+
+ /**
+ * Return this byte buffer as a buffer of ints.
+ *
+ * The returned buffer provides a different view on the same memory as the original byte
+ * buffer, meaning that changing a value in one will affect the other.
+ *
+ * @return this buffer as a {@link IntDataBuffer}
+ * @throws IllegalStateException if this buffer cannot be converted
+ */
+ IntDataBuffer asInts();
+
+ /**
+ * Return this byte buffer as a buffer of shorts.
+ *
+ * The returned buffer provides a different view on the same memory as the original byte
+ * buffer, meaning that changing a value in one will affect the other.
+ *
+ * @return this buffer as a {@link ShortDataBuffer}
+ * @throws IllegalStateException if this buffer cannot be converted
+ */
+ ShortDataBuffer asShorts();
+
+ /**
+ * Return this byte buffer as a buffer of longs.
+ *
+ * The returned buffer provides a different view on the same memory as the original byte
+ * buffer, meaning that changing a value in one will affect the other.
+ *
+ * @return this buffer as a {@link LongDataBuffer}
+ * @throws IllegalStateException if this buffer cannot be converted
+ */
+ LongDataBuffer asLongs();
+
+ /**
+ * Return this byte buffer as a buffer of floats.
+ *
+ * The returned buffer provides a different view on the same memory as the original byte
+ * buffer, meaning that changing a value in one will affect the other.
+ *
+ * @return this buffer as a {@link FloatDataBuffer}
+ * @throws IllegalStateException if this buffer cannot be converted
+ */
+ FloatDataBuffer asFloats();
+
+ /**
+ * Return this byte buffer as a buffer of doubles.
+ *
+ * The returned buffer provides a different view on the same memory as the original byte
+ * buffer, meaning that changing a value in one will affect the other.
+ *
+ * @return this buffer as a {@link DoubleDataBuffer}
+ * @throws IllegalStateException if this buffer cannot be converted
+ */
+ DoubleDataBuffer asDoubles();
+
+ /**
+ * Return this byte buffer as a buffer of booleans.
+ *
+ * The returned buffer provides a different view on the same memory as the original byte
+ * buffer, meaning that changing a value in one will affect the other.
+ *
+ * @return this buffer as a {@link BooleanDataBuffer}
+ * @throws IllegalStateException if this buffer cannot be converted
+ */
+ BooleanDataBuffer asBooleans();
+
+ @Override
+ default Byte getObject(long index) {
+ return getByte(index);
+ }
+
+ @Override
+ default ByteDataBuffer setObject(Byte value, long index) {
+ return setByte(value, index);
+ }
+
+ @Override
+ ByteDataBuffer copyTo(DataBuffer Instances of {@code DataBuffer} map native or heap memory segments to a linear view that
+ * supports:
+ *
+ * For exemple, in case of a byte buffer, this value is equal to the number of bytes this
+ * buffer can hold. For an integer buffer, it is equal to the number of integers, therefore the
+ * size in bytes of this buffer is {@code size() * Integer.BYTES}.
+ *
+ * @return the buffer size
+ */
+ long size();
+
+ /**
+ * Tells whether or not this buffer is backed by an accessible array.
+ *
+ * @return true if, and only if, this buffer is read-only
+ */
+ boolean isReadOnly();
+
+ /**
+ * Reads the value at the given index.
+ *
+ * Important: Usage of this method should be limited to buffers of non-primitive types
+ * or when the data type is not deterministically known by the caller. In any other case, prefer
+ * the usage of its primitive variant which will significantly improve performances (e.g. {@code
+ * IntDataBuffer.getInt(idx)}
+ *
+ * @param index the index from which the float will be read
+ * @return the value at the given index
+ * @throws IndexOutOfBoundsException if index is negative or not smaller than the buffer size
+ */
+ T getObject(long index);
+
+ /**
+ * Writes the given value into this buffer at the given index.
+ *
+ * Important: Usage of this method should be limited to buffers of non-primitive types
+ * or when the data type is not deterministically known by the caller. In any other case, prefer
+ * the usage of its primitive variant which will significantly improve performances (e.g. {@code
+ * IntDataBuffer.setInt(idx)}
+ *
+ * @param value the value to be written
+ * @param index the index at which the value will be written
+ * @return this buffer
+ * @throws IndexOutOfBoundsException if index is negative or not smaller than the buffer size
+ * @throws ReadOnlyBufferException if this buffer is read-only
+ */
+ DataBuffer This method transfers values from this buffer into the given destination array. If there are
+ * fewer values in the buffer than are required to satisfy the request, that is, if {@code
+ * dst.length > size()}, then no values are transferred and a BufferUnderflowException is thrown.
+ *
+ * Otherwise, this method copies {@code n = dst.length} values from this buffer into the given
+ * array.
+ *
+ * @param dst the array into which values are to be written
+ * @return this buffer
+ * @throws BufferUnderflowException if there are not enough values to copy from this buffer
+ */
+ default DataBuffer This method transfers values from this buffer into the given destination array. If there are
+ * fewer values in the buffer than are required to satisfy the request, that is, if {@code length
+ * > size()}, then no values are transferred and a BufferUnderflowException is thrown.
+ *
+ * Otherwise, this method copies {@code n = length} values from this buffer into the given
+ * array starting at the given offset.
+ *
+ * @param dst the array into which values are to be written
+ * @param offset the offset within the array of the first value to be written; must be
+ * non-negative and no larger than {@code dst.length}
+ * @param length the maximum number of values to be written to the given array; must be
+ * non-negative and no larger than {@code dst.length - offset}
+ * @return this buffer
+ * @throws BufferUnderflowException if there are fewer than length values remaining in this buffer
+ * @throws IndexOutOfBoundsException if the preconditions on the offset and length parameters do
+ * not hold
+ */
+ DataBuffer This method transfers the values in the given source array into this buffer. If there are
+ * more values in the source array than in this buffer, that is, if {@code src.length > size()},
+ * then no values are transferred and a BufferOverflowException is thrown.
+ *
+ * Otherwise, this method copies {@code n = src.length} values from the given array.
+ *
+ * @param src the source array from which values are to be read
+ * @return this buffer
+ * @throws BufferOverflowException if there is insufficient space in this buffer for the values in
+ * the source array
+ * @throws ReadOnlyBufferException if this buffer is read-only
+ */
+ default DataBuffer This method transfers the values in the given source array into this buffer. If there are
+ * more values in the source array than in this buffer, that is, if {@code length > size()}, then
+ * no values are transferred and a BufferOverflowException is thrown.
+ *
+ * Otherwise, this method copies {@code n = length} values from the given array into this
+ * buffer, starting at the given offset.
+ *
+ * @param src the source array from which values are to be read
+ * @param offset the offset within the array of the first value to be read; must be non-negative
+ * and no larger than {@code src.length}
+ * @param length the number of values to be read from the given array; must be non-negative and no
+ * larger than {@code src.length - offset}
+ * @return this buffer
+ * @throws BufferOverflowException if there is insufficient space in this buffer for the values in
+ * the source array
+ * @throws IndexOutOfBoundsException if the preconditions on the offset and length parameters do
+ * not hold
+ * @throws ReadOnlyBufferException if this buffer is read-only
+ */
+ DataBuffer If there are more values to copy than the destination buffer size, i.e. {@code size >
+ * dst.size()}, then no values are transferred and a BufferOverflowException is thrown. On the
+ * other hand, if there are more values to copy that the source buffer size, i.e. {@code >
+ * src.size()}, then a BufferUnderfloatException is thrown.
+ *
+ * Otherwise, this method copies {@code n = size} values from this buffer into the destination
+ * buffer.
+ *
+ * @param dst the destination buffer into which values are copied; must not be this buffer
+ * @param size number of values to copy to the destination buffer
+ * @return this buffer
+ * @throws IllegalArgumentException if the destination buffer is this buffer
+ * @throws ReadOnlyBufferException if the destination buffer is read-only
+ * @throws java.nio.BufferOverflowException if there is not enough space in destination buffer
+ * @throws java.nio.BufferUnderflowException if there are not enough values in the source buffer
+ */
+ DataBuffer The index must not be greater than this buffer size. Changes to this buffer's content will
+ * be visible in the new buffer and vice versa. The new buffer will be read-only if, and only if,
+ * this buffer is read-only.
+ *
+ * This call is equivalent to {@link #slice(long, long) slice(index, size() - index)}
+ *
+ * @param index index of the first value of the new buffer created, must not be greater than
+ * {@code size()}
+ * @return the new buffer
+ * @throws IllegalArgumentException if index do not pass validation checks
+ */
+ default DataBuffer The new size must not be greater than this buffer size. Changes to this buffer's content
+ * will be visible in the new buffer and vice versa. The new buffer will be read-only if, and only
+ * if, this buffer is read-only.
+ *
+ * This call is equivalent to {@link #slice(long, long) slice(0, size)}
+ *
+ * @param size size of this new buffer
+ * @return the new buffer
+ * @throws IllegalArgumentException if index and/or size values do not pass validation checks
+ */
+ default DataBuffer The index plus the new size must not be greater than this buffer size. Changes to this
+ * buffer's content will be visible in the new buffer and vice versa. The new buffer will be
+ * read-only if, and only if, this buffer is read-only.
+ *
+ * @param index index of the first value of the new buffer created
+ * @param size size of this new buffer, must not be greater than {@code size()}
+ * @return the new buffer
+ * @throws IllegalArgumentException if size value do not pass validation checks
+ */
+ DataBuffer{@code
+ * FloatNdArray matrix = NdArrays.ofFloats(shape(2, 2)); // matrix rank = 2
+ * matrix.getFloat(0, 1); // succeeds, returns 0.0f
+ * matrix.getFloat(0); // throws IllegalRankException
+ *
+ * FloatNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.getFloat(); // succeeds, returns 0.0f
+ * }
+ *
+ * @param coordinates coordinates of the scalar to resolve
+ * @return value of that scalar
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ float getFloat(long... coordinates);
+
+ /**
+ * Assigns the float value of the scalar found at the given coordinates.
+ *
+ * {@code
+ * FloatNdArray matrix = NdArrays.ofFloats(shape(2, 2)); // matrix rank = 2
+ * matrix.setFloat(10.0f, 0, 1); // succeeds
+ * matrix.setFloat(10.0f, 0); // throws IllegalRankException
+ *
+ * FloatNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.setFloat(10.0f); // succeeds
+ * }
+ *
+ * @param value value to assign
+ * @param coordinates coordinates of the scalar to assign
+ * @return this array
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ FloatNdArray setFloat(float value, long... coordinates);
+
+ @Override
+ FloatNdArray withShape(Shape shape);
+
+ @Override
+ FloatNdArray slice(Index... coordinates);
+
+ @Override
+ FloatNdArray get(long... coordinates);
+
+ @Override
+ FloatNdArray set(NdArray{@code
+ * IntNdArray matrix = NdArrays.ofInts(shape(2, 2)); // matrix rank = 2
+ * matrix.getInt(0, 1); // succeeds, returns 0
+ * matrix.getInt(0); // throws IllegalRankException
+ *
+ * IntNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.getInt(); // succeeds, returns 0
+ * }
+ *
+ * @param coordinates coordinates of the scalar to resolve
+ * @return value of that scalar
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ int getInt(long... coordinates);
+
+ /**
+ * Assigns the integer value of the scalar found at the given coordinates.
+ *
+ * {@code
+ * IntNdArray matrix = NdArrays.ofInts(shape(2, 2)); // matrix rank = 2
+ * matrix.setInt(10, 0, 1); // succeeds
+ * matrix.setInt(10, 0); // throws IllegalRankException
+ *
+ * IntNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.setInt(10); // succeeds
+ * }
+ *
+ * @param value value to assign
+ * @param coordinates coordinates of the scalar to assign
+ * @return this array
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ IntNdArray setInt(int value, long... coordinates);
+
+ /**
+ * Retrieve all scalar values of this array as a stream of integers.
+ *
+ * {@code
+ * LongNdArray matrix = NdArrays.ofLongs(shape(2, 2)); // matrix rank = 2
+ * matrix.getLong(0, 1); // succeeds, returns 0L
+ * matrix.getLong(0); // throws IllegalRankException
+ *
+ * LongNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.getLong(); // succeeds, returns 0L
+ * }
+ *
+ * @param coordinates coordinates of the scalar to resolve
+ * @return value of that scalar
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ long getLong(long... coordinates);
+
+ /**
+ * Assigns the long value of the scalar found at the given coordinates.
+ *
+ * {@code
+ * LongNdArray matrix = NdArrays.ofLongs(shape(2, 2)); // matrix rank = 2
+ * matrix.setLong(10L, 0, 1); // succeeds
+ * matrix.setLong(10L, 0); // throws IllegalRankException
+ *
+ * LongNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.setLong(10L); // succeeds
+ * }
+ *
+ * @param value value to assign
+ * @param coordinates coordinates of the scalar to assign
+ * @return this array
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ LongNdArray setLong(long value, long... coordinates);
+
+ /**
+ * Retrieve all scalar values of this array as a stream of longs.
+ *
+ * {@code
+ * // Creates a 2x3x2 matrix (of rank 3)
+ * FloatNdArray matrix3d = NdArrays.ofFloats(shape(2, 3, 2));
+ *
+ * // Initialize sub-matrices data with vectors
+ * matrix.set(NdArrays.vectorOf(1.0f, 2.0f), 0, 0)
+ * .set(NdArrays.vectorOf(3.0f, 4.0f), 0, 1)
+ * .set(NdArrays.vectorOf(5.0f, 6.0f), 0, 2)
+ * .set(NdArrays.vectorOf(7.0f, 8.0f), 1, 0)
+ * .set(NdArrays.vectorOf(9.0f, 10.0f), 1, 1)
+ * .set(NdArrays.vectorOf(11.0f, 12.0f), 1, 2);
+ *
+ * // Access the second 3x2 matrix (of rank 2)
+ * FloatNdArray matrix = matrix3d.get(1);
+ *
+ * // Access directly the float value at (1, 0) from the second matrix
+ * assertEquals(9.0f, matrix.getFloat(1, 0));
+ * }
+ *
+ * @param {@code
+ * // Iterate matrix for initializing each of its vectors
+ * matrixOfFloats.elements(0).forEach(v -> {
+ * v.set(vector(1.0f, 2.0f, 3.0f));
+ * });
+ *
+ * // Iterate a vector for reading each of its scalar
+ * vectorOfFloats.scalars().forEachIdx((coords, s) -> {
+ * System.out.println("Value " + s.getFloat() + " found at " + coords);
+ * });
+ * }
+ *
+ * @param dimensionIdx index of the dimension
+ * @return an {@code NdArray} sequence
+ * @throws IllegalArgumentException if {@code dimensionIdx} is greater or equal to the total
+ * number of dimensions of this array
+ */
+ NdArraySequence extends NdArray
+ *
+ *
+ * For example,
+ *
+ * {@code
+ * NdArrays.ofInts(Shape.scalar()).withShape(Shape.of(1, 1)); // ok
+ * NdArrays.ofInts(Shape.of(2, 3).withShape(Shape.of(3, 2)); // ok
+ * NdArrays.ofInts(Shape.scalar()).withShape(Shape.of(1, 2)); // not ok, sizes are different (1 != 2)
+ * NdArrays.ofInts(Shape.of(2, 3)).withShape(Shape.unknown()); // not ok, new shape unknown
+ * }
+ *
+ * {@code
+ * FloatNdArray matrix3d = NdArrays.ofFloats(shape(3, 2, 4)); // with [x, y, z] axes
+ *
+ * // Iterates elements on the x axis by preserving only the 3rd value on the z axis,
+ * // (i.e. [x, y, 2])
+ * matrix3d.slice(all(), all(), at(2)).elements(0).forEach(m -> {
+ * assertEquals(shape(2), m); // y=2, z=0 (scalar)
+ * });
+ *
+ * // Creates a slice that contains only the last element of the y axis and elements with an
+ * // odd `z` coordinate.
+ * FloatNdArray slice = matrix3d.slice(all(), at(1), odd());
+ * assertEquals(shape(3, 2), slice.shape()); // x=3, y=0 (scalar), z=2 (odd coordinates)
+ *
+ * // Iterates backward the elements on the x axis
+ * matrix3d.slice(flip()).elements(0).forEach(m -> {
+ * assertEquals(shape(2, 4), m); // y=2, z=4
+ * });
+ * }
+ *
+ * @param indices index selectors per dimensions, starting from dimension 0 of this array.
+ * @return the element resulting of the index selection
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ */
+ NdArray{@code
+ * FloatNdArray matrix = NdArrays.ofFloats(shape(2, 2)); // matrix rank = 2
+ * matrix.set(vector(10.0f, 20.0f), 0); // success
+ * matrix.set(scalar(10.0f), 1, 0); // success
+ * }
+ *
+ * @param src an array of the values to assign
+ * @param coordinates coordinates of the element to assign
+ * @return this array
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ */
+ NdArray{@code
+ * FloatNdArray matrix = NdArrays.ofFloats(shape(2, 2)); // matrix rank = 2
+ * matrix.getObject(0, 1); // succeeds, returns 0.0f
+ * matrix.getObject(0); // throws IllegalRankException
+ *
+ * FloatNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.getObject(); // succeeds, returns 0.0f
+ * }
+ *
+ * Note: if this array stores values of a primitive type, prefer the usage of the specialized
+ * method in the subclass for that type. For example, {@code floatArray.getFloat(0); }.
+ *
+ * @param coordinates coordinates of the scalar to resolve
+ * @return value of that scalar
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ T getObject(long... coordinates);
+
+ /**
+ * Assigns the value of the scalar found at the given coordinates.
+ *
+ * {@code
+ * FloatNdArray matrix = NdArrays.ofFloats(shape(2, 2)); // matrix rank = 2
+ * matrix.setObject(10.0f, 0, 1); // succeeds
+ * matrix.setObject(10.0f, 0); // throws IllegalRankException
+ *
+ * FloatNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.setObject(10.0f); // succeeds
+ * }
+ *
+ * Note: if this array stores values of a primitive type, prefer the usage of the specialized
+ * method in the subclass for that type. For example, {@code floatArray.setFloat(10.0f, 0); }
+ *
+ * @param value the value to assign
+ * @param coordinates coordinates of the scalar to assign
+ * @return this array
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ NdArray{@code
+ * IntNdArray array = NdArrays.ofInts(Shape.of(2, 2))
+ * .set(NdArrays.vectorOf(1, 2), 0)
+ * .set(NdArrays.vectorOf(3, 4), 1);
+ *
+ * assertEquals(array, StdArrays.ndCopyOf(new int[][] {{1, 2}, {3, 4}})); // true
+ * assertEquals(array, StdArrays.ndCopyOf(new Integer[][] {{1, 2}, {3, 4}})); // true, as Integers are equal to ints
+ * assertNotEquals(array, NdArrays.vectorOf(1, 2, 3, 4)); // false, different shapes
+ * assertNotEquals(array, StdArrays.ndCopyOf(new int[][] {{3, 4}, {1, 2}})); // false, different order
+ * assertNotEquals(array, StdArrays.ndCopyOf(new long[][] {{1L, 2L}, {3L, 4L}})); // false, different types
+ * }
+ *
+ * {@code
+ * final List
+ *
+ * @return a sequence that returns each elements iterated as a new slice
+ * @see DataBufferWindow
+ */
+ NdArraySequence{@code
+ * // A 2-element vector.
+ * Shape vector = Shape.of(2);
+ *
+ * // A 2x3 matrix.
+ * Shape matrix = Shape.of(2, 3);
+ *
+ * // A matrix with 4 columns but an unknown number of rows.
+ * // This is typically used to indicate the shape of tensors that represent
+ * // a variable-sized batch of values. The Shape below might represent a
+ * // variable-sized batch of 4-element vectors.
+ * Shape batch = Shape.of(-1, 4);
+ *
+ * // A scalar. For readability, you should prefer calling Shape.scalar()
+ * Shape scalar = Shape.of()
+ * }
+ *
+ * @param dimensionSizes number of elements in each dimension of this shape, if any, or {@link
+ * Shape#UNKNOWN_SIZE} if unknown.
+ * @return a new shape
+ */
+ public static Shape of(long... dimensionSizes) {
+ if (dimensionSizes == null || dimensionSizes.length == 0) {
+ return scalar();
+ }
+ return new Shape(dimensionSizes);
+ }
+
+ /**
+ * Returns the total number of elements a Tensor with this Shape would have.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * Shape.unknown() is compatible with all shapes.
+ * Shape(UNKNOWN_SIZE, UNKNOWN_SIZE) is compatible with all two-dimensional
+ * shapes, such as Shape(32, 784), and also Shape.unknown(). It is
+ * not compatible with, for example, Shape(UNKNOWN_SIZE) or
+ * Shape(UNKNOWN_SIZE, UNKNOWN_SIZE, UNKNOWN_SIZE).
+ * Shape(32, UNKNOWN_SIZE) is compatible with all two-dimensional shapes with
+ * size 32 in the 0th dimension, and also Shape(UNKNOWN_SIZE, UNKNOWN_SIZE) and
+ * Shape.unknown(). It is not compatible with, for example, Shape(32)
+ * , Shape(32, UNKNOWN_SIZE, 1) or Shape(64, UNKNOWN_SIZE).
+ * Shape(32, 784) is compatible with itself, and also
+ * Shape(32, UNKNOWN_SIZE), Shape(UNKNOWN_SIZE, 784),
+ * Shape(UNKNOWN_SIZE, UNKNOWN_SIZE) and Shape.unknown(). It is not
+ * compatible with, for example, Shape(32, 1, 784) or Shape(UNKNOWN_SIZE)
+ * .
+ * Shape(32, 784) is compatible with Shape.unknown(), and
+ * Shape.unknown() is compatible with Shape(4, 4), but Shape(32, 784)
+ * is not compatible with Shape(4, 4).
+ *
+ * Shape.UNKNOWN_SIZE or both
+ * dimensions are equal
+ *
+ * @param dim the first dimension
+ * @param otherDim the second dimension
+ * @return true, if both dimensions are compatible
+ */
+ public static boolean isCompatible(long dim, long otherDim) {
+ return dim == Shape.UNKNOWN_SIZE || otherDim == Shape.UNKNOWN_SIZE || dim == otherDim;
+ }
+}
diff --git a/tensorflow-ndarray/src/main/java/org/tensorflow/ndarray/Shaped.java b/tensorflow-ndarray/src/main/java/org/tensorflow/ndarray/Shaped.java
new file mode 100644
index 00000000000..244550bb4a7
--- /dev/null
+++ b/tensorflow-ndarray/src/main/java/org/tensorflow/ndarray/Shaped.java
@@ -0,0 +1,44 @@
+/*
+Copyright 2020 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+=======================================================================
+*/
+package org.tensorflow.ndarray;
+
+/** Any data container with a given {@link Shape}. */
+public interface Shaped {
+
+ /**
+ * @return the shape of this container
+ */
+ Shape shape();
+
+ /**
+ * @return the rank of this container
+ */
+ default int rank() {
+ return shape().numDimensions();
+ }
+
+ /**
+ * Computes and returns the total size of this container, in number of values.
+ *
+ * {@code
+ * ShortNdArray matrix = NdArrays.ofShorts(shape(2, 2)); // matrix rank = 2
+ * matrix.getShort(0, 1); // succeeds, returns 0.0f
+ * matrix.getShort(0); // throws IllegalRankException
+ *
+ * ShortNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.getShort(); // succeeds, returns 0.0f
+ * }
+ *
+ * @param coordinates coordinates of the scalar to resolve
+ * @return value of that scalar
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ short getShort(long... coordinates);
+
+ /**
+ * Assigns the short value of the scalar found at the given coordinates.
+ *
+ * {@code
+ * ShortNdArray matrix = NdArrays.ofShorts(shape(2, 2)); // matrix rank = 2
+ * matrix.setShort(10.0f, 0, 1); // succeeds
+ * matrix.setShort(10.0f, 0); // throws IllegalRankException
+ *
+ * ShortNdArray scalar = matrix.get(0, 1); // scalar rank = 0
+ * scalar.setShort(10.0f); // succeeds
+ * }
+ *
+ * @param value value to assign
+ * @param coordinates coordinates of the scalar to assign
+ * @return this array
+ * @throws IndexOutOfBoundsException if some coordinates are outside the limits of their
+ * respective dimension
+ * @throws IllegalRankException if number of coordinates is not sufficient to access a scalar
+ * element
+ */
+ ShortNdArray setShort(short value, long... coordinates);
+
+ @Override
+ ShortNdArray withShape(Shape shape);
+
+ @Override
+ ShortNdArray slice(Index... coordinates);
+
+ @Override
+ ShortNdArray get(long... coordinates);
+
+ @Override
+ ShortNdArray set(NdArray
+ *
+ *
+ * It is important to note that there is no guarantee the memory managed by a {@code DataBuffer} is
+ * linear, specially when dealing with non-primitive types or large buffers.
+ *
+ * @param