use crate::layers::*;
use crate::tensor::Tensor;
#[test]
fn test_attention_getters_and_traits() {
let attn = Attention::new(64).expect("test");
assert_eq!(attn.head_dim(), 64);
let expected = 1.0 / (64.0f32).sqrt();
assert!((attn.scale() - expected).abs() < 1e-7);
let debug = format!("{:?}", attn);
assert!(debug.contains("Attention"));
let cloned = attn.clone();
assert_eq!(attn.head_dim(), cloned.head_dim());
}
#[test]
fn test_sliding_window_minimal_window() {
let swa = SlidingWindowAttention::new(4, 1).expect("test");
let q = Tensor::from_vec(vec![4], vec![1.0, 0.0, 0.0, 0.0]).expect("test");
let k = Tensor::from_vec(vec![4], vec![1.0, 0.0, 0.0, 0.0]).expect("test");
let v = Tensor::from_vec(vec![4], vec![2.0, 3.0, 4.0, 5.0]).expect("test");
let output = swa.forward(&q, &k, &v).expect("test");
assert_eq!(output.shape(), &[1, 4]);
for i in 0..4 {
assert!((output.data()[i] - v.data()[i]).abs() < 1e-5);
}
}
#[test]
fn test_sliding_window_bidirectional_mode() {
let swa = SlidingWindowAttention::new(4, 3).expect("test");
let q = Tensor::from_vec(vec![4, 4], vec![0.1; 16]).expect("test");
let k = Tensor::from_vec(vec![4, 4], vec![0.2; 16]).expect("test");
let v = Tensor::from_vec(vec![4, 4], (1..17).map(|x| x as f32 * 0.1).collect()).expect("test");
let bidirectional = swa.forward_with_mask(&q, &k, &v, false).expect("test");
assert_eq!(bidirectional.shape(), &[4, 4]);
let forward_result = swa.forward(&q, &k, &v).expect("test");
let causal = swa.forward_with_mask(&q, &k, &v, true).expect("test");
for i in 0..forward_result.data().len() {
assert!((forward_result.data()[i] - causal.data()[i]).abs() < 1e-6);
}
}
#[test]
fn test_sliding_window_getters_and_traits() {
let swa = SlidingWindowAttention::new(64, 4096).expect("test");
assert_eq!(swa.head_dim(), 64);
assert_eq!(swa.window_size(), 4096);
assert!((swa.scale() - 1.0 / 8.0).abs() < 1e-7);
assert_eq!(swa.effective_context(0, 10), 1); assert_eq!(swa.effective_context(5, 10), 6);
let debug = format!("{:?}", swa);
assert!(debug.contains("SlidingWindowAttention"));
let cloned = swa.clone();
assert_eq!(swa.window_size(), cloned.window_size());
}
#[test]
fn test_flash_forward_1d_inputs() {
let attn = Attention::new(8).expect("test");
let q = Tensor::from_vec(vec![8], vec![1.0; 8]).expect("test");
let k = Tensor::from_vec(vec![8], vec![1.0; 8]).expect("test");
let v = Tensor::from_vec(vec![8], (1..9).map(|x| x as f32).collect()).expect("test");
let flash = attn.flash_forward(&q, &k, &v, 1).expect("test");
let v2 = attn.flash_forward_v2(&q, &k, &v, 1).expect("test");
let parallel = attn.flash_forward_parallel(&q, &k, &v, 1).expect("test");
assert_eq!(flash.shape(), &[1, 8]);
assert_eq!(v2.shape(), &[1, 8]);
assert_eq!(parallel.shape(), &[1, 8]);
for i in 0..8 {
assert!((flash.data()[i] - v.data()[i]).abs() < 1e-5);
}
}
#[test]
fn test_simd_remainder_paths() {
let attn9 = Attention::new(9).expect("test");
let q9 = Tensor::from_vec(
vec![2, 9],
(0..18).map(|i| (i as f32 * 0.1).sin()).collect(),
)
.expect("test");
let k9 = Tensor::from_vec(
vec![2, 9],
(0..18).map(|i| (i as f32 * 0.1).cos()).collect(),
)
.expect("test");
let v9 =
Tensor::from_vec(vec![2, 9], (0..18).map(|i| i as f32 * 0.05).collect()).expect("test");
let std9 = attn9.forward(&q9, &k9, &v9).expect("test");
let v2_9 = attn9.flash_forward_v2(&q9, &k9, &v9, 1).expect("test");
for i in 0..std9.data().len() {
assert!((std9.data()[i] - v2_9.data()[i]).abs() < 1e-4);
}
let attn15 = Attention::new(15).expect("test");
let q15 = Tensor::from_vec(vec![2, 15], vec![0.1; 30]).expect("test");
let k15 = Tensor::from_vec(vec![2, 15], vec![0.2; 30]).expect("test");
let v15 =
Tensor::from_vec(vec![2, 15], (0..30).map(|i| i as f32 * 0.02).collect()).expect("test");
let std15 = attn15.forward(&q15, &k15, &v15).expect("test");
let par15 = attn15
.flash_forward_parallel(&q15, &k15, &v15, 2)
.expect("test");
for i in 0..std15.data().len() {
assert!((std15.data()[i] - par15.data()[i]).abs() < 1e-4);
}
}
#[test]
fn test_fused_qkv_traits_and_heads() {
let fused = FusedQKVAttention::new(8, 32).expect("test");
let debug = format!("{:?}", fused);
assert!(debug.contains("FusedQKVAttention"));
let cloned = fused.clone();
assert_eq!(fused.head_dim(), cloned.head_dim());
assert_eq!(fused.hidden_dim(), cloned.hidden_dim());
let single = FusedQKVAttention::new(8, 8).expect("test");
assert_eq!(single.num_heads(), 1);
let input = Tensor::from_vec(vec![2, 8], vec![0.1; 16]).expect("test");
let output = single.forward(&input).expect("test");
assert_eq!(output.shape(), &[2, 8]);
let many = FusedQKVAttention::new(4, 64).expect("test");
assert_eq!(many.num_heads(), 16);
}
#[test]
fn test_mha_modes_and_traits() {
let mha = MultiHeadAttention::mha(64, 8).expect("test");
let debug = format!("{:?}", mha);
assert!(debug.contains("MultiHeadAttention"));
let cloned = mha.clone();
assert_eq!(mha.num_heads(), cloned.num_heads());
assert!(mha.is_mha());
assert!(!mha.is_mqa());
assert!(!mha.is_gqa());
let mqa = MultiHeadAttention::mqa(64, 8).expect("test");
assert!(mqa.is_mqa());
assert!(!mqa.is_mha());
let gqa = MultiHeadAttention::gqa(128, 16, 4).expect("test");
assert!(gqa.is_gqa());
assert!(!gqa.is_mha());
assert!(!gqa.is_mqa());
assert_eq!(gqa.head_dim(), 8);
}
#[test]
fn test_mha_single_head_edge_case() {
let mha = MultiHeadAttention::new(16, 1, 1).expect("test");
assert!(mha.is_mha()); assert!(mha.is_mqa()); assert!(!mha.is_gqa());
let input = Tensor::from_vec(vec![2, 16], vec![0.1; 32]).expect("test");
let output = mha.forward(&input).expect("test");
assert_eq!(output.shape(), &[2, 16]);
}
#[test]
fn test_attention_cross_attention_shape() {
let attn = Attention::new(4).expect("test");
let q = Tensor::from_vec(vec![2, 4], vec![1.0; 8]).expect("test");
let k = Tensor::from_vec(vec![3, 4], vec![1.0; 12]).expect("test");
let v = Tensor::from_vec(vec![3, 4], (1..13).map(|x| x as f32 * 0.1).collect()).expect("test");
let output = attn.forward(&q, &k, &v).expect("test");
assert_eq!(output.shape(), &[2, 4]); }
#[test]
fn test_attention_long_sequence() {
let attn = Attention::new(8).expect("test");
let q = Tensor::from_vec(vec![64, 8], vec![0.1; 512]).expect("test");
let k = Tensor::from_vec(vec![64, 8], vec![0.1; 512]).expect("test");
let v =
Tensor::from_vec(vec![64, 8], (0..512).map(|i| i as f32 * 0.001).collect()).expect("test");
let output = attn.forward(&q, &k, &v).expect("test");
assert_eq!(output.shape(), &[64, 8]);
for &val in output.data() {
assert!(val.is_finite());
}
}
#[test]
fn test_flash_block_larger_than_seq() {
let attn = Attention::new(8).expect("test");
let q = Tensor::from_vec(vec![4, 8], vec![0.1; 32]).expect("test");
let k = Tensor::from_vec(vec![4, 8], vec![0.2; 32]).expect("test");
let v = Tensor::from_vec(vec![4, 8], (0..32).map(|i| i as f32 * 0.05).collect()).expect("test");
let standard = attn.forward(&q, &k, &v).expect("test");
let flash = attn.flash_forward(&q, &k, &v, 16).expect("test");
let v2 = attn.flash_forward_v2(&q, &k, &v, 16).expect("test");
let parallel = attn.flash_forward_parallel(&q, &k, &v, 16).expect("test");
for i in 0..standard.data().len() {
assert!((standard.data()[i] - flash.data()[i]).abs() < 1e-4);
assert!((standard.data()[i] - v2.data()[i]).abs() < 1e-4);
assert!((standard.data()[i] - parallel.data()[i]).abs() < 1e-4);
}
}
#[test]
fn test_sliding_window_bidirectional_vs_causal() {
let swa = SlidingWindowAttention::new(4, 5).expect("test");
let q = Tensor::from_vec(
vec![6, 4],
(0..24).map(|i| (i as f32 * 0.15).sin()).collect(),
)
.expect("test");
let k = Tensor::from_vec(
vec![6, 4],
(0..24).map(|i| (i as f32 * 0.15).cos()).collect(),
)
.expect("test");
let v = Tensor::from_vec(vec![6, 4], (0..24).map(|i| i as f32 * 0.1).collect()).expect("test");
let causal = swa.forward(&q, &k, &v).expect("test");
let bidirectional = swa.forward_with_mask(&q, &k, &v, false).expect("test");
assert_eq!(causal.shape(), bidirectional.shape());
for &val in causal.data() {
assert!(val.is_finite());
}
for &val in bidirectional.data() {
assert!(val.is_finite());
}
}