Editor/MotionBricks/Tensor.cs

A simple dense float tensor type used in the Editor tools. It stores a name, a flat float[] buffer and an int[] shape in GGML order, validates the element count on construction, and exposes Cols, Rows and a Row(index) span accessor.

Native Interop
#nullable enable annotations

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Numerics;
using System.Runtime.InteropServices;

namespace HumanoidMocap.EditorTools.MotionBricks;

/// <summary>
/// A dense F32 tensor. <see cref="Shape"/> uses GGML order (fastest dimension first), so a
/// PyTorch <c>Linear(in, out)</c> weight has shape <c>[in, out]</c> and is stored row-major
/// as <c>out</c> rows of <c>in</c> values.
/// </summary>
public sealed class Tensor
{
    public string Name { get; }
    public float[] Data { get; }
    public int[] Shape { get; }

    public Tensor( string name, float[] data, int[] shape )
    {
        Name = name;
        Data = data;
        Shape = shape;
        var count = shape.Aggregate( 1L, ( a, b ) => a * b );
        if ( count != data.Length )
            throw new InvalidDataException( $"Tensor '{name}' holds {data.Length} values but its shape needs {count}." );
    }

    /// <summary>Length of one row (GGML ne0).</summary>
    public int Cols => Shape[0];

    /// <summary>Number of rows (product of the remaining dimensions).</summary>
    public int Rows => Data.Length / Shape[0];

    public ReadOnlySpan<float> Row( int index ) => Data.AsSpan( index * Cols, Cols );
}