Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
This commit is contained in:
207
crates/ruvector-sparse-inference/tests/backend_simd_tests.rs
Normal file
207
crates/ruvector-sparse-inference/tests/backend_simd_tests.rs
Normal file
@@ -0,0 +1,207 @@
|
||||
//! Standalone tests for SIMD backend kernels
|
||||
|
||||
use ndarray::Array2;
|
||||
use ruvector_sparse_inference::backend::{cpu::CpuBackend, get_backend, Backend};
|
||||
use ruvector_sparse_inference::config::ActivationType;
|
||||
|
||||
#[test]
|
||||
fn test_cpu_backend_dot_product() {
|
||||
let backend = CpuBackend;
|
||||
|
||||
// Test small vector
|
||||
let a = vec![1.0, 2.0, 3.0, 4.0];
|
||||
let b = vec![2.0, 3.0, 4.0, 5.0];
|
||||
let result = backend.dot_product(&a, &b);
|
||||
assert!(
|
||||
(result - 40.0).abs() < 1e-5,
|
||||
"Expected 40.0, got {}",
|
||||
result
|
||||
);
|
||||
|
||||
// Test larger vector (exercises SIMD paths)
|
||||
let a: Vec<f32> = (0..256).map(|i| i as f32).collect();
|
||||
let b: Vec<f32> = (0..256).map(|i| (i * 2) as f32).collect();
|
||||
let result = backend.dot_product(&a, &b);
|
||||
let expected: f32 = (0..256).map(|i| (i * i * 2) as f32).sum();
|
||||
assert!(
|
||||
(result - expected).abs() < 1.0,
|
||||
"Expected {}, got {}",
|
||||
expected,
|
||||
result
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cpu_backend_relu() {
|
||||
let backend = CpuBackend;
|
||||
|
||||
let mut data = vec![-2.0, -1.0, 0.0, 1.0, 2.0, 3.0, -4.0, 5.0];
|
||||
backend.activation(&mut data, ActivationType::Relu);
|
||||
assert_eq!(data, vec![0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 0.0, 5.0]);
|
||||
|
||||
// Test larger array (exercises SIMD paths)
|
||||
let mut data: Vec<f32> = (0..256).map(|i| i as f32 - 128.0).collect();
|
||||
backend.activation(&mut data, ActivationType::Relu);
|
||||
for (i, &val) in data.iter().enumerate() {
|
||||
let expected = (i as f32 - 128.0).max(0.0);
|
||||
assert!(
|
||||
(val - expected).abs() < 1e-5,
|
||||
"Index {}: expected {}, got {}",
|
||||
i,
|
||||
expected,
|
||||
val
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cpu_backend_gelu() {
|
||||
let backend = CpuBackend;
|
||||
|
||||
let mut data = vec![0.0, 1.0, -1.0, 2.0];
|
||||
backend.activation(&mut data, ActivationType::Gelu);
|
||||
|
||||
// GELU(0) ≈ 0
|
||||
assert!(
|
||||
data[0].abs() < 0.01,
|
||||
"GELU(0) should be ≈0, got {}",
|
||||
data[0]
|
||||
);
|
||||
|
||||
// GELU(1) ≈ 0.841
|
||||
assert!(
|
||||
(data[1] - 0.841).abs() < 0.01,
|
||||
"GELU(1) should be ≈0.841, got {}",
|
||||
data[1]
|
||||
);
|
||||
|
||||
// GELU(-1) ≈ -0.159 (GELU is NOT an odd function)
|
||||
assert!(
|
||||
(data[2] + 0.159).abs() < 0.1,
|
||||
"GELU(-1) should be ≈-0.159, got {}",
|
||||
data[2]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cpu_backend_silu() {
|
||||
let backend = CpuBackend;
|
||||
|
||||
let mut data = vec![0.0, 1.0, -1.0, 2.0];
|
||||
backend.activation(&mut data, ActivationType::Silu);
|
||||
|
||||
// SiLU(0) ≈ 0
|
||||
assert!(
|
||||
data[0].abs() < 0.01,
|
||||
"SiLU(0) should be ≈0, got {}",
|
||||
data[0]
|
||||
);
|
||||
|
||||
// SiLU(1) ≈ 0.731
|
||||
assert!(
|
||||
(data[1] - 0.731).abs() < 0.01,
|
||||
"SiLU(1) should be ≈0.731, got {}",
|
||||
data[1]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cpu_backend_add() {
|
||||
let backend = CpuBackend;
|
||||
|
||||
let mut a = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
|
||||
let b = vec![10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0];
|
||||
backend.add(&mut a, &b);
|
||||
assert_eq!(a, vec![11.0, 22.0, 33.0, 44.0, 55.0, 66.0, 77.0, 88.0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cpu_backend_axpy() {
|
||||
let backend = CpuBackend;
|
||||
|
||||
let mut a = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
|
||||
let b = vec![1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0];
|
||||
backend.axpy(&mut a, &b, 2.5);
|
||||
assert_eq!(a, vec![3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cpu_backend_sparse_matmul() {
|
||||
let backend = CpuBackend;
|
||||
|
||||
// Create a 4x4 matrix
|
||||
let matrix = Array2::from_shape_vec(
|
||||
(4, 4),
|
||||
vec![
|
||||
1.0, 0.0, 2.0, 0.0, 0.0, 3.0, 0.0, 4.0, 5.0, 0.0, 6.0, 0.0, 0.0, 7.0, 0.0, 8.0,
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let input = vec![1.0, 2.0, 3.0, 4.0];
|
||||
|
||||
// Only compute rows 0 and 2
|
||||
let active_rows = vec![0, 2];
|
||||
let output = backend.sparse_matmul(&matrix, &input, &active_rows);
|
||||
|
||||
// Row 0: 1*1 + 0*2 + 2*3 + 0*4 = 7
|
||||
// Row 2: 5*1 + 0*2 + 6*3 + 0*4 = 23
|
||||
assert_eq!(output.len(), 2);
|
||||
assert!((output[0] - 7.0).abs() < 1e-5);
|
||||
assert!((output[1] - 23.0).abs() < 1e-5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cpu_backend_sparse_matmul_accumulate() {
|
||||
let backend = CpuBackend;
|
||||
|
||||
let matrix = Array2::from_shape_vec(
|
||||
(4, 4),
|
||||
vec![
|
||||
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0,
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let input = vec![1.0, 2.0];
|
||||
let active_cols = vec![0, 2];
|
||||
let mut output = vec![0.0; 4];
|
||||
|
||||
backend.sparse_matmul_accumulate(&matrix, &input, &active_cols, &mut output);
|
||||
|
||||
// Column 0 * 1.0 + Column 2 * 2.0
|
||||
// [1, 5, 9, 13] * 1.0 + [3, 7, 11, 15] * 2.0
|
||||
assert!((output[0] - 7.0).abs() < 1e-5); // 1 + 6
|
||||
assert!((output[1] - 19.0).abs() < 1e-5); // 5 + 14
|
||||
assert!((output[2] - 31.0).abs() < 1e-5); // 9 + 22
|
||||
assert!((output[3] - 43.0).abs() < 1e-5); // 13 + 30
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_backend() {
|
||||
let backend = get_backend();
|
||||
println!("Using backend: {}", backend.name());
|
||||
println!("SIMD width: {}", backend.simd_width());
|
||||
|
||||
// Verify backend works
|
||||
let a = vec![1.0, 2.0, 3.0, 4.0];
|
||||
let b = vec![2.0, 3.0, 4.0, 5.0];
|
||||
let result = backend.dot_product(&a, &b);
|
||||
assert!((result - 40.0).abs() < 1e-5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_backend_simd_width() {
|
||||
let backend = CpuBackend;
|
||||
let width = backend.simd_width();
|
||||
|
||||
// Width should be 1, 4, or 8 depending on CPU features
|
||||
assert!(
|
||||
width == 1 || width == 4 || width == 8,
|
||||
"Unexpected SIMD width: {}",
|
||||
width
|
||||
);
|
||||
|
||||
println!("Backend: {}", backend.name());
|
||||
println!("SIMD width: {}", width);
|
||||
}
|
||||
Reference in New Issue
Block a user