> For the complete documentation index, see [llms.txt](https://docs.natml.ai/unity/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.natml.ai/unity/api/mlfeature/mlarrayfeature.md).

# MLArrayFeature

This is a multidimensional array feature, a.k.a a tensor. Most models which accept tensors will accept an array feature in NatML.

{% hint style="info" %}
The array data type `T` is always [`unmanaged`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/unmanaged-types).
{% endhint %}

{% hint style="success" %}
Array features are always views of a pre-allocated array or buffer. As such, creating an array feature will never allocate tensor memory.
{% endhint %}

## Creating the Feature

The array feature can be created from any numeric array or buffer representation:

### From a Managed Array

```csharp
/// <summary>
/// Create an array feature.
/// </summary>
/// <param name="data">Feature data.</param>
/// <param name="shape">Feature shape.</param>
MLArrayFeature (T[] data, int[] shape = null);
```

An array feature can be created from a managed array. In rare cases where it is useful to fully specify the feature type, there is an overload which accepts the array type:

```csharp
/// <summary>
/// Create an array feature.
/// </summary>
/// <param name="data">Feature data.</param>
/// <param name="type">Feature type.</param>
MLArrayFeature (T[] data, MLArrayType type);
```

### From a Native Array

The array feature provides variants of the managed array constructors where the `data` argument is a [`NativeArray<T>`](https://docs.unity3d.com/ScriptReference/Unity.Collections.NativeArray_1.html). This can be useful for working with certain performance-critical Unity API's like Burst:

```csharp
/// <summary>
/// Create an array feature.
/// </summary>
/// <param name="data">Feature data.</param>
/// <param name="shape">Feature shape.</param>
MLArrayFeature (NativeArray<T> data, int[] shape = null);
```

Similarly, in cases where it is necessary to explicitly specify the array feature type, there is a corresponding overload:

```csharp
/// <summary>
/// Create an array feature.
/// </summary>
/// <param name="data">Feature data.</param>
/// <param name="type">Feature type.</param>
MLArrayFeature (NativeArray<T> data, MLArrayType type);
```

### From a Native Buffer

The array feature provides variants of the managed array constructors where the `data` argument is a typed native buffer. These can be useful for making predictions on arrays from native code or external libraries like OpenCV:

```csharp
/// <summary>
/// Create an array feature.
/// </summary>
/// <param name="data">Feature data.</param>
/// <param name="shape">Feature shape.</param>
MLArrayFeature (T* data, int[] shape = null);
```

There is a corresponding constructor for specifying the feature type:

```csharp
/// <summary>
/// Create an array feature.
/// </summary>
/// <param name="data">Feature data.</param>
/// <param name="type">Feature type.</param>
MLArrayFeature (T* data, MLArrayType type);
```

{% hint style="warning" %}
The `data` buffer MUST remain valid for the lifetime of the array feature.
{% endhint %}

### From an Edge Feature

```csharp
/// <summary>
/// Create an array feature from an Edge ML feature.
/// Note that this does NOT take ownership of the edge feature.
/// As such the edge feature must be explicitly disposed by the client.
/// </summary>
/// <param name="feature">Edge ML feature. This MUST be an array feature.</param>
MLArrayFeature (MLEdgeFeature feature);
```

An array feature can be created from an `MLEdgeFeature`. This is useful for making predictions with an [`MLEdgeModel`](/unity/api/mlmodel/mledgemodel.md) .

{% hint style="warning" %}
The `feature` MUST have a numeric data type.
{% endhint %}

### From a Cloud Feature

```csharp
/// <summary>
/// Create an array feature from a cloud feature.
/// </summary>
/// <param name="feature">Cloud feature.</param>
MLArrayFeature (MLCloudFeature feature);
```

The array feature can be created from an `MLCloudFeature`. This is useful for making predictions with an [`MLCloudModel`](/unity/api/mlmodel/mlcloudmodel.md) .

{% hint style="warning" %}
The `feature` MUST have a numeric data type.
{% endhint %}

## Inspecting the Feature

The array feature provides information about its shape.

### Feature Type

```csharp
/// <summary>
/// Feature type.
/// </summary>
MLFeatureType type { get; }
```

Refer to the [Inspecting the Feature](/unity/api/mlfeature.md#inspecting-the-feature) section of the `MLFeature` class for more information.

{% hint style="info" %}
The `type` is always an [`MLArrayType`](/unity/api/mlfeaturetype/mlarraytype.md).
{% endhint %}

### Feature Shape

```csharp
/// <summary>
/// Feature shape.
/// </summary>
int[] shape { get; }
```

The feature shape is a convenience property which provides the shape from the feature `type`.

{% hint style="warning" %}
The `shape` can be `null` if the feature was created with no shape.
{% endhint %}

### Element Count

```csharp
/// <summary>
/// Feature element count.
/// </summary>
int elementCount { get; }
```

The element count is a convenience property which provides the element count from the feature `type`.

{% hint style="warning" %}
The `elementCount` will be zero when the feature does not have a `shape`.
{% endhint %}

## Accessing Feature Data

The array feature provides accessors for reading and writing feature data.

### Multi-Indexing

```csharp
/// <summary>
/// Get or set a value at a specified multi-index.
/// </summary>
/// <param name="idx">Multi-index.</param>
T this [params int[] idx] { get; set; }
```

The array feature provides support for multi-indexing. This is a common pattern for working with tensors in machine learning:

```csharp
// With an array feature
var feature = new MLArrayFeature<float>(...);
// You can index across multiple dimensions
var logit = feature[0,12,29,1];
```

{% hint style="info" %}
Multiple indexing requires the array feature to have a valid `shape`, but linear indexing (i.e. indexing with a single number) does not.
{% endhint %}

{% hint style="warning" %}
The array feature does not perform bounds checking for performance, so make sure to always index correctly.
{% endhint %}

The array feature also supports linear indexing, in which case it accesses the elements of the feature assuming a flat shape:

```csharp
// You can also index linearly, disregarding the shape
var logit = feature[392];
```

### Copying

```csharp
/// <summary>
/// Copy the array feature into another feature.
/// This copies `destination.elementCount * sizeof(U)` elements.
/// </summary>
/// <param name="destination">Feature to copy data into.</destination>
void CopyTo<U> (MLArrayFeature<U> destination) where U : unmanaged;
```

The array feature can copy it data into another array feature.

{% hint style="info" %}
This method copies `destination.elementCount * sizeof(U)` bytes into the `destination` feature.
{% endhint %}

{% hint style="warning" %}
This method does not respect any permutations that have been applied to the array feature.
{% endhint %}

{% hint style="success" %}
To copy data into a managed array, native buffer, or other destination, first create an `MLArrayFeature` to wrap the destination, then use the `CopyTo` method.
{% endhint %}

### Converting to Array

```csharp
/// <summary>
/// Convert the array feature to a flattened array.
/// </summary>
/// <returns>Result array.</returns>
 T[] ToArray ();
```

The array feature can copy its data into an array and return the array. The destination array type can also be specified:

```csharp
/// <summary>
/// Convert the array feature to a flattened array.
/// This method always returns a copy of the array feature data.
/// </summary>
/// <returns>Result array.</returns>
U[] ToArray<U> () where U : unmanaged;
```

{% hint style="warning" %}
This method does not respect any permutations that have been applied to the array feature.
{% endhint %}

### Pinning

```csharp
/// <summary>
/// Pin the array feature.
/// </summary>
ref T GetPinnableReference ();
```

The array feature supports pinning, allowing direct access to the underlying feature data while bypassing all checks. This can be used in `unsafe` context with the `fixed` statement:

```csharp
// Given an array feature
MLArrayFeature<float> feature = ...;
// Manually set the 12th element in the feature by pinning
fixed (float* featureData = feature)
    featureData[11] = 420.69;
```

{% hint style="success" %}
Pinning is mostly used for bulk read or write operations. Use multi-indexing for individual element access.
{% endhint %}

{% hint style="danger" %}
Do not use pinning unless you know exactly what you are doing. Mistakes are almost guaranteed to result in segmentation faults and hard crashes.
{% endhint %}

## Viewing Operations

The array feature supports viewing operations. Each of these operations do not allocate any memory; they simply return a shallow feature that has the proper shape.

### Permute

```csharp
/// <summary>
/// Permute the dimensions of this array feature.
/// This operation is a generalization of the transpose operation.
/// </summary>
/// <param name="dims">Permuted dimensions.</param>
/// <returns>Array feature with permuted dimensions.</returns>
MLArrayFeature<T> Permute (params int[] dims);
```

The array feature's dimensions can be permuted, allowing different dimensions to be swapped (like transposing):

```csharp
// Create an array feature with shape (3,5)
var feature = new MLArrayFeature<float>(..., new [] { 3, 5 });
Debug.Log(feature.shape);              // (3,5)
// Transpose it by permuting dimensions
var transposedFeature = feature.Permute(1, 0);
Debug.Log(transposedFeature.shape);    // (5,3)
```

### View

```csharp
/// <summary>
/// Create a view of this array feature with a different shape.
/// The element count of the new shape MUST match that of the feature.
/// </summary>
/// <param name="shape">New shape.</param>
/// <returns>Array feature with new shape.</returns>
MLArrayFeature<T> View (params int[] shape);
```

The array feature supports creating a view of the feature data with a different shape:

```csharp
// Create an array feature
var feature = new MLArrayFeature<float>(..., new [] { 5, 30 });
Debug.Log(feature.shape);          // (5,30)
// View the feature with a different shape
var viewedFeature = feature.View(5, 10, 3); 
Debug.Log(viewedFeature.shape);    // (5,10,3)
```

{% hint style="warning" %}
The element count of the view shape **must** match the element count of the feature.
{% endhint %}

## Creating an Edge Feature

```csharp
/// <summary>
/// Create an edge feature that is ready for prediction with edge models.
/// </summary>
/// <param name="type">Feature type used to create the edge feature.</param>
/// <returns>Edge feature.</returns>
MLEdgeFeature IMLEdgeFeature.Create (MLFeatureType type);
```

INCOMPLETE.

## Creating a Cloud Feature

<pre class="language-csharp"><code class="lang-csharp">/// &#x3C;summary>
/// Create a cloud feature that is ready for prediction with cloud models.
/// &#x3C;/summary>
/// &#x3C;param name="type">Feature type used to create the cloud feature.&#x3C;/param>
/// &#x3C;returns>Cloud feature.&#x3C;/returns>
<strong>MLCloudFeature IMLCloudFeature.Create (MLFeatureType type)
</strong></code></pre>

INCOMPLETE.
