use core::mem::MaybeUninit;
use strided_basic::{
axpby_accum, embed_diagonal_into_uninit, embed_diagonal_view_into_uninit,
triangular_mask_into_uninit, triangular_mask_view_into_uninit,
};
use strided_view::StridedView;
fn at(src: &StridedView<'_, i32>, coord: &[usize]) -> i32 {
let offset: isize = coord
.iter()
.zip(src.strides())
.fold(src.offset(), |acc, (&c, &s)| acc + c as isize * s);
src.data()[offset as usize]
}
fn initialized<T: Copy>(out: &[MaybeUninit<T>]) -> Vec<T> {
out.iter().map(|x| unsafe { x.assume_init() }).collect()
}
#[test]
fn axpby_values_and_error_preserve_destination() {
for n in [0, 1, 3, 8, 32769, 65537] {
let x: Vec<f64> = (0..n).map(|i| i as f64 - 7.0).collect();
let mut y = vec![3.0; n];
axpby_accum(&mut y, &x, 2.0, -3.0).unwrap();
assert_eq!(y, x.iter().map(|x| 2.0 * x - 9.0).collect::<Vec<_>>());
}
let mut y = [7.0];
assert!(axpby_accum(&mut y, &[], 1.0, 1.0).is_err());
assert_eq!(y, [7.0]);
axpby_accum(&mut y, &[f64::NAN], 0.0, 1.0).unwrap();
assert!(y[0].is_nan());
let mut y = [f64::NAN];
axpby_accum(&mut y, &[1.0], 1.0, 0.0).unwrap();
assert!(y[0].is_nan());
use num_complex::Complex64;
let x = [Complex64::new(2.0, 3.0)];
let mut y = [Complex64::new(4.0, -1.0)];
let alpha = Complex64::new(0.0, 1.0);
let beta = Complex64::new(-1.0, 0.0);
let expected = alpha * x[0] + beta * y[0];
axpby_accum(&mut y, &x, alpha, beta).unwrap();
assert_eq!(y[0], expected);
}
#[test]
fn triangular_matches_elementwise_reference() {
for shape in [
vec![0, 3],
vec![3, 0, 2],
vec![3, 5],
vec![5, 3, 2],
vec![129, 257, 2],
] {
let n = shape.iter().product();
let input: Vec<i32> = (0..n as i32).map(|x| x + 1).collect();
for k in [i64::MIN, -4, -1, 0, 1, 4, i64::MAX] {
for upper in [false, true] {
let mut output = vec![MaybeUninit::uninit(); n];
triangular_mask_into_uninit(&mut output, &input, &shape, k, upper, -99).unwrap();
let expected: Vec<_> = input
.iter()
.enumerate()
.map(|(flat, &v)| {
let row = (flat % shape[0]) as i128;
let col = ((flat / shape[0]) % shape[1]) as i128;
let keep = if upper {
row <= col - k as i128
} else {
row >= col - k as i128
};
if keep {
v
} else {
-99
}
})
.collect();
assert_eq!(initialized(&output), expected, "{shape:?} {k} {upper}");
}
}
}
}
#[test]
fn embedding_all_axes_and_ranks() {
for shape in [
vec![0],
vec![1],
vec![3],
vec![2, 3],
vec![2, 3, 4],
vec![3, 1, 2, 2],
vec![37, 43],
] {
let n: usize = shape.iter().product();
let input: Vec<i64> = (0..n as i64).map(|x| x + 1).collect();
for a in 0..shape.len() {
for b in 0..=shape.len() {
let mut out_shape = shape.clone();
out_shape.insert(b, shape[a]);
let mut output = vec![MaybeUninit::uninit(); n * shape[a]];
embed_diagonal_into_uninit(&mut output, &input, &shape, a, b, 0).unwrap();
let mut expected = vec![0; output.len()];
for (i, &value) in input.iter().enumerate() {
let mut rem = i;
let mut coords = Vec::new();
for &dim in &shape {
coords.push(rem % dim);
rem /= dim;
}
let d = coords[a];
coords.insert(b, d);
let mut stride = 1;
let mut offset = 0;
for (&coord, &dim) in coords.iter().zip(&out_shape) {
offset += coord * stride;
stride *= dim;
}
expected[offset] = value;
}
assert_eq!(initialized(&output), expected, "{shape:?} {a} {b}");
}
}
}
}
#[test]
fn invalid_shapes_do_not_write() {
let mut output = [MaybeUninit::new(71_i32); 4];
assert!(triangular_mask_into_uninit(&mut output, &[1; 4], &[4], 0, true, 0).is_err());
assert!(triangular_mask_into_uninit(&mut output, &[1; 4], &[2, 3], 0, true, 0).is_err());
assert!(
triangular_mask_into_uninit(&mut output, &[1; 4], &[usize::MAX, 2], 0, true, 0).is_err()
);
assert!(embed_diagonal_into_uninit(&mut output, &[1, 2], &[2], 1, 1, 0).is_err());
assert!(embed_diagonal_into_uninit(&mut output, &[1, 2], &[2], 0, 2, 0).is_err());
assert!(embed_diagonal_into_uninit(&mut output, &[1, 2], &[3], 0, 1, 0).is_err());
assert_eq!(initialized(&output), [71; 4]);
}
#[cfg(feature = "parallel")]
#[test]
fn bounded_and_sequential_policy_inside_pool() {
use std::num::NonZeroUsize;
use strided_basic::{with_execution_policy, ExecutionPolicy};
let pool = rayon::ThreadPoolBuilder::new()
.num_threads(4)
.build()
.unwrap();
pool.install(|| {
for policy in [
ExecutionPolicy::Sequential,
ExecutionPolicy::Rayon {
max_threads: NonZeroUsize::new(2).unwrap(),
},
] {
with_execution_policy(policy, || {
triangular_matches_elementwise_reference();
embedding_all_axes_and_ranks();
axpby_values_and_error_preserve_destination();
});
}
});
}
#[test]
fn triangular_mask_reads_transposed_source_without_staging() {
let base: Vec<i32> = (0..12).collect();
let src = StridedView::new(&base, &[4, 3], &[3, 1], 0).unwrap();
let mut out = vec![MaybeUninit::uninit(); 12];
triangular_mask_view_into_uninit(&mut out, &src, 0, false, -1).unwrap();
let got = initialized(&out);
let want: Vec<i32> = (0..12)
.map(|flat| {
let (row, col) = (flat % 4, flat / 4);
if row >= col {
at(&src, &[row, col])
} else {
-1
}
})
.collect();
assert_eq!(got, want);
}
#[test]
fn triangular_mask_reads_reversed_offset_source() {
let base: Vec<i32> = (0..12).collect();
let src = StridedView::new(&base, &[4, 3], &[-3, 1], 9).unwrap();
let mut out = vec![MaybeUninit::uninit(); 12];
triangular_mask_view_into_uninit(&mut out, &src, 1, true, -1).unwrap();
let got = initialized(&out);
let want: Vec<i32> = (0..12)
.map(|flat| {
let (row, col) = (flat % 4, flat / 4);
if row + 1 <= col {
at(&src, &[row, col])
} else {
-1
}
})
.collect();
assert_eq!(got, want);
assert_eq!(base, (0..12).collect::<Vec<_>>());
}
#[test]
fn triangular_mask_reads_permuted_batch_strides() {
let base: Vec<i32> = (0..12).collect();
let src = StridedView::new(&base, &[3, 2, 2], &[1, 3, 6], 0).unwrap();
let mut out = vec![MaybeUninit::uninit(); 12];
triangular_mask_view_into_uninit(&mut out, &src, 0, false, -1).unwrap();
let got = initialized(&out);
let want: Vec<i32> = (0..12)
.map(|flat| {
let (row, rest) = (flat % 3, flat / 3);
let (col, batch) = (rest % 2, rest / 2);
let coord = [row, col, batch];
if row >= col {
at(&src, &coord)
} else {
-1
}
})
.collect();
assert_eq!(got, want);
}
#[test]
fn embed_diagonal_reads_strided_source() {
let base = [10, 1, 11, 2, 12, 3];
let src = StridedView::new(&base, &[3], &[2], 1).unwrap();
let mut out = vec![MaybeUninit::uninit(); 9];
embed_diagonal_view_into_uninit(&mut out, &src, 0, 1, -1).unwrap();
assert_eq!(initialized(&out), vec![1, -1, -1, -1, 2, -1, -1, -1, 3]);
assert_eq!(base, [10, 1, 11, 2, 12, 3]);
}
#[test]
fn view_variants_agree_with_dense_variants() {
let base: Vec<i32> = (0..24).collect();
let strides = [1, 4, 12];
let src = StridedView::new(&base, &[4, 3, 2], &strides, 0).unwrap();
let mut dense = vec![MaybeUninit::uninit(); 24];
let mut via_view = vec![MaybeUninit::uninit(); 24];
triangular_mask_into_uninit(&mut dense, &base, &[4, 3, 2], -1, false, 0).unwrap();
triangular_mask_view_into_uninit(&mut via_view, &src, -1, false, 0).unwrap();
assert_eq!(initialized(&dense), initialized(&via_view));
let mut dense = vec![MaybeUninit::uninit(); 72];
let mut via_view = vec![MaybeUninit::uninit(); 72];
embed_diagonal_into_uninit(&mut dense, &base, &[4, 3, 2], 1, 0, 0).unwrap();
embed_diagonal_view_into_uninit(&mut via_view, &src, 1, 0, 0).unwrap();
assert_eq!(initialized(&dense), initialized(&via_view));
}