#![cfg(all(feature = "par", feature = "gpu-wgpu"))]
use ordofp_core::par::{ParFlumen, backend::wgpu::GpuWgpu};
macro_rules! gpu_or_skip {
() => {
match GpuWgpu::with_min_len(1) {
Ok(gpu) => gpu,
Err(e) => {
eprintln!("skipping GPU test: {e}");
return;
}
}
};
}
#[test]
fn reduce_after_pool_reuse_is_exact() {
let gpu = gpu_or_skip!();
let big: Vec<f32> = (0..8192).map(|i| i as f32).collect();
let _ = ParFlumen::from_vec_gpu(big)
.map_gpu("x", |x| x)
.collect_gpu(&gpu);
let small: Vec<f32> = vec![1.0; 1024];
let sum = ParFlumen::from_vec_gpu(small).reduce_gpu(&gpu, "+", |a, b| a + b);
assert_eq!(sum, Some(1024.0));
}
#[test]
fn reduce_product_non_multiple_of_workgroup() {
let gpu = gpu_or_skip!();
let xs: Vec<f32> = vec![1.0; 100]; let prod = ParFlumen::from_vec_gpu(xs).reduce_gpu(&gpu, "*", |a, b| a * b);
assert_eq!(prod, Some(1.0));
}
#[test]
fn reduce_min_max() {
let gpu = gpu_or_skip!();
let xs: Vec<i32> = (1..=4097).collect(); assert_eq!(
ParFlumen::from_vec_gpu(xs.clone()).reduce_gpu(&gpu, "min", std::cmp::Ord::min),
Some(1)
);
assert_eq!(
ParFlumen::from_vec_gpu(xs).reduce_gpu(&gpu, "max", std::cmp::Ord::max),
Some(4097)
);
}
#[test]
fn reduce_single_element() {
let gpu = gpu_or_skip!();
let xs: Vec<f32> = vec![42.0];
assert_eq!(
ParFlumen::from_vec_gpu(xs).reduce_gpu(&gpu, "+", |a, b| a + b),
Some(42.0)
);
}
#[test]
fn bad_wgsl_falls_back_to_cpu() {
let gpu = gpu_or_skip!();
let xs: Vec<f32> = vec![1.0, 2.0, 3.0];
let out = ParFlumen::from_vec_gpu(xs)
.map_gpu("this is not wgsl !!!", |x| x * 2.0)
.collect_gpu(&gpu);
assert_eq!(out, vec![2.0, 4.0, 6.0]);
}
#[test]
fn unknown_operator_falls_back() {
let gpu = gpu_or_skip!();
let xs: Vec<f32> = vec![1.0, 2.0, 3.0];
let out = ParFlumen::from_vec_gpu(xs).reduce_gpu(&gpu, "^", |acc, x| acc + x);
assert_eq!(out, Some(6.0));
}