#![cfg(feature = "eval")]
use rlx_tensor::Tensor;
fn approx(a: &[f32], b: &[f32]) {
assert_eq!(a.len(), b.len(), "length mismatch: {a:?} vs {b:?}");
for (x, y) in a.iter().zip(b) {
assert!((x - y).abs() < 1e-4, "{a:?} != {b:?}");
}
}
#[test]
fn rms_norm_matches_naive() {
let eps: f64 = 1e-5;
let x = Tensor::from_vec(vec![1.0, 2.0, 3.0, -1.0, 0.5, 4.0], [2, 3]);
let gamma = Tensor::from_vec(vec![1.0, 2.0, 0.5], [3]);
let beta = Tensor::from_vec(vec![0.1, -0.2, 0.3], [3]);
let fused = x.rms_norm(&gamma, &beta, eps as f32).to_vec();
let ms = (&x * &x).mean([1], true); let denom = (&ms + eps).sqrt();
let normed = &x / &denom;
let naive = (&(&normed * &gamma) + &beta).to_vec();
approx(&fused, &naive);
}
#[test]
fn layer_norm_matches_naive() {
let eps: f64 = 1e-5;
let x = Tensor::from_vec(vec![1.0, 2.0, 3.0, -1.0, 0.5, 4.0], [2, 3]);
let gamma = Tensor::from_vec(vec![1.0, 2.0, 0.5], [3]);
let beta = Tensor::from_vec(vec![0.1, -0.2, 0.3], [3]);
let fused = x.layer_norm(&gamma, &beta, eps as f32).to_vec();
let mu = x.mean([1], true); let xc = &x - μ
let var = (&xc * &xc).mean([1], true);
let denom = (&var + eps).sqrt();
let normed = &xc / &denom;
let naive = (&(&normed * &gamma) + &beta).to_vec();
approx(&fused, &naive);
}
#[test]
fn rope_identity_when_cos1_sin0() {
let x = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0], [1, 2, 4]);
let cos = Tensor::from_vec(vec![1.0; 4], [4]);
let sin = Tensor::from_vec(vec![0.0; 4], [4]);
let out = x.rope(&cos, &sin, 4).to_vec();
approx(&out, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);
}
#[test]
fn rope_rotates_by_known_angle() {
let x = Tensor::from_vec(vec![1.0, 2.0], [1, 1, 2]);
let cos = Tensor::from_vec(vec![0.6], [1]);
let sin = Tensor::from_vec(vec![0.8], [1]);
let out = x.rope(&cos, &sin, 2).to_vec();
approx(&out, &[-1.0, 2.0]);
}
#[test]
fn rope_reads_a_row_per_position_from_a_flat_table() {
let x = Tensor::from_vec(vec![1.0, 2.0, 3.0, 4.0], [1, 2, 2]);
let cos = Tensor::from_vec(vec![1.0, 0.0], [2]);
let sin = Tensor::from_vec(vec![0.0, 1.0], [2]);
let out = x.rope(&cos, &sin, 2).to_vec();
approx(&out, &[1.0, 2.0, -4.0, 3.0]);
}