use crate::gguf::test_helpers::create_test_model_with_config;
use crate::gguf::{GGUFConfig, OwnedQuantizedModelCached};
#[test]
#[cfg(feature = "gpu")]
#[serial_test::serial]
fn test_imp_112a_cached_scheduler_initialization() {
let config = GGUFConfig {
architecture: "test".to_string(),
constraints: crate::gguf::ArchConstraints::from_architecture("test"),
hidden_dim: 64,
intermediate_dim: 128,
num_layers: 1,
num_heads: 4,
num_kv_heads: 4,
vocab_size: 100,
context_length: 256,
rope_theta: 10000.0,
eps: 1e-5,
rope_type: 0,
explicit_head_dim: None,
query_pre_attn_scalar: None,
bos_token_id: None,
eos_token_id: None,
};
let model = create_test_model_with_config(&config);
let cached_model = OwnedQuantizedModelCached::new(model);
let tokens = vec![1u32, 5, 10];
let result1 = cached_model
.forward_batch_gpu_cached(&tokens)
.expect("IMP-112a: First cached forward should succeed");
assert_eq!(
result1.len(),
tokens.len() * config.vocab_size,
"IMP-112a: Should return correct output shape"
);
let result2 = cached_model
.forward_batch_gpu_cached(&tokens)
.expect("IMP-112a: Second cached forward should succeed");
assert_eq!(result1.len(), result2.len());
for i in 0..result1.len() {
let diff = (result1[i] - result2[i]).abs();
assert!(
diff < 1e-6,
"IMP-112a: Results should be identical on repeated calls, pos {}: diff={}",
i,
diff
);
}
}
#[test]
#[cfg(feature = "gpu")]
#[serial_test::serial]
fn test_imp_112b_cached_matches_uncached() {
let config = GGUFConfig {
architecture: "test".to_string(),
constraints: crate::gguf::ArchConstraints::from_architecture("test"),
hidden_dim: 64,
intermediate_dim: 128,
num_layers: 1,
num_heads: 4,
num_kv_heads: 4,
vocab_size: 100,
context_length: 256,
rope_theta: 10000.0,
eps: 1e-5,
rope_type: 0,
explicit_head_dim: None,
query_pre_attn_scalar: None,
bos_token_id: None,
eos_token_id: None,
};
let model = create_test_model_with_config(&config);
let cached_model = OwnedQuantizedModelCached::new(model.clone());
let tokens = vec![1u32, 5, 10, 20];
let uncached_result = model
.forward_batch_gpu(&tokens)
.expect("Uncached forward should succeed");
let cached_result = cached_model
.forward_batch_gpu_cached(&tokens)
.expect("Cached forward should succeed");
assert_eq!(uncached_result.len(), cached_result.len());
for i in 0..uncached_result.len() {
let diff = (uncached_result[i] - cached_result[i]).abs();
assert!(
diff < 1e-4,
"IMP-112b: Cached should match uncached, pos {}: uncached={}, cached={}, diff={}",
i,
uncached_result[i],
cached_result[i],
diff
);
}
}
#[test]
#[cfg(feature = "cuda")]
#[serial_test::serial]
fn test_parity_114_cuda_gemm_correctness() {
let config = GGUFConfig {
architecture: "test".to_string(),
constraints: crate::gguf::ArchConstraints::from_architecture("test"),
hidden_dim: 64,
intermediate_dim: 128,
num_layers: 1,
num_heads: 4,
num_kv_heads: 4,
vocab_size: 100,
context_length: 256,
rope_theta: 10000.0,
eps: 1e-5,
rope_type: 0,
explicit_head_dim: None,
query_pre_attn_scalar: None,
bos_token_id: None,
eos_token_id: None,
};
let model = create_test_model_with_config(&config);
let cached_model = OwnedQuantizedModelCached::new(model);
let tokens = vec![1u32, 5, 10, 20];
let result = cached_model
.forward_batch_gpu_cached(&tokens)
.expect("PARITY-114: CUDA forward should succeed");
assert_eq!(result.len(), tokens.len() * config.vocab_size);
assert!(
result.iter().all(|x| x.is_finite()),
"PARITY-114: CUDA should produce finite values"
);
let max_val = result.iter().cloned().fold(f32::NEG_INFINITY, f32::max);
let min_val = result.iter().cloned().fold(f32::INFINITY, f32::min);
eprintln!(
"PARITY-114 RESOLVED: CUDA output range: [{:.4}, {:.4}]",
min_val, max_val
);
}
#[test]
#[cfg(feature = "gpu")]
#[serial_test::serial]
fn test_imp_112c_multiple_operations_same_scheduler() {
let config = GGUFConfig {
architecture: "test".to_string(),
constraints: crate::gguf::ArchConstraints::from_architecture("test"),
hidden_dim: 64,
intermediate_dim: 128,
num_layers: 1,
num_heads: 4,
num_kv_heads: 4,
vocab_size: 100,
context_length: 256,
rope_theta: 10000.0,
eps: 1e-5,
rope_type: 0,
explicit_head_dim: None,
query_pre_attn_scalar: None,
bos_token_id: None,
eos_token_id: None,
};
let model = create_test_model_with_config(&config);
let cached_model = OwnedQuantizedModelCached::new(model);
let tokens1 = vec![1u32, 2, 3];
let tokens2 = vec![10u32, 20, 30, 40];
let tokens3 = vec![5u32];
let result1 = cached_model
.forward_batch_gpu_cached(&tokens1)
.expect("IMP-112c: Forward 1 should succeed");
let result2 = cached_model
.forward_batch_gpu_cached(&tokens2)
.expect("IMP-112c: Forward 2 should succeed");
let result3 = cached_model
.forward_batch_gpu_cached(&tokens3)
.expect("IMP-112c: Forward 3 should succeed");
assert_eq!(result1.len(), 3 * config.vocab_size);
assert_eq!(result2.len(), 4 * config.vocab_size);
assert_eq!(result3.len(), config.vocab_size);
assert!(result1.iter().all(|x| x.is_finite()));
assert!(result2.iter().all(|x| x.is_finite()));
assert!(result3.iter().all(|x| x.is_finite()));
}
#[test]
#[cfg(feature = "gpu")]
#[serial_test::serial]
fn test_imp_112d_cached_attention_matches_uncached() {
let config = GGUFConfig {
architecture: "test".to_string(),
constraints: crate::gguf::ArchConstraints::from_architecture("test"),
hidden_dim: 64,
intermediate_dim: 128,
num_layers: 1,
num_heads: 4,
num_kv_heads: 4,
vocab_size: 100,
context_length: 256,
rope_theta: 10000.0,
eps: 1e-5,
rope_type: 0,
explicit_head_dim: None,
query_pre_attn_scalar: None,
bos_token_id: None,
eos_token_id: None,
};
let model = create_test_model_with_config(&config);
let cached_model = OwnedQuantizedModelCached::new(model.clone());
let seq_len = 8;
let hidden_dim = config.hidden_dim;
let q: Vec<f32> = (0..seq_len * hidden_dim)
.map(|i| ((i % 13) as f32 - 6.0) * 0.1)
.collect();
let k: Vec<f32> = (0..seq_len * hidden_dim)
.map(|i| ((i % 11) as f32 - 5.0) * 0.1)
.collect();
let v: Vec<f32> = (0..seq_len * hidden_dim)
.map(|i| ((i % 7) as f32 - 3.0) * 0.1)
.collect();
let uncached_attn = model
.parallel_multihead_attention_gpu(&q, &k, &v, seq_len)
.expect("Uncached attention should succeed");
let cached_attn = cached_model
.parallel_multihead_attention_gpu_cached(&q, &k, &v, seq_len)
.expect("Cached attention should succeed");
assert_eq!(uncached_attn.len(), cached_attn.len());
for i in 0..uncached_attn.len() {
let diff = (uncached_attn[i] - cached_attn[i]).abs();
assert!(
diff < 1e-4,
"IMP-112d: Cached attention should match uncached, pos {}: diff={}",
i,
diff
);
}
}
#[test]
fn test_imp_111a_online_softmax_correctness() {
let config = GGUFConfig {
architecture: "test".to_string(),
constraints: crate::gguf::ArchConstraints::from_architecture("test"),
hidden_dim: 64,
intermediate_dim: 128,
num_layers: 1,
num_heads: 4,
num_kv_heads: 4,
vocab_size: 100,
context_length: 256,
rope_theta: 10000.0,
eps: 1e-5,
rope_type: 0,
explicit_head_dim: None,
query_pre_attn_scalar: None,
bos_token_id: None,
eos_token_id: None,
};
let model = create_test_model_with_config(&config);
let scores: Vec<f32> = (0..16).map(|i| ((i % 7) as f32 - 3.0) * 0.5).collect();
let standard = model.standard_softmax(&scores);
let tile_size = 4;
let online = model
.online_softmax(&scores, tile_size)
.expect("IMP-111a: Online softmax should succeed");
assert_eq!(standard.len(), online.len());
for i in 0..standard.len() {
let diff = (standard[i] - online[i]).abs();
assert!(
diff < 1e-5,
"IMP-111a: Online softmax differs at {}: standard={}, online={}, diff={}",
i,
standard[i],
online[i],
diff
);
}
let std_sum: f32 = standard.iter().sum();
let online_sum: f32 = online.iter().sum();
assert!(
(std_sum - 1.0).abs() < 1e-5,
"Standard softmax should sum to 1"
);
assert!(
(online_sum - 1.0).abs() < 1e-5,
"Online softmax should sum to 1"
);
}
#[test]
fn test_imp_111b_tiled_attention_matches_standard() {
let config = GGUFConfig {
architecture: "test".to_string(),
constraints: crate::gguf::ArchConstraints::from_architecture("test"),
hidden_dim: 32,
intermediate_dim: 64,
num_layers: 1,
num_heads: 4,
num_kv_heads: 4,
vocab_size: 50,
context_length: 128,
rope_theta: 10000.0,
eps: 1e-5,
rope_type: 0,
explicit_head_dim: None,
query_pre_attn_scalar: None,
bos_token_id: None,
eos_token_id: None,
};
let model = create_test_model_with_config(&config);
let seq_len = 8;
let head_dim = config.hidden_dim / config.num_heads;
let q: Vec<f32> = (0..seq_len * head_dim)
.map(|i| ((i % 13) as f32 - 6.0) * 0.1)
.collect();
let k: Vec<f32> = (0..seq_len * head_dim)
.map(|i| ((i % 11) as f32 - 5.0) * 0.1)
.collect();
let v: Vec<f32> = (0..seq_len * head_dim)
.map(|i| ((i % 7) as f32 - 3.0) * 0.1)
.collect();
let scale = 1.0 / (head_dim as f32).sqrt();
let standard_output = model
.standard_single_head_attention(&q, &k, &v, seq_len, head_dim, scale)
.expect("Standard attention should succeed");
let tile_size = 4;
let tiled_output = model
.tiled_single_head_attention(&q, &k, &v, seq_len, head_dim, scale, tile_size)
.expect("IMP-111b: Tiled attention should succeed");
assert_eq!(standard_output.len(), tiled_output.len());
for i in 0..standard_output.len() {
let diff = (standard_output[i] - tiled_output[i]).abs();
assert!(
diff < 1e-4,
"IMP-111b: Tiled attention differs at {}: standard={}, tiled={}, diff={}",
i,
standard_output[i],
tiled_output[i],
diff
);
}
}
include!("imp_111c.rs");
include!("imp_114a.rs");