> For the complete documentation index, see [llms.txt](https://deeplearning4j.konduit.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://deeplearning4j.konduit.ai/en-1.0.0-rewrite/core-concepts/tensors-and-ndarrays.md).

# Tensors and NDArrays

### 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:**

| Preferred Name | Bits | Notes                                          |
| -------------- | ---- | ---------------------------------------------- |
| `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:**

| Preferred Name | Bits |
| -------------- | ---- |
| `INT64`        | 64   |
| `INT32`        | 32   |
| `INT16`        | 16   |
| `INT8`         | 8    |

**Unsigned integer:**

| Preferred Name | Bits |
| -------------- | ---- |
| `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:

| Old name | Preferred name |
| -------- | -------------- |
| `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`:

```java
// OLD (beta4) — does not compile in M2.1
DataBuffer.Type.DOUBLE

// NEW (M2.1)
DataType.DOUBLE
```

#### Default DataType and Global Configuration

The default type for new arrays is `FLOAT`. You can change this globally at application startup:

```java
import org.nd4j.linalg.api.buffer.DataType;
import org.nd4j.linalg.factory.Nd4j;

// Set both the default floating-point and integer types
Nd4j.setDefaultDataTypes(DataType.FLOAT, DataType.INT32);
```

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

```java
import org.nd4j.linalg.factory.Nd4j;
import org.nd4j.linalg.api.buffer.DataType;
import org.nd4j.linalg.api.ndarray.INDArray;

INDArray zeros = Nd4j.zeros(DataType.FLOAT, 3, 5);   // 3x5, all zeros
INDArray ones  = Nd4j.ones(DataType.FLOAT, 2, 4);    // 2x4, all ones
```

#### Scalar-Filled Arrays

Use `zeros` combined with an in-place add to fill with any constant:

```java
INDArray tens = Nd4j.zeros(3, 5).addi(10);   // 3x5, all values 10
```

#### From Java Arrays

```java
// 2D from a Java 2D array — shape is inferred automatically
INDArray fromArr = Nd4j.createFromArray(new float[][]{{1, 2, 3}, {4, 5, 6}});

// 1D row vector from a flat Java array
INDArray rowVec = Nd4j.create(new float[]{1, 2, 3});

// Column vector: pass shape explicitly
INDArray colVec = Nd4j.create(new float[]{1, 2, 3}, new int[]{3, 1});
```

#### Random Arrays

```java
// Uniform random values in [0, 1)
INDArray uniformRand = Nd4j.rand(DataType.FLOAT, 3, 4);

// Standard normal distribution N(0, 1)
INDArray gaussianRand = Nd4j.randn(DataType.FLOAT, 3, 4);
```

#### Linspace

```java
// 100 evenly-spaced points from 0 to 10 (inclusive)
INDArray lin = Nd4j.linspace(DataType.FLOAT, 0, 10, 100);
```

#### Identity Matrix

```java
// 5x5 identity matrix (ones on diagonal, zeros elsewhere)
INDArray eye = Nd4j.eye(5);
```

#### Stacking and Concatenation

```java
// Horizontal stack — arrays must have the same number of rows
INDArray hstacked = Nd4j.hstack(arr1, arr2);

// Vertical stack — arrays must have the same number of columns
INDArray vstacked = Nd4j.vstack(arr1, arr2);

// Concatenate along any dimension
INDArray concatenated = Nd4j.concat(0, arr1, arr2);   // along rows
INDArray sideBy = Nd4j.concat(1, arr1, arr2);          // along columns
```

### Shape Introspection

Once you have an array, these methods tell you its structure:

```java
long[] shape    = arr.shape();        // e.g., [3, 4, 5]
int    rank     = arr.rank();          // 3
long   length   = arr.length();        // 60

// 2D-specific convenience methods
long   rows     = arr.rows();          // 3
long   cols     = arr.columns();       // 4

// Size of a specific dimension
long   dimSize  = arr.size(2);         // 5

// Type checks
boolean isMatrix = arr.isMatrix();     // true if rank == 2
boolean isVector = arr.isVector();     // true if rank == 1, or if one dim is 1
boolean isScalar = arr.isScalar();     // true if rank == 0 or length == 1
```

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:

```java
INDArray matrix = Nd4j.createFromArray(new float[][]{{1,2,3},{4,5,6},{7,8,9}});

INDArray row = matrix.getRow(0);  // view of first row: [1, 2, 3]
row.addi(10);                     // modify in-place

// row is now [11, 12, 13]
// matrix row 0 is ALSO [11, 12, 13] — same underlying memory!
System.out.println(matrix.getRow(0));  // prints [11.0000, 12.0000, 13.0000]
```

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()`:

```java
INDArray rowCopy = matrix.getRow(1).dup();  // independent copy of row 1
rowCopy.addi(100);                          // modifies only rowCopy

// matrix is unchanged
System.out.println(matrix.getRow(1));  // still [4.0000, 5.0000, 6.0000]
```

#### 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 `i` suffix (e.g., `add`, `mul`, `sub`) are **out-of-place**: they allocate a new array and leave the original unchanged.

```java
INDArray x = Nd4j.create(new float[]{1, 2, 3});
INDArray y = Nd4j.create(new float[]{4, 5, 6});

// Out-of-place: x is NOT modified
INDArray z = x.add(y);
// z is [5, 7, 9]
// x is still [1, 2, 3]

// In-place: x IS modified
INDArray w = x.addi(y);
// w is [5, 7, 9]
// x is ALSO [5, 7, 9]
// w == x (literally the same Java object returned)
```

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:

```java
INDArray mat = Nd4j.rand(DataType.FLOAT, 3, 4);
INDArray t   = mat.transpose();   // view — same data, different shape/strides

// t.shape() is [4, 3]
// Modifying t via in-place operations modifies mat
```

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_VALUE` elements. 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

```java
// Get a single value as a double (works regardless of array's DataType)
double val = arr.getDouble(row, col);

// Get as float
float f = arr.getFloat(row, col);

// Set a single value
arr.putScalar(new int[]{row, col}, 3.14);

// For higher-rank arrays, provide all indices
arr.putScalar(new int[]{batch, channel, height, width}, 0.5);
```

#### Rows and Columns

```java
// Get a row as a view (modifying it modifies arr)
INDArray row = arr.getRow(i);

// Replace a row with another array
arr.putRow(i, someRowVector);

// Get and replace columns similarly
INDArray col = arr.getColumn(j);
arr.putColumn(j, someColumnVector);
```

#### Sub-Arrays with NDArrayIndex

`NDArrayIndex` gives you flexible sub-array access:

```java
import org.nd4j.linalg.indexing.NDArrayIndex;

// Rows 0..2 (exclusive of 3), all columns
INDArray sub = arr.get(NDArrayIndex.interval(0, 3), NDArrayIndex.all());

// Single row at index 2, columns 1..3 (exclusive of 4)
INDArray specific = arr.get(NDArrayIndex.point(2), NDArrayIndex.interval(1, 4));

// Last element along a dimension
INDArray last = arr.get(NDArrayIndex.point(arr.rows() - 1), NDArrayIndex.all());
```

`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

```java
INDArray sum     = a.add(b);   // element-wise addition, new array
INDArray diff    = a.sub(b);   // element-wise subtraction
INDArray product = a.mul(b);   // element-wise multiplication
INDArray quot    = a.div(b);   // element-wise division
```

#### Matrix Multiplication

```java
// a is [m x k], b is [k x n], result is [m x n]
INDArray result = a.mmul(b);
```

#### Reductions

```java
// Total sum as a scalar Java number
double total = arr.sumNumber().doubleValue();

// Sum along dimension 0 (collapse rows, result has shape [1, cols])
INDArray colSums = arr.sum(0);

// Mean along dimension 1 (collapse columns, result has shape [rows, 1])
INDArray rowMeans = arr.mean(1);

// Max and min
INDArray colMaxes = arr.max(0);
double   globalMax = arr.maxNumber().doubleValue();
```

#### Shape Transformations

```java
// Transpose (view — see Views section above)
INDArray transposed = arr.transpose();

// Reshape — total elements must be the same
// For a [3, 4] array (12 elements):
INDArray reshaped = arr.reshape(2, 6);    // [2, 6] — same 12 elements
INDArray flat     = arr.reshape(1, 12);   // flatten to [1, 12]

// Flatten to 1D
INDArray flat1d = arr.reshape(arr.length());
```

#### Scalar Operations

```java
// Add a scalar to every element
INDArray plusOne = arr.add(1.0);

// Multiply every element by a scalar
INDArray doubled = arr.mul(2.0);

// In-place scalar operations
arr.addi(1.0);
arr.muli(2.0);
```

***

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.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://deeplearning4j.konduit.ai/en-1.0.0-rewrite/core-concepts/tensors-and-ndarrays.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
