Tensors and NDArrays
INDArray fundamentals — shape, rank, stride, DataType, creating arrays, views vs copies, and off-heap memory in ND4J
What is an INDArray?
INDArray is the fundamental data structure in ND4J. It represents an N-dimensional array — a tensor — that can hold numerical data in any number of dimensions. Every operation in ND4J, and by extension all of DL4J, produces and consumes INDArray instances.
The Java interface is org.nd4j.linalg.api.ndarray.INDArray. You never instantiate this directly; instead you use the static factory methods on org.nd4j.linalg.factory.Nd4j.
Key Properties
Every INDArray has four defining properties:
Rank — the number of dimensions. A scalar has rank 0, a vector rank 1, a matrix rank 2, and so on. There is no hard upper limit on rank.
Shape — a long[] giving the size of each dimension. A 3x4x5 array has shape [3, 4, 5]. The shape determines what indices are valid when you access elements.
Length — the total number of elements, which is the product of the shape dimensions. A 3x4x5 array has length 60.
Stride — a long[] giving the separation in the underlying flat buffer between consecutive elements along each dimension. Stride is what makes views (slices, transposes, sub-arrays) possible without copying data. For a C-order (row-major) 3x4 matrix the strides are [4, 1] — moving one row costs 4 positions in the buffer, moving one column costs 1.
Indexing Convention
ND4J uses zero-based indexing throughout. For a 2D array (matrix):
Dimension 0 is the row dimension
Dimension 1 is the column dimension
This generalises for higher ranks: dimension 0 is the outermost (slowest-varying) dimension in C order.
DataType
Every INDArray has a numeric type, represented by the org.nd4j.linalg.api.buffer.DataType enum. Choosing the right type matters for precision, memory use, and hardware compatibility.
Available Types in M2.1
Floating point:
DOUBLE
64
Double-precision float
FLOAT
32
Single-precision float (default)
FLOAT16
16
Half-precision float
BFLOAT16
16
Brain float, wider exponent range than FLOAT16
Signed integer:
INT64
64
INT32
32
INT16
16
INT8
8
Unsigned integer:
UINT64
64
UINT32
32
UINT16
16
UINT8
8
Other: BOOL, UTF8
Deprecated Aliases
The following names still compile but you should prefer the names above in new code:
HALF
FLOAT16
LONG
INT64
INT
INT32
SHORT
INT16
BYTE
INT8
UBYTE
UINT8
FLOAT16 and HALF are the same enum constant — FLOAT16 is a static alias for HALF. The same relationship holds for the integer pairs (INT32/INT, INT64/LONG, etc.). Both names are interchangeable at the JVM level, but the preferred names make code easier to read.
Migration Note from beta4
If you are migrating from an earlier beta release, note that DataBuffer.Type.DOUBLE and DataBuffer.Type.FLOAT no longer exist. Replace all uses of DataBuffer.Type with DataType:
Default DataType and Global Configuration
The default type for new arrays is FLOAT. You can change this globally at application startup:
Calling this once before any array creation ensures consistent types throughout your application.
Creating NDArrays
All array creation goes through static methods on Nd4j. The most commonly used ones are shown below.
Zeros and Ones
Scalar-Filled Arrays
Use zeros combined with an in-place add to fill with any constant:
From Java Arrays
Random Arrays
Linspace
Identity Matrix
Stacking and Concatenation
Shape Introspection
Once you have an array, these methods tell you its structure:
Note that rows() and columns() are only meaningful for 2D arrays. For higher-rank tensors, use shape() and size(dimension).
Views vs. Copies
Understanding the difference between a view and a copy is one of the most important concepts in ND4J. Getting it wrong leads to bugs that are hard to track down.
Views Share Underlying Memory
Many operations return a view — a new INDArray object that refers to the same backing memory buffer as the original. Modifying the view modifies the original:
Operations that commonly return views: getRow, getColumn, reshape, transpose, get with NDArrayIndex, sub-array slicing.
Copies with dup()
If you need an independent copy, call .dup():
In-Place vs. Out-of-Place Operations
ND4J follows a naming convention for element-wise operations:
Methods ending in
i(e.g.,addi,muli,subi) are in-place: they modify the array they are called on and return the same object.Methods without the
isuffix (e.g.,add,mul,sub) are out-of-place: they allocate a new array and leave the original unchanged.
The in-place variants avoid allocating a new array, which matters when performance is critical. However, be careful when calling in-place operations on views — you will modify the original array's data.
Transpose is a View
transpose() returns a view with modified strides, not a copy:
If you need an independent transposed copy: mat.transpose().dup().
Memory Layout
Off-Heap Storage
NDArrays in ND4J are stored in off-heap memory — outside the JVM's garbage-collected heap. This is managed via JavaCPP and direct native memory. The benefits are significant:
BLAS interoperability: Native linear algebra libraries (OpenBLAS, cuBLAS) can operate directly on the data without copying.
No 2^31 element limit: Java arrays are limited to
Integer.MAX_VALUEelements. Off-heap buffers have no such restriction.No GC pressure: Large arrays do not contribute to GC pauses because they are not on the JVM heap. However, you must be aware of memory lifecycle — see the Memory and Workspaces page for details on workspace-based memory management.
C Order and F Order
ND4J supports two memory layouts for 2D and higher-rank arrays:
C order (row-major): Elements within a row are contiguous in memory. This is the default. Consistent with NumPy's default and with C arrays.
F order (column-major): Elements within a column are contiguous in memory. This is Fortran order, used internally by some BLAS routines.
Most operations work correctly regardless of order. You can check the order with arr.ordering() which returns 'c' or 'f'. If you need a specific order, use arr.dup('c') or arr.dup('f').
For most users, the default C order is the right choice.
Getting and Setting Values
Individual Elements
Rows and Columns
Sub-Arrays with NDArrayIndex
NDArrayIndex gives you flexible sub-array access:
NDArrayIndex.interval and NDArrayIndex.point return views by default. Use .dup() if you need a copy.
Basic Operations Preview
The full operations reference is covered in the Operations page. Here is a quick overview of the most common patterns.
Element-Wise Arithmetic
Matrix Multiplication
Reductions
Shape Transformations
Scalar Operations
For memory management and workspace configuration, see the Memory and Workspaces page. For the full catalog of mathematical operations including transforms, linear algebra, and reductions, see the Operations page.
Last updated
Was this helpful?