Ancient

 view release on metacpan or  search on metacpan

t/7014-nvec-simd-sizes.t  view on Meta::CPAN

#!/usr/bin/env perl
use strict;
use warnings;
use Test::More;
use lib 'blib/lib', 'blib/arch';

use_ok('nvec');

# ============================================
# SIMD correctness tests across different sizes
# Tests various vector sizes to ensure correct
# handling of SIMD lanes and scalar tails
# ============================================

# SIMD lane sizes:
# - NEON: 2 doubles (128-bit)
# - SSE2: 2 doubles (128-bit)
# - AVX:  4 doubles (256-bit)
# - AVX2: 4 doubles (256-bit)

my @test_sizes = (
    1, 2, 3, 4,           # Small, around SIMD boundaries
    5, 6, 7, 8,           # One full AVX vector
    9, 15, 16, 17,        # Around 2x AVX
    31, 32, 33,           # Around 4x AVX
    63, 64, 65,           # Around 8x AVX
    100, 127, 128, 129,   # Larger
    255, 256, 257,        # Power of 2 boundaries
    1000, 1023, 1024, 1025,  # Large
);

my $tol = 1e-10;

sub is_float {
    my ($got, $expected, $name) = @_;
    if (abs($expected) < $tol) {
        ok(abs($got) < $tol, $name)
            or diag("got: $got, expected: ~0");
    } else {
        ok(abs($got - $expected) / abs($expected) < $tol, $name)
            or diag("got: $got, expected: $expected, diff: " . abs($got - $expected));
    }
}

# ============================================
# Sum correctness across sizes
# ============================================

subtest 'sum across sizes' => sub {
    for my $n (@test_sizes) {
        my $v = nvec::fill($n, 1.0);
        is($v->sum, $n, "sum of $n ones = $n");
    }
};

subtest 'sum of range' => sub {
    for my $n (1, 10, 100, 1000) {
        my $v = nvec::range(1, $n + 1);  # 1 to n
        my $expected = $n * ($n + 1) / 2;  # Gauss formula
        is_float($v->sum, $expected, "sum 1..$n = $expected");
    }
};

# ============================================
# Dot product correctness across sizes
# ============================================

subtest 'dot product across sizes' => sub {
    for my $n (@test_sizes) {
        my $a = nvec::ones($n);
        my $b = nvec::fill($n, 2.0);
        is_float($a->dot($b), 2.0 * $n, "dot: ones · 2s for n=$n");
    }
};

subtest 'dot product self' => sub {
    for my $n (1, 7, 8, 9, 31, 32, 33, 100) {
        my $v = nvec::fill($n, 3.0);
        is_float($v->dot($v), 9.0 * $n, "dot: 3s · 3s for n=$n");
    }
};

# ============================================
# Element-wise operations across sizes
# ============================================

subtest 'add across sizes' => sub {
    for my $n (@test_sizes) {
        my $a = nvec::fill($n, 1.0);
        my $b = nvec::fill($n, 2.0);
        my $c = $a->add($b);

        is($c->len, $n, "add len for n=$n");
        is($c->get(0), 3.0, "add first for n=$n");
        is($c->get($n-1), 3.0, "add last for n=$n");
        is($c->sum, 3.0 * $n, "add sum for n=$n");
    }
};

subtest 'sub across sizes' => sub {
    for my $n (@test_sizes) {
        my $a = nvec::fill($n, 5.0);
        my $b = nvec::fill($n, 2.0);
        my $c = $a->sub($b);

        is($c->get(0), 3.0, "sub first for n=$n");
        is($c->get($n-1), 3.0, "sub last for n=$n");
    }
};

subtest 'mul across sizes' => sub {
    for my $n (@test_sizes) {
        my $a = nvec::fill($n, 3.0);
        my $b = nvec::fill($n, 4.0);
        my $c = $a->mul($b);

        is($c->get(0), 12.0, "mul first for n=$n");
        is($c->get($n-1), 12.0, "mul last for n=$n");
    }



( run in 0.664 second using v1.01-cache-2.11-cpan-d7a12ab2c7f )