#![cfg(feature = "wgpu")]
use scirs2_special::gpu_kernels::wgsl::{
bessel_j0_batch_wgpu, erf_batch_wgpu, erfc_batch_wgpu, erfinv_batch_wgpu, gamma_batch_wgpu,
lgamma_batch_wgpu, WgslDispatchError,
};
fn is_no_gpu(e: &WgslDispatchError) -> bool {
matches!(e, WgslDispatchError::GpuNotAvailable)
}
macro_rules! gpu_test {
($label:expr, $call:expr, $body:expr) => {{
match $call {
Err(e) if is_no_gpu(&e) => {
println!("{}: skipping — no GPU adapter", $label);
}
Err(e) => panic!("unexpected error: {:?}", e),
Ok(ys) => $body(ys),
}
}};
}
#[test]
fn test_gamma_wgpu_batch() {
let xs = vec![1.0_f64, 2.0, 3.0, 0.5];
gpu_test!("test_gamma_wgpu_batch", gamma_batch_wgpu(&xs), |ys: Vec<
f64,
>| {
assert_eq!(ys.len(), xs.len());
let expected = [1.0_f64, 1.0, 2.0, 1.772_453_850_9];
for (i, (y, e)) in ys.iter().zip(expected.iter()).enumerate() {
assert!(
(y - e).abs() < 1e-3,
"gamma(xs[{}]={}) = {} (expected {})",
i,
xs[i],
y,
e
);
}
});
}
#[test]
fn test_erf_wgpu_batch() {
let xs = vec![0.0_f64, 1.0, -1.0, 2.0];
gpu_test!("test_erf_wgpu_batch", erf_batch_wgpu(&xs), |ys: Vec<
f64,
>| {
assert_eq!(ys.len(), xs.len());
let expected = [0.0_f64, 0.842_700_79, -0.842_700_79, 0.995_322_27];
for (i, (y, e)) in ys.iter().zip(expected.iter()).enumerate() {
assert!(
(y - e).abs() < 1e-4,
"erf(xs[{}]={}) = {} (expected {})",
i,
xs[i],
y,
e
);
}
});
}
#[test]
fn test_bessel_j0_wgpu_batch() {
let xs = vec![0.0_f64, 2.4048];
gpu_test!(
"test_bessel_j0_wgpu_batch",
bessel_j0_batch_wgpu(&xs),
|ys: Vec<f64>| {
assert_eq!(ys.len(), xs.len());
assert!((ys[0] - 1.0).abs() < 1e-3);
assert!(ys[1].abs() < 0.01);
}
);
}
#[test]
fn test_lgamma_wgpu_batch() {
let xs = vec![1.0_f64, 2.0, 3.0, 0.5];
let ln2 = std::f64::consts::LN_2;
let ln_sqrt_pi = 0.5_f64 * std::f64::consts::PI.ln();
let expected = [0.0_f64, 0.0, ln2, ln_sqrt_pi];
gpu_test!(
"test_lgamma_wgpu_batch",
lgamma_batch_wgpu(&xs),
|ys: Vec<f64>| {
assert_eq!(ys.len(), xs.len());
for (i, (y, e)) in ys.iter().zip(expected.iter()).enumerate() {
assert!(
(y - e).abs() < 1e-3,
"lgamma(xs[{}]={}) = {} (expected {})",
i,
xs[i],
y,
e
);
}
}
);
}
#[test]
fn test_erfc_wgpu_batch() {
let xs = vec![0.0_f64, 1.0, -1.0, 2.0];
let expected = [1.0_f64, 0.157_299_21, 1.842_700_79, 0.004_677_73];
gpu_test!("test_erfc_wgpu_batch", erfc_batch_wgpu(&xs), |ys: Vec<
f64,
>| {
assert_eq!(ys.len(), xs.len());
for (i, (y, e)) in ys.iter().zip(expected.iter()).enumerate() {
assert!(
(y - e).abs() < 1e-3,
"erfc(xs[{}]={}) = {} (expected {})",
i,
xs[i],
y,
e
);
}
});
}
#[test]
fn test_erfinv_wgpu_batch() {
let xs = vec![0.0_f64, 0.5, -0.5, 0.9];
let expected = [0.0_f64, 0.476_936_276_2, -0.476_936_276_2, 1.163_087_154];
gpu_test!(
"test_erfinv_wgpu_batch",
erfinv_batch_wgpu(&xs),
|ys: Vec<f64>| {
assert_eq!(ys.len(), xs.len());
for (i, (y, e)) in ys.iter().zip(expected.iter()).enumerate() {
assert!(
(y - e).abs() < 0.01,
"erfinv(xs[{}]={}) = {} (expected {})",
i,
xs[i],
y,
e
);
}
}
);
}
#[test]
fn test_empty_input() {
let xs: Vec<f64> = vec![];
match gamma_batch_wgpu(&xs) {
Ok(ys) => assert!(ys.is_empty()),
Err(WgslDispatchError::GpuNotAvailable) => {}
Err(e) => panic!("unexpected error on empty input: {:?}", e),
}
}