use core::mem::MaybeUninit;
use super::{DynamicSlicePlan, DynamicUpdateSlicePlan, RawStridedMut, RawStridedRef};
use crate::threading::run_serial_and_parallel;
#[test]
fn dynamic_slice_rank_one_contiguous_parallel_matches_serial() {
let operand: Vec<f64> = (0..100_003).map(|v| v as f64 * 0.25).collect();
for (len, start) in [(40_001usize, 7i64), (65_539, 99_999), (0, 5), (1, 3)] {
let plan =
DynamicSlicePlan::compile(&[100_003], &[1], &[1], &[1], &[len], &[1], &[len]).unwrap();
assert!(plan.uses_rank_one_contiguous_path());
let clamped = (start as usize).min(100_003 - len);
let expected = operand[clamped..clamped + len].to_vec();
let starts = [start];
let source = RawStridedRef::new(&operand, &[100_003], &[1], 0).unwrap();
let start_ref = RawStridedRef::new(&starts, &[1], &[1], 0).unwrap();
let dest_dims = [len];
let (serial, parallel) = run_serial_and_parallel(|| {
let mut out = vec![-1.0f64; len];
let mut dest = RawStridedMut::new(&mut out, &dest_dims, &[1], 0).unwrap();
plan.execute(&mut dest, &source, &start_ref).unwrap();
let mut storage = vec![MaybeUninit::<f64>::uninit(); len];
let mut dest = RawStridedMut::new(&mut storage, &dest_dims, &[1], 0).unwrap();
plan.execute_uninit(&mut dest, &source, &start_ref).unwrap();
let uninit: Vec<f64> = storage.iter().map(|v| unsafe { v.assume_init() }).collect();
(out, uninit)
});
assert_eq!(serial.0, expected, "len {len}");
assert_eq!(parallel.0, expected, "len {len}");
assert_eq!(serial.1, expected, "len {len}");
assert_eq!(parallel.1, expected, "len {len}");
}
}
#[test]
fn dynamic_update_slice_parallel_matches_serial() {
let n = 90_001usize;
let operand: Vec<i64> = (0..n as i64).collect();
let update: Vec<i64> = (0..40_001).map(|v| -v - 1).collect();
let plan = DynamicUpdateSlicePlan::compile(&[n], &[1], &[1], &[1], &[40_001], &[1], &[n], &[1])
.unwrap();
assert!(plan.uses_rank_one_contiguous_path());
let starts = [12_345i64];
let full = [n];
let source = RawStridedRef::new(&operand, &full, &[1], 0).unwrap();
let update_ref = RawStridedRef::new(&update, &[40_001], &[1], 0).unwrap();
let start_ref = RawStridedRef::new(&starts, &[1], &[1], 0).unwrap();
let mut expected = operand.clone();
expected[12_345..12_345 + 40_001].copy_from_slice(&update);
let (serial, parallel) = run_serial_and_parallel(|| {
let mut out = vec![0i64; n];
let mut dest = RawStridedMut::new(&mut out, &full, &[1], 0).unwrap();
plan.execute(&mut dest, &source, &update_ref, &start_ref)
.unwrap();
out
});
assert_eq!(serial, expected);
assert_eq!(parallel, expected);
let dims = [301usize, 211];
let op_strides = [-1isize, 301];
let op_offset = 300isize;
let operand: Vec<i64> = (0..(301 * 211) as i64).collect();
let update: Vec<i64> = (0..(101 * 51) as i64).map(|v| -v - 1).collect();
let plan = DynamicUpdateSlicePlan::compile(
&dims,
&op_strides,
&[2],
&[1],
&[101, 51],
&[1, 101],
&dims,
&[1, 301],
)
.unwrap();
let starts = [17i64, 190];
let source = RawStridedRef::new(&operand, &dims, &op_strides, op_offset).unwrap();
let update_ref = RawStridedRef::new(&update, &[101, 51], &[1, 101], 0).unwrap();
let start_ref = RawStridedRef::new(&starts, &[2], &[1], 0).unwrap();
let mut expected = vec![0i64; 301 * 211];
for j in 0..211 {
for i in 0..301 {
expected[i + 301 * j] = operand[(op_offset - i as isize + 301 * j as isize) as usize];
}
}
for j in 0..51 {
for i in 0..101 {
expected[(17 + i) + 301 * (160 + j)] = update[i + 101 * j];
}
}
let (serial, parallel) = run_serial_and_parallel(|| {
let mut out = vec![0i64; 301 * 211];
let mut dest = RawStridedMut::new(&mut out, &dims, &[1, 301], 0).unwrap();
plan.execute(&mut dest, &source, &update_ref, &start_ref)
.unwrap();
out
});
assert_eq!(serial, expected);
assert_eq!(parallel, expected);
}
#[test]
fn dynamic_slice_rank_six_parallel_matches_serial() {
let dims = [3usize, 5, 7, 9, 11, 5];
let strides = [1isize, 3, 15, 105, 945, 10_395];
let total: usize = dims.iter().product();
let operand: Vec<i64> = (0..total as i64).collect();
let slice = [3usize, 4, 7, 8, 11, 5];
let dest_strides = [1isize, 3, 12, 84, 672, 7_392];
let plan =
DynamicSlicePlan::compile(&dims, &strides, &[6], &[1], &slice, &dest_strides, &slice)
.unwrap();
let starts = [0i64, 1, 0, 1, 0, 0];
let source = RawStridedRef::new(&operand, &dims, &strides, 0).unwrap();
let start_ref = RawStridedRef::new(&starts, &[6], &[1], 0).unwrap();
let out_len: usize = slice.iter().product();
let (serial, parallel) = run_serial_and_parallel(|| {
let mut out = vec![-1i64; out_len];
let mut dest = RawStridedMut::new(&mut out, &slice, &dest_strides, 0).unwrap();
plan.execute(&mut dest, &source, &start_ref).unwrap();
out
});
assert_eq!(serial, parallel);
assert_eq!(serial[0], 3 + 105);
assert!(!serial.contains(&-1));
}