#[test]
fn test_fused_qkv_attention_correctness() {
let head_dim = 16;
let hidden_dim = 64;
let seq_len = 4;
let fused = FusedQKVAttention::new(head_dim, hidden_dim).expect("test");
let input = Tensor::from_vec(
vec![seq_len, hidden_dim],
(0..(seq_len * hidden_dim))
.map(|i| (i as f32 * 0.01).sin())
.collect(),
)
.expect("test");
let output = fused.forward(&input).expect("test");
assert_eq!(output.shape(), input.shape());
for &val in output.data() {
assert!(val.is_finite(), "Output contains non-finite value: {}", val);
}
}
#[test]
fn test_fused_qkv_attention_single_token() {
let fused = FusedQKVAttention::new(8, 32).expect("test");
let input = Tensor::from_vec(vec![1, 32], vec![0.5; 32]).expect("test");
let output = fused.forward(&input).expect("test");
assert_eq!(output.shape(), &[1, 32]);
}
#[test]
fn test_fused_qkv_attention_error_zero_head_dim() {
let result = FusedQKVAttention::new(0, 64);
assert!(result.is_err());
}
#[test]
fn test_fused_qkv_attention_error_zero_hidden_dim() {
let result = FusedQKVAttention::new(8, 0);
assert!(result.is_err());
}
#[test]
fn test_fused_qkv_attention_error_mismatched_input() {
let fused = FusedQKVAttention::new(8, 64).expect("test");
let input = Tensor::from_vec(vec![4, 32], vec![0.1; 4 * 32]).expect("test");
let result = fused.forward(&input);
assert!(result.is_err());
}
#[test]
fn test_fused_qkv_attention_numerical_stability() {
let fused = FusedQKVAttention::new(8, 32).expect("test");
let input = Tensor::from_vec(vec![4, 32], vec![100.0; 4 * 32]).expect("test");
let output = fused.forward(&input).expect("test");
for &val in output.data() {
assert!(
val.is_finite(),
"Large inputs caused non-finite output: {}",
val
);
}
let input_small = Tensor::from_vec(vec![4, 32], vec![1e-10; 4 * 32]).expect("test");
let output_small = fused.forward(&input_small).expect("test");
for &val in output_small.data() {
assert!(
val.is_finite(),
"Small inputs caused non-finite output: {}",
val
);
}
}
#[test]
fn test_fused_qkv_attention_causal_mask() {
let fused = FusedQKVAttention::new(4, 16).expect("test");
let input =
Tensor::from_vec(vec![4, 16], (0..64).map(|i| (i as f32) * 0.1).collect()).expect("test");
let output = fused.forward(&input).expect("test");
assert_eq!(output.shape(), &[4, 16]);
}
#[test]
fn test_qa_003_attention_scores_correctness() {
let head_dim = 4;
let attention = Attention::new(head_dim).expect("test");
let q = Tensor::from_vec(
vec![2, head_dim],
vec![1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0],
)
.expect("test");
let k = q.clone();
let v = Tensor::from_vec(
vec![2, head_dim],
vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0],
)
.expect("test");
let output = attention.forward(&q, &k, &v).expect("test");
assert_eq!(output.shape(), &[2, head_dim]);
let data = output.data();
for &val in data {
assert!(val.is_finite(), "QA-003: Attention output should be finite");
}
}
#[test]
fn test_qa_004_rope_embeddings_correctness() {
let rope = RoPE::new(64, 10000.0).expect("test");
let input = Tensor::from_vec(vec![1, 64], vec![1.0; 64]).expect("test");
let output_pos0 = rope.forward(&input, 0).expect("test");
let output_pos1 = rope.forward(&input, 1).expect("test");
let data0 = output_pos0.data();
let data1 = output_pos1.data();
let mut differs = false;
for (a, b) in data0.iter().zip(data1.iter()) {
if (a - b).abs() > 1e-6 {
differs = true;
break;
}
}
assert!(
differs,
"QA-004: RoPE should produce different outputs at different positions"
);
for &val in data0 {
assert!(val.is_finite(), "QA-004: RoPE output should be finite");
}
}
#[test]
fn test_qa_005_softmax_sum_to_one() {
for size in [4, 16, 64, 256] {
let input = Tensor::from_vec(
vec![size],
(0..size).map(|i| (i as f32 * 0.1).sin()).collect(),
)
.expect("test");
let output = softmax(&input).expect("test");
let sum: f32 = output.data().iter().sum();
assert!(
(sum - 1.0).abs() < 1e-5,
"QA-005: Softmax sum should be 1.0, got {} for size {}",
sum,
size
);
for &val in output.data() {
assert!(val >= 0.0, "QA-005: Softmax outputs should be non-negative");
assert!(val <= 1.0, "QA-005: Softmax outputs should be <= 1.0");
}
}
}
#[test]
fn test_qa_006_layer_norm_unit_variance() {
let hidden_dim = 64;
let layer_norm = LayerNorm::new(hidden_dim, 1e-5).expect("test");
let input = Tensor::from_vec(
vec![1, hidden_dim],
(0..hidden_dim).map(|i| i as f32).collect(),
)
.expect("test");
let output = layer_norm.forward(&input).expect("test");
let data = output.data();
let mean: f32 = data.iter().sum::<f32>() / (hidden_dim as f32);
let variance: f32 = data.iter().map(|x| (x - mean).powi(2)).sum::<f32>() / (hidden_dim as f32);
assert!(
mean.abs() < 0.1,
"QA-006: Layer norm mean should be near 0, got {}",
mean
);
assert!(
variance > 0.0 && variance < 10.0,
"QA-006: Layer norm variance should be bounded, got {}",
variance
);
}
#[test]
fn test_qa_007_gelu_activation_correctness() {
let input_zero = Tensor::from_vec(vec![1], vec![0.0]).expect("test");
let output_zero = gelu(&input_zero).expect("test");
assert!(
output_zero.data()[0].abs() < 1e-5,
"QA-007: GELU(0) should be ~0, got {}",
output_zero.data()[0]
);
let input_pos = Tensor::from_vec(vec![1], vec![1.0]).expect("test");
let output_pos = gelu(&input_pos).expect("test");
assert!(
output_pos.data()[0] > 0.0,
"QA-007: GELU(1.0) should be positive"
);
let input_large = Tensor::from_vec(vec![1], vec![10.0]).expect("test");
let output_large = gelu(&input_large).expect("test");
assert!(
(output_large.data()[0] - 10.0).abs() < 1.0,
"QA-007: GELU(10) should be ~10"
);
let input_neg = Tensor::from_vec(vec![1], vec![-0.5]).expect("test");
let output_neg = gelu(&input_neg).expect("test");
assert!(
output_neg.data()[0] < 0.0 && output_neg.data()[0] > -1.0,
"QA-007: GELU(-0.5) should be small negative"
);
}
#[test]
fn test_qa_009_kv_cache_correctness() {
use crate::inference::KVCache;
let num_layers = 2;
let hidden_dim = 64;
let max_seq_len = 32;
let mut cache = KVCache::new(num_layers, hidden_dim, max_seq_len);
let k_data: Vec<f32> = (0..hidden_dim).map(|i| i as f32 * 0.1).collect();
let v_data: Vec<f32> = (0..hidden_dim).map(|i| i as f32 * 0.2).collect();
cache.store(0, &k_data, &v_data);
cache.advance();
let k_data2: Vec<f32> = (0..hidden_dim).map(|i| i as f32 * 0.3).collect();
let v_data2: Vec<f32> = (0..hidden_dim).map(|i| i as f32 * 0.4).collect();
cache.store(0, &k_data2, &v_data2);
cache.advance();
let k_out = cache.get_k(0);
let v_out = cache.get_v(0);
assert_eq!(
k_out.len(),
2 * hidden_dim,
"QA-009: K cache should contain 2 positions"
);
assert_eq!(
v_out.len(),
2 * hidden_dim,
"QA-009: V cache should contain 2 positions"
);
for i in 0..hidden_dim {
assert!(
(k_out[i] - k_data[i]).abs() < 1e-6,
"QA-009: K cache position 0 should match stored value at index {}",
i
);
assert!(
(v_out[i] - v_data[i]).abs() < 1e-6,
"QA-009: V cache position 0 should match stored value at index {}",
i
);
}
for i in 0..hidden_dim {
assert!(
(k_out[hidden_dim + i] - k_data2[i]).abs() < 1e-6,
"QA-009: K cache position 1 should match stored value at index {}",
i
);
}
}
#[test]
fn test_qa_010_quantized_vs_f32_tolerance() {
use crate::quantize::{dequantize_q4_k, dequantize_q8_0};
let mut q8_data = vec![0u8; 34]; q8_data[0..2].copy_from_slice(&0x3C00_u16.to_le_bytes());
for i in 0..32 {
q8_data[2 + i] = i as u8; }
let dequant = dequantize_q8_0(&q8_data).expect("test");
assert_eq!(
dequant.len(),
32,
"QA-010: Q8_0 should produce 32 values per block"
);
for &val in &dequant {
assert!(
val.is_finite(),
"QA-010: Q8_0 dequantized values should be finite"
);
}
let mut q4k_data = vec![0u8; 144]; q4k_data[0..2].copy_from_slice(&0x3C00_u16.to_le_bytes());
q4k_data[2..4].copy_from_slice(&0x0000_u16.to_le_bytes());
let q4k_dequant = dequantize_q4_k(&q4k_data).expect("test");
assert_eq!(
q4k_dequant.len(),
256,
"QA-010: Q4_K should produce 256 values per super-block"
);
for &val in &q4k_dequant {
assert!(
val.is_finite(),
"QA-010: Dequantized values should be finite"
);
}
}