#![allow(clippy::while_let_on_iterator)]
#[cfg(test)]
mod tests {
use hermes_simd_core::{
align::Unaligned,
execution::Unmasked,
ops::{Dot, Max, Min, ReductionOp, Sum},
scalar::NumericElement,
view::SimdView,
};
use hermes_simd_intrinsics::Scalar as ScalarArch;
#[test]
fn test_min_scalar_f32() {
let a: f32 = 3.0_f32;
let b: f32 = -1.0_f32;
assert_eq!(a.min_scalar(b), -1.0_f32);
assert_eq!(b.min_scalar(a), -1.0_f32);
}
#[test]
fn test_max_scalar_f32() {
let a: f32 = 3.0_f32;
let b: f32 = -1.0_f32;
assert_eq!(a.max_scalar(b), 3.0_f32);
assert_eq!(b.max_scalar(a), 3.0_f32);
}
#[test]
fn test_min_max_identity_f32() {
assert_eq!(<f32 as NumericElement>::MIN_VALUE, f32::NEG_INFINITY);
assert_eq!(<f32 as NumericElement>::MAX_VALUE, f32::INFINITY);
}
#[test]
fn test_min_max_identity_i32() {
assert_eq!(<i32 as NumericElement>::MIN_VALUE, i32::MIN);
assert_eq!(<i32 as NumericElement>::MAX_VALUE, i32::MAX);
}
#[test]
fn test_sum_identity_and_combine() {
assert_eq!(<Sum as ReductionOp<f32>>::identity_scalar(), 0.0_f32);
assert_eq!(<Sum as ReductionOp<f32>>::scalar_combine(2.0, 3.0), 5.0_f32);
}
#[test]
fn test_min_identity_and_combine() {
assert_eq!(<Min as ReductionOp<f32>>::identity_scalar(), f32::INFINITY);
assert_eq!(<Min as ReductionOp<f32>>::scalar_combine(2.0, 3.0), 2.0_f32);
assert_eq!(<Min as ReductionOp<f32>>::scalar_combine(3.0, 2.0), 2.0_f32);
}
#[test]
fn test_max_identity_and_combine() {
assert_eq!(
<Max as ReductionOp<f32>>::identity_scalar(),
f32::NEG_INFINITY
);
assert_eq!(<Max as ReductionOp<f32>>::scalar_combine(2.0, 3.0), 3.0_f32);
assert_eq!(<Max as ReductionOp<f32>>::scalar_combine(3.0, 2.0), 3.0_f32);
}
fn make_view(data: &[f32]) -> SimdView<'_, f32, ScalarArch, Unaligned, Unmasked, &[f32]> {
SimdView::new(data).expect("Unaligned always succeeds")
}
#[test]
fn test_reduce_sum() {
let data = [1.0_f32, 2.0, 3.0, 4.0, 5.0];
let view = make_view(&data);
assert_eq!(view.reduce(Sum), 15.0_f32);
}
#[test]
fn test_reduce_sum_empty() {
let data: [f32; 0] = [];
let view = make_view(&data);
assert_eq!(view.reduce(Sum), 0.0_f32);
}
#[test]
fn test_reduce_min() {
let data = [3.0_f32, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0, 6.0];
let view = make_view(&data);
assert_eq!(view.reduce(Min), 1.0_f32);
}
#[test]
fn test_reduce_max() {
let data = [3.0_f32, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0, 6.0];
let view = make_view(&data);
assert_eq!(view.reduce(Max), 9.0_f32);
}
#[test]
fn test_reduce_min_negative() {
let data = [-5.0_f32, -3.0, -10.0, -1.0];
let view = make_view(&data);
assert_eq!(view.reduce(Min), -10.0_f32);
}
#[test]
fn test_reduce_max_negative() {
let data = [-5.0_f32, -3.0, -10.0, -1.0];
let view = make_view(&data);
assert_eq!(view.reduce(Max), -1.0_f32);
}
#[test]
fn test_reduce_min_empty() {
let data: [f32; 0] = [];
let view = make_view(&data);
assert_eq!(view.reduce(Min), f32::INFINITY);
}
#[test]
fn test_reduce_max_empty() {
let data: [f32; 0] = [];
let view = make_view(&data);
assert_eq!(view.reduce(Max), f32::NEG_INFINITY);
}
#[test]
fn test_zip_reduce_dot() {
let a = [1.0_f32, 2.0, 3.0];
let b = [4.0_f32, 5.0, 6.0];
let va = make_view(&a);
let vb = make_view(&b);
let result = va.zip_reduce(&vb, Dot).unwrap();
assert!((result - 32.0_f32).abs() < 1e-5);
}
#[test]
fn test_zip_chunks_remainder() {
let a = [1.0_f32, 2.0, 3.0, 4.0, 5.0];
let b = [10.0_f32, 20.0, 30.0, 40.0, 50.0];
let va = make_view(&a);
let vb = make_view(&b);
let lane = <ScalarArch as hermes_simd_core::kernel::SimdKernel<f32>>::LANE_COUNT;
let mut zip = va.zip_chunks(&vb);
let mut chunk_count = 0;
while let Some(_) = zip.next() {
chunk_count += 1;
}
let (ra, rb) = zip.remainder();
assert_eq!(chunk_count * lane + ra.len(), a.len());
assert_eq!(chunk_count * lane + rb.len(), b.len());
}
}