use crate::quantize::detect_simd_backend;
use crate::quantize::types::{
DequantStats, InterleavedQ4K, Q4_0Block, Q4_KBlock, Q5_KBlock, Q6_KBlock, Q8KSuperBlock,
Q8_0Block, SimdBackend, BLOCK_SIZE, QK_K,
};
#[test]
fn test_q8_0_block_quantize_near_zero_values() {
let values = [1e-12f32; 32];
let block = Q8_0Block::quantize(&values);
let expected_scale = 1.0 / 127.0;
assert!(
(block.scale - expected_scale).abs() < 1e-9,
"Expected minimal scale {expected_scale}, got {}",
block.scale
);
assert!(
block.quants.iter().all(|&q| q == 0),
"Expected all zeros for near-zero input"
);
}
#[test]
fn test_q8_0_block_quantize_exact_zeros() {
let values = [0.0f32; 32];
let block = Q8_0Block::quantize(&values);
assert!(block.scale > 0.0, "Scale should be positive even for zeros");
assert!(
block.quants.iter().all(|&q| q == 0),
"All quants should be zero"
);
}
#[test]
fn test_q8_0_block_quantize_clamp_negative() {
let mut values = [0.0f32; 32];
values[0] = 1.0; values[1] = -200.0;
let mut values2 = [0.0f32; 32];
values2[0] = 1.0; for i in 1..32 {
values2[i] = if i % 2 == 0 { 1.0 } else { -1.0 };
}
let block = Q8_0Block::quantize(&values2);
assert!(block.scale > 0.0);
}
#[test]
fn test_q8_0_block_quantize_clamp_positive() {
let mut values = [100.0f32; 32];
values[0] = 100.0; let block = Q8_0Block::quantize(&values);
assert!(
block.quants.iter().all(|&q| q == 127),
"All should clamp to 127"
);
}
#[test]
fn test_q8_0_block_relative_error_tiny_max() {
let original = [1e-12f32; 32];
let block = Q8_0Block::quantize(&original);
let error = block.relative_error(&original);
assert!(
error.abs() < 1e-6,
"Relative error should be 0 for tiny values, got {error}"
);
}
#[test]
fn test_q8_0_block_quantization_error_varied() {
let mut original = [0.0f32; 32];
for i in 0..32 {
original[i] = (i as f32) * 0.5 - 7.5; }
let block = Q8_0Block::quantize(&original);
let error = block.quantization_error(&original);
assert!(error >= 0.0, "Error should be non-negative");
assert!(error < 1.0, "Error should be small for reasonable values");
}
#[test]
fn test_q8_0_block_mixed_extremes() {
let mut values = [0.0f32; 32];
values[0] = 1000.0;
values[1] = -1000.0;
for i in 2..32 {
values[i] = (i as f32) - 16.0;
}
let block = Q8_0Block::quantize(&values);
let dequantized = block.dequantize();
let max_orig = values.iter().cloned().fold(f32::NEG_INFINITY, f32::max);
let max_deq = dequantized
.iter()
.cloned()
.fold(f32::NEG_INFINITY, f32::max);
assert!(
(max_orig - max_deq).abs() < max_orig * 0.02,
"Max should be preserved within 2%"
);
}
#[test]
fn test_q8k_superblock_quantize_near_zero() {
let values = [1e-12f32; 256];
let block = Q8KSuperBlock::quantize(&values);
let expected_scale = 1.0 / 127.0;
assert!(
(block.scale - expected_scale).abs() < 1e-9,
"Expected minimal scale"
);
}
#[test]
fn test_q8k_superblock_quantize_into_near_zero() {
let values = [1e-12f32; 256];
let mut scale = 0.0f32;
let mut quants = [0i8; 256];
Q8KSuperBlock::quantize_into(&values, &mut scale, &mut quants);
let expected_scale = 1.0 / 127.0;
assert!(
(scale - expected_scale).abs() < 1e-9,
"Expected minimal scale from quantize_into"
);
}
#[test]
fn test_q8k_superblock_quantize_into_varied() {
let mut values = [0.0f32; 256];
for i in 0..256 {
values[i] = (i as f32 - 127.5) * 0.1;
}
let mut scale = 0.0f32;
let mut quants = [0i8; 256];
Q8KSuperBlock::quantize_into(&values, &mut scale, &mut quants);
assert!(scale > 0.0, "Scale should be positive");
let sum: i32 = quants.iter().map(|&q| q as i32).sum();
assert!(sum.abs() < 256, "Sum should be roughly balanced");
}
#[test]
fn test_q8k_superblock_dequantize_roundtrip() {
let mut values = [0.0f32; 256];
for i in 0..256 {
values[i] = (i as f32 - 127.5) * 0.01;
}
let block = Q8KSuperBlock::quantize(&values);
let dequantized = block.dequantize();
let mut max_error: f32 = 0.0;
for (orig, deq) in values.iter().zip(dequantized.iter()) {
max_error = max_error.max((orig - deq).abs());
}
assert!(
max_error < 0.1,
"Roundtrip error should be small, got {max_error}"
);
}
#[test]
fn test_q8k_superblock_all_negative() {
let values = [-1.0f32; 256];
let block = Q8KSuperBlock::quantize(&values);
assert!(
block.quants.iter().all(|&q| q == -127),
"All should be -127 for uniform negative"
);
}
#[test]
fn test_interleaved_q4k_empty() {
let data: Vec<u8> = vec![];
let result = InterleavedQ4K::from_q4k(&data);
assert!(result.is_ok());
let interleaved = result.expect("valid result");
assert_eq!(interleaved.num_super_blocks, 0);
assert_eq!(interleaved.num_values(), 0);
}
#[test]
fn test_interleaved_q4k_single_block() {
let mut data = vec![0u8; 144];
data[0] = 0x00;
data[1] = 0x3C;
data[2] = 0x00;
data[3] = 0x38;
let result = InterleavedQ4K::from_q4k(&data);
assert!(result.is_ok());
let interleaved = result.expect("valid result");
assert_eq!(interleaved.num_super_blocks, 1);
assert_eq!(interleaved.num_values(), 256);
assert_eq!(interleaved.d.len(), 1);
assert_eq!(interleaved.dmin.len(), 1);
assert_eq!(interleaved.scales.len(), 12);
assert_eq!(interleaved.qs.len(), 128);
}
#[test]
fn test_interleaved_q4k_invalid_length() {
let data = vec![0u8; 143];
let result = InterleavedQ4K::from_q4k(&data);
assert!(result.is_err());
if let Err(e) = result {
let err_str = format!("{e:?}");
assert!(
err_str.contains("143") || err_str.contains("144"),
"Error should mention the sizes"
);
}
}
#[test]
fn test_interleaved_q4k_multiple_blocks() {
let mut data = vec![0u8; 144 * 3];
data[0] = 0x00;
data[1] = 0x3C;
data[144] = 0x00;
data[145] = 0x40;
data[288] = 0x00;
data[289] = 0x38;
let result = InterleavedQ4K::from_q4k(&data);
assert!(result.is_ok());
let interleaved = result.expect("valid result");
assert_eq!(interleaved.num_super_blocks, 3);
assert_eq!(interleaved.num_values(), 768);
assert_eq!(interleaved.d.len(), 3);
assert_eq!(interleaved.dmin.len(), 3);
assert_eq!(interleaved.scales.len(), 36); assert_eq!(interleaved.qs.len(), 384); }
#[test]
fn test_interleaved_q4k_debug() {
let data = vec![0u8; 144];
let interleaved = InterleavedQ4K::from_q4k(&data).expect("valid data");
let debug_str = format!("{interleaved:?}");
assert!(debug_str.contains("InterleavedQ4K"));
assert!(debug_str.contains("num_super_blocks"));
}
#[test]
fn test_interleaved_q4k_clone() {
let data = vec![0u8; 144];
let original = InterleavedQ4K::from_q4k(&data).expect("valid data");
let cloned = original.clone();
assert_eq!(original.num_super_blocks, cloned.num_super_blocks);
assert_eq!(original.d, cloned.d);
assert_eq!(original.dmin, cloned.dmin);
assert_eq!(original.scales, cloned.scales);
assert_eq!(original.qs, cloned.qs);
}
#[test]
fn test_simd_backend_display_comprehensive() {
let backends = [
(SimdBackend::Avx2, "AVX2"),
(SimdBackend::Sse2, "SSE2"),
(SimdBackend::Neon, "NEON"),
(SimdBackend::Scalar, "Scalar"),
];
for (backend, expected) in backends {
let display = format!("{backend}");
assert_eq!(
display, expected,
"Display for {backend:?} should be {expected}"
);
}
}
#[test]
fn test_simd_backend_debug_all() {
let backends = [
SimdBackend::Avx2,
SimdBackend::Sse2,
SimdBackend::Neon,
SimdBackend::Scalar,
];
for backend in backends {
let debug_str = format!("{backend:?}");
assert!(
!debug_str.is_empty(),
"Debug output should not be empty for {backend:?}"
);
}
}
#[test]
fn test_dequant_stats_fields() {
let stats = DequantStats {
blocks_processed: 42,
bytes_processed: 1024,
simd_backend: SimdBackend::Avx2,
};
assert_eq!(stats.blocks_processed, 42);
assert_eq!(stats.bytes_processed, 1024);
assert_eq!(stats.simd_backend, SimdBackend::Avx2);
}
#[test]
fn test_dequant_stats_debug_comprehensive() {
let stats = DequantStats {
blocks_processed: 999,
bytes_processed: 12345,
simd_backend: SimdBackend::Neon,
};
let debug_str = format!("{stats:?}");
assert!(debug_str.contains("999"), "Should contain blocks count");
assert!(debug_str.contains("12345"), "Should contain bytes count");
assert!(debug_str.contains("Neon"), "Should contain backend name");
}
#[test]
fn test_detect_simd_backend_valid() {
let backend = detect_simd_backend();
let is_valid = matches!(
backend,
SimdBackend::Avx2 | SimdBackend::Sse2 | SimdBackend::Neon | SimdBackend::Scalar
);
assert!(is_valid, "Backend should be a valid variant");
}
include!("block_type_coverage.rs");