#![cfg(feature = "eval")]
use rlx_tensor::{Device, Tensor, available_devices};
fn approx(a: &[f32], b: &[f32], dev: Device) {
assert_eq!(a.len(), b.len(), "{dev:?}: length mismatch");
for (x, y) in a.iter().zip(b) {
assert!((x - y).abs() < 1e-3, "{dev:?}: {a:?} != {b:?}");
}
}
fn sample() -> Tensor {
let a = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [2, 3]);
let w = Tensor::from_vec(vec![0.5, -1.0, 2.0, 0.0, 1.0, 1.0], [3, 2]);
let b = Tensor::from_vec(vec![0.1, -0.2], [2]);
(&a.matmul(&w) + &b).relu().sum([1], false)
}
#[test]
fn gpu_backends_match_cpu() {
let reference = sample().to_vec_on(Device::Cpu);
let mut validated = vec![Device::Cpu];
for dev in available_devices() {
if matches!(dev, Device::Cpu | Device::Ane) {
continue;
}
let got = sample().to_vec_on(dev);
approx(&got, &reference, dev);
validated.push(dev);
}
eprintln!("validated backends against CPU: {validated:?}");
assert!(validated.contains(&Device::Cpu));
rlx_tensor::clear_cache();
}
#[test]
fn different_work_on_different_gpu_backends() {
use rlx_tensor::{Device, Tensor, available_devices};
let gpus: Vec<Device> = available_devices()
.into_iter()
.filter(|d| !matches!(d, Device::Cpu | Device::Ane))
.collect();
eprintln!("live GPU backends: {gpus:?}");
for (i, dev) in gpus.iter().enumerate() {
let x = Tensor::from_vec(vec![1.0, 2.0, 3.0], [3]);
let y = (&x * &x).sum([0], false).to_vec_on(*dev); assert!((y[0] - 14.0).abs() < 1e-3, "{dev:?} -> {y:?}");
eprintln!(" backend #{i} {dev:?}: sum(x^2)=14 OK");
}
rlx_tensor::clear_cache();
}