tests/test_inference.cs
using System.Diagnostics;
using HumanoidMocapX.Inference;
using HumanoidMocapX;

static class InferenceTests
{
    internal static void Run()
    {
        Linear();
        ParallelLinear();
        Attention();
        Sampling();
        Allocations();
        Console.WriteLine("PASS: linear buffers, attention masks/head isolation, twenty-step sampling and allocation checks");
    }

    // Large enough for the multithreaded path; it must match the serial layer bit for bit.
    static void ParallelLinear()
    {
        const int width = 640, channels = 96, rows = 70;
        var weight = new Tensor("big.weight", Enumerable.Range(0, width * channels).Select(i => MathF.Sin(i * .37f)).ToArray(), new[] { width, channels });
        var bias = new Tensor("big.bias", Enumerable.Range(0, channels).Select(i => MathF.Cos(i * .11f)).ToArray(), new[] { channels });
        var linear = new FlowLinear(new FlowWeights(new Dictionary<string, Tensor> { [weight.Name] = weight, [bias.Name] = bias }), "big", width, channels);
        var input = Enumerable.Range(0, rows * width).Select(i => MathF.Sin(i * .013f)).ToArray();
        float[] serial = new float[rows * channels], parallel = new float[serial.Length];
        linear.Run(input, rows, serial); linear.RunParallel(input, rows, parallel);
        MotionTests.Check(serial.Select(BitConverter.SingleToInt32Bits).SequenceEqual(parallel.Select(BitConverter.SingleToInt32Bits)),
            "Parallel linear differs from the serial layer");
        using var cancelled = new CancellationTokenSource(); cancelled.Cancel();
        MotionTests.Throws<OperationCanceledException>(() => linear.RunParallel(input, rows, parallel, cancelled.Token));
    }

    static void Linear()
    {
        var weight = new Tensor("test", new[] { 1f, 0f, -1f, 2f, -1f, .5f }, new[] { 3, 2 });
        var bias = new Tensor("bias", new[] { .25f, -.5f }, new[] { 2 });
        float[] input = { 1, 2, 3, -1, 0, 2 };
        var output = new float[4];
        FlowLinear.Run(input, 2, weight, bias, output);
        float[] expected = { -1.75f, 1f, -2.75f, -1.5f };
        for (var i = 0; i < output.Length; i++) MotionTests.Near(expected[i], output[i]);
        MotionTests.Throws<ArgumentException>(() => FlowLinear.Run(input, 1, weight, bias, output));
        var square = new Tensor("identity", new[] { 1f, 0f, 0f, 1f }, new[] { 2, 2 });
        MotionTests.Throws<ArgumentException>(() => FlowLinear.Run(output, 2, square, null, output));
    }

    static void Attention()
    {
        const int frames = 71, width = 8, heads = 2;
        foreach (var joint in new[] { false, true })
        {
            var tokens = frames * (joint ? 2 : 1);
            var length = tokens * width;
            var q = Enumerable.Range(0, length).Select(i => MathF.Sin(i * .13f)).ToArray();
            var k = Enumerable.Range(0, length).Select(i => MathF.Cos(i * .07f)).ToArray();
            var v = Enumerable.Range(0, length).Select(i => i % 19 - 9f).ToArray();
            var output = new float[length];
            var attention = new FlowAttention(frames, width, heads, joint);
            var ranges = new uint[tokens * 4]; attention.CopyKeyRanges(ranges);
            for (var row = 0; row < tokens; row++)
                for (var column = 0; column < tokens; column++)
                {
                    var allowed = !joint || (row < frames && column < frames && Math.Abs(row - column) <= 60)
                        || (column >= frames && Math.Abs(row % frames - column % frames) <= 3);
                    var inRange = column >= ranges[row * 4] && column < ranges[row * 4] + ranges[row * 4 + 1]
                        || column >= ranges[row * 4 + 2] && column < ranges[row * 4 + 2] + ranges[row * 4 + 3];
                    MotionTests.Equal(allowed, inRange);
                }
            MotionTests.Throws<ArgumentException>(() => attention.CopyKeyRanges(new uint[1]));
            attention.Run(q, k, v, output);
            var expected = DenseReference(q, k, v, frames, width, heads, joint);
            for (var i = 0; i < length; i++) MotionTests.Near(expected[i], output[i], .00001);
            MotionTests.Throws<ArgumentException>(() => attention.Run(q, k, v, q));
            using var cancelled = new CancellationTokenSource(); cancelled.Cancel();
            MotionTests.Throws<OperationCanceledException>(() => attention.Run(q, k, v, output, cancelled.Token));
        }

        // A video token must never see motion values, even when all attention scores are equal.
        var zero = new float[frames * 2];
        var impulse = new float[frames * 2]; impulse[60] = 1; impulse[61] = 100;
        impulse[frames + 3] = 10; impulse[frames + 4] = 1000;
        var result = new float[frames * 2];
        new FlowAttention(frames, 1, 1, true).Run(zero, zero, impulse, result);
        MotionTests.Near(11d / 65, result[0]);
        MotionTests.Near(10d / 4, result[frames]);
    }

    static float[] DenseReference(float[] q, float[] k, float[] v, int frames, int width, int heads, bool joint)
    {
        var count = q.Length / width; var headWidth = width / heads;
        var result = new float[q.Length];
        for (var row = 0; row < count; row++)
            for (var head = 0; head < heads; head++)
            {
                var probabilities = new double[count]; double sum = 0;
                for (var col = 0; col < count; col++)
                {
                    var allowed = !joint || (row < frames && col < frames && Math.Abs(row - col) <= 60)
                        || (col >= frames && Math.Abs(row % frames - col % frames) <= 3);
                    if (!allowed) continue;
                    double score = 0;
                    for (var channel = 0; channel < headWidth; channel++)
                        score += q[row * width + head * headWidth + channel] * k[col * width + head * headWidth + channel];
                    probabilities[col] = Math.Exp(score / Math.Sqrt(headWidth)); sum += probabilities[col];
                }
                for (var channel = 0; channel < headWidth; channel++)
                {
                    double value = 0;
                    for (var col = 0; col < count; col++) value += probabilities[col] / sum * v[col * width + head * headWidth + channel];
                    result[row * width + head * headWidth + channel] = (float)value;
                }
            }
        return result;
    }

    static void Sampling()
    {
        var state = Enumerable.Repeat(-2f, FlowSampler.Channels).ToArray();
        var scratch = new float[state.Length]; int calls = 0;
        void Predict(ReadOnlySpan<float> values, float time, Span<float> output, CancellationToken token)
        {
            MotionTests.Near(calls / 20d, time);
            MotionTests.Near(-2 + 6 * time, values[0]);
            output.Fill(4); calls++;
        }
        FlowSampler.Sample(state, scratch, Predict);
        MotionTests.Equal(20, calls);
        foreach (var value in state) MotionTests.Near(4, value);
        MotionTests.Throws<ArgumentException>(() => FlowSampler.Sample(state, state, Predict));
        MotionTests.Throws<ArgumentException>(() => FlowSampler.Sample(new float[1], new float[1], Predict));
        state[0] = float.NaN;
        MotionTests.Throws<ArithmeticException>(() => FlowSampler.Sample(state, scratch, Predict));
        state[0] = 0;
        MotionTests.Throws<ArithmeticException>(() => FlowSampler.Sample(state, scratch,
            static (_, _, output, _) => output.Fill(float.PositiveInfinity)));
        using var cancelled = new CancellationTokenSource(); cancelled.Cancel();
        MotionTests.Throws<OperationCanceledException>(() => FlowSampler.Sample(state, scratch, Predict, cancelled.Token));
        MotionTests.Equal(20, calls);
    }

    static void Allocations()
    {
        var weight = new Tensor("benchmark", Enumerable.Repeat(.125f, 256 * 128).ToArray(), new[] { 256, 128 });
        var input = new float[8 * 256]; var output = new float[8 * 128];
        var attention = new FlowAttention(16, 8, 2, true);
        var qkv = new float[32 * 8]; var attended = new float[qkv.Length];
        var state = new float[FlowSampler.Channels]; var predicted = new float[state.Length];
        FlowPrediction predictor = static (_, _, result, _) => result.Fill(1);
        NeuralOps.Linear(input, 8, weight, null);
        FlowLinear.Run(input, 8, weight, null, output);
        attention.Run(qkv, qkv, qkv, attended);
        FlowSampler.Sample(state, predicted, predictor);
        var before = GC.GetAllocatedBytesForCurrentThread();
        var start = Stopwatch.GetTimestamp();
        for (var i = 0; i < 10; i++) NeuralOps.Linear(input, 8, weight, null);
        var originalTime = Stopwatch.GetElapsedTime(start);
        var originalBytes = GC.GetAllocatedBytesForCurrentThread() - before;
        before = GC.GetAllocatedBytesForCurrentThread(); start = Stopwatch.GetTimestamp();
        for (var i = 0; i < 10; i++) FlowLinear.Run(input, 8, weight, null, output);
        var bufferedTime = Stopwatch.GetElapsedTime(start);
        var bufferedBytes = GC.GetAllocatedBytesForCurrentThread() - before;
        before = GC.GetAllocatedBytesForCurrentThread();
        for (var i = 0; i < 10; i++) { attention.Run(qkv, qkv, qkv, attended); FlowSampler.Sample(state, predicted, predictor); }
        var loopBytes = GC.GetAllocatedBytesForCurrentThread() - before;
        MotionTests.Equal(0L, bufferedBytes); MotionTests.Equal(0L, loopBytes);
        Console.WriteLine($"Linear check, 10 x [8,256]→128: original {originalTime.TotalMilliseconds:F2} ms/{originalBytes} caller-thread bytes; buffered {bufferedTime.TotalMilliseconds:F2} ms/{bufferedBytes} bytes");
    }
}