use hermes_simd::{
Add, BitAnd, BitOr, BitXor, Div, Mul, Scalar, SimdError, SimdView, Sub, Unaligned, Unmasked,
};
type View<'a, T> = SimdView<'a, T, Scalar, Unaligned, Unmasked, &'a [T]>;
type ViewMut<'a, T> = SimdView<'a, T, Scalar, Unaligned, Unmasked, &'a mut [T]>;
fn make_view(data: &[f32]) -> View<'_, f32> {
SimdView::new(data).expect("Scalar/Unaligned always succeeds")
}
fn make_view_mut(data: &mut [f32]) -> ViewMut<'_, f32> {
SimdView::new_mut(data).expect("Scalar/Unaligned always succeeds")
}
#[test]
fn test_transform_in_place_add() {
let a_orig = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
let b = [10.0f32, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0];
let expected: Vec<f32> = a_orig.iter().zip(b.iter()).map(|(a, b)| a + b).collect();
let mut a = a_orig;
let b_view = make_view(&b);
let mut a_view = make_view_mut(&mut a);
a_view.transform_in_place(&b_view, Add).unwrap();
assert_eq!(&a[..], expected.as_slice());
}
#[test]
fn test_transform_in_place_sub() {
let a_orig = [10.0f32, 20.0, 30.0, 40.0, 50.0, 7.0, 8.0, 9.0, 11.0];
let b = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
let expected: Vec<f32> = a_orig.iter().zip(b.iter()).map(|(a, b)| a - b).collect();
let mut a = a_orig;
let b_view = make_view(&b);
let mut a_view = make_view_mut(&mut a);
a_view.transform_in_place(&b_view, Sub).unwrap();
assert_eq!(&a[..], expected.as_slice());
}
#[test]
fn test_transform_in_place_mul() {
let a_orig = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
let b = [2.0f32, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
let expected: Vec<f32> = a_orig.iter().zip(b.iter()).map(|(a, b)| a * b).collect();
let mut a = a_orig;
let b_view = make_view(&b);
let mut a_view = make_view_mut(&mut a);
a_view.transform_in_place(&b_view, Mul).unwrap();
assert_eq!(&a[..], expected.as_slice());
}
#[test]
fn test_transform_in_place_div() {
let a_orig = [10.0f32, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0];
let b = [2.0f32, 4.0, 5.0, 8.0, 10.0, 6.0, 7.0, 8.0, 9.0];
let expected: Vec<f32> = a_orig.iter().zip(b.iter()).map(|(a, b)| a / b).collect();
let mut a = a_orig;
let b_view = make_view(&b);
let mut a_view = make_view_mut(&mut a);
a_view.transform_in_place(&b_view, Div).unwrap();
for (got, exp) in a.iter().zip(expected.iter()) {
assert!((got - exp).abs() < 1e-5, "got={got}, expected={exp}");
}
}
#[test]
fn test_add_assign_matches_transform_in_place_add() {
let a_orig = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
let b = [10.0f32; 10];
let mut a_generic = a_orig;
{
let b_view = make_view(&b);
let mut view = make_view_mut(&mut a_generic);
view.transform_in_place(&b_view, Add).unwrap();
}
let mut a_delegate = a_orig;
{
let b_view = make_view(&b);
let mut view = make_view_mut(&mut a_delegate);
view.add_assign(&b_view).unwrap();
}
assert_eq!(a_generic, a_delegate);
}
#[test]
fn test_mul_assign_matches_transform_in_place_mul() {
let a_orig = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0];
let b = [3.0f32; 10];
let mut a_generic = a_orig;
{
let b_view = make_view(&b);
let mut view = make_view_mut(&mut a_generic);
view.transform_in_place(&b_view, Mul).unwrap();
}
let mut a_delegate = a_orig;
{
let b_view = make_view(&b);
let mut view = make_view_mut(&mut a_delegate);
view.mul_assign(&b_view).unwrap();
}
assert_eq!(a_generic, a_delegate);
}
#[test]
fn test_zip_into_add() {
let a = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
let b = [10.0f32, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0];
let expected: Vec<f32> = a.iter().zip(b.iter()).map(|(a, b)| a + b).collect();
let mut out = vec![0.0f32; 9];
let a_view = make_view(&a);
let b_view = make_view(&b);
a_view.zip_into(&b_view, &mut out, Add).unwrap();
assert_eq!(out, expected);
}
#[test]
fn test_zip_into_sub() {
let a = [10.0f32, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0];
let b = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
let expected: Vec<f32> = a.iter().zip(b.iter()).map(|(a, b)| a - b).collect();
let mut out = vec![0.0f32; 9];
let a_view = make_view(&a);
let b_view = make_view(&b);
a_view.zip_into(&b_view, &mut out, Sub).unwrap();
assert_eq!(out, expected);
}
#[test]
fn test_zip_into_mul_matches_elementwise_mul() {
let a = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0];
let b = [2.0f32; 11];
let mut out_generic = vec![0.0f32; 11];
let mut out_delegate = vec![0.0f32; 11];
{
let a_view = make_view(&a);
let b_view = make_view(&b);
a_view.zip_into(&b_view, &mut out_generic, Mul).unwrap();
}
{
let a_view = make_view(&a);
let b_view = make_view(&b);
a_view.elementwise_mul(&b_view, &mut out_delegate).unwrap();
}
assert_eq!(out_generic, out_delegate);
}
#[test]
fn test_zip_into_div() {
let a = [10.0f32, 20.0, 30.0, 40.0];
let b = [2.0f32, 4.0, 5.0, 8.0];
let expected: Vec<f32> = a.iter().zip(b.iter()).map(|(a, b)| a / b).collect();
let mut out = vec![0.0f32; 4];
let a_view = make_view(&a);
let b_view = make_view(&b);
a_view.zip_into(&b_view, &mut out, Div).unwrap();
for (got, exp) in out.iter().zip(expected.iter()) {
assert!((got - exp).abs() < 1e-5, "got={got}, expected={exp}");
}
}
#[test]
fn test_transform_in_place_length_mismatch() {
let a = [1.0f32; 4];
let b = [1.0f32; 5];
let mut a = a;
let b_view = make_view(&b);
let mut a_view = make_view_mut(&mut a);
let err = a_view.transform_in_place(&b_view, Add);
assert_eq!(err, Err(SimdError::LengthMismatch));
}
#[test]
fn test_zip_into_length_mismatch() {
let a = [1.0f32; 4];
let b = [1.0f32; 5];
let mut out = vec![0.0f32; 4];
let a_view = make_view(&a);
let b_view = make_view(&b);
let err = a_view.zip_into(&b_view, &mut out, Add);
assert_eq!(err, Err(SimdError::LengthMismatch));
}
#[test]
fn test_zip_into_output_too_short() {
let a = [1.0f32; 8];
let b = [1.0f32; 8];
let mut out = vec![0.0f32; 4]; let a_view = make_view(&a);
let b_view = make_view(&b);
let err = a_view.zip_into(&b_view, &mut out, Add);
assert_eq!(err, Err(SimdError::InsufficientOutputLength));
}
#[test]
fn test_strategy_zst_sizes() {
use core::mem::size_of;
assert_eq!(size_of::<Add>(), 0);
assert_eq!(size_of::<Sub>(), 0);
assert_eq!(size_of::<Mul>(), 0);
assert_eq!(size_of::<Div>(), 0);
assert_eq!(size_of::<BitAnd>(), 0);
assert_eq!(size_of::<BitOr>(), 0);
assert_eq!(size_of::<BitXor>(), 0);
}
#[test]
fn test_transform_in_place_odd_length() {
let a_orig = [1.0f32, 2.0, 3.0, 4.0, 5.0];
let b = [10.0f32, 20.0, 30.0, 40.0, 50.0];
let expected: Vec<f32> = a_orig.iter().zip(b.iter()).map(|(x, y)| x + y).collect();
let mut a = a_orig;
let b_view = make_view(&b);
let mut a_view = make_view_mut(&mut a);
a_view.transform_in_place(&b_view, Add).unwrap();
assert_eq!(&a[..], expected.as_slice());
}
#[test]
fn test_zip_into_odd_length() {
let a = [1.0f32, 2.0, 3.0, 4.0, 5.0];
let b = [1.0f32, 2.0, 3.0, 4.0, 5.0];
let expected: Vec<f32> = a.iter().zip(b.iter()).map(|(x, y)| x * y).collect();
let mut out = vec![0.0f32; 5];
let a_view = make_view(&a);
let b_view = make_view(&b);
a_view.zip_into(&b_view, &mut out, Mul).unwrap();
assert_eq!(out, expected);
}