use crate::quantize::{
dequantize_q8_blocks, detect_simd_backend, fused_q4_0_q8_0_parallel_matvec,
fused_q4_0_q8_0_parallel_matvec_into, fused_q8_0_q8_0_parallel_matvec,
quantize_activations_q8k_into, quantize_to_q8_blocks, DequantStats, InterleavedQ4K,
Q8KSuperBlock, Q8_0Block, SimdBackend, BLOCK_SIZE, QK_K,
};
use crate::quantize::{
extract_scale_min, fused_q4_0_q8_0_dot_scalar,
fused_q4_0_q8_0_dot_simd, fused_q8_0_q8_0_dot_scalar,
};
#[test]
fn test_f16_to_f32_lut_special_values() {
let zero_data = vec![0u8; 144];
let interleaved = InterleavedQ4K::from_q4k(&zero_data).expect("valid");
assert_eq!(interleaved.d[0], 0.0, "f16 zero should convert to f32 zero");
let mut one_data = vec![0u8; 144];
one_data[0..2].copy_from_slice(&0x3C00u16.to_le_bytes());
let interleaved = InterleavedQ4K::from_q4k(&one_data).expect("valid");
assert!(
(interleaved.d[0] - 1.0).abs() < 1e-6,
"f16 1.0 should convert correctly"
);
let mut neg_one_data = vec![0u8; 144];
neg_one_data[0..2].copy_from_slice(&0xBC00u16.to_le_bytes());
let interleaved = InterleavedQ4K::from_q4k(&neg_one_data).expect("valid");
assert!(
(interleaved.d[0] + 1.0).abs() < 1e-6,
"f16 -1.0 should convert correctly"
);
}
#[test]
fn test_f16_to_f32_lut_half_precision() {
let mut data = vec![0u8; 144];
data[0..2].copy_from_slice(&0x3800u16.to_le_bytes());
let interleaved = InterleavedQ4K::from_q4k(&data).expect("valid");
assert!(
(interleaved.d[0] - 0.5).abs() < 1e-6,
"f16 0.5 should convert correctly"
);
data[0..2].copy_from_slice(&0x4000u16.to_le_bytes());
let interleaved = InterleavedQ4K::from_q4k(&data).expect("valid");
assert!(
(interleaved.d[0] - 2.0).abs() < 1e-6,
"f16 2.0 should convert correctly"
);
}
#[test]
fn test_f16_to_f32_lut_subnormal_f16() {
let mut data = vec![0u8; 144];
data[0..2].copy_from_slice(&0x0001u16.to_le_bytes());
let interleaved = InterleavedQ4K::from_q4k(&data).expect("valid");
assert!(interleaved.d[0] > 0.0, "Subnormal f16 should be positive");
assert!(
interleaved.d[0] < 1e-6,
"Subnormal f16 should be very small"
);
}
#[test]
fn test_f16_to_f32_lut_infinity() {
let mut data = vec![0u8; 144];
data[0..2].copy_from_slice(&0x7C00u16.to_le_bytes());
let interleaved = InterleavedQ4K::from_q4k(&data).expect("valid");
assert!(interleaved.d[0].is_infinite() && interleaved.d[0] > 0.0);
data[0..2].copy_from_slice(&0xFC00u16.to_le_bytes());
let interleaved = InterleavedQ4K::from_q4k(&data).expect("valid");
assert!(interleaved.d[0].is_infinite() && interleaved.d[0] < 0.0);
}
#[test]
fn test_f16_to_f32_lut_nan() {
let mut data = vec![0u8; 144];
data[0..2].copy_from_slice(&0x7E00u16.to_le_bytes());
let interleaved = InterleavedQ4K::from_q4k(&data).expect("valid");
assert!(
interleaved.d[0].is_nan(),
"f16 NaN should convert to f32 NaN"
);
}
#[test]
fn test_f16_to_f32_lut_max_f16() {
let mut data = vec![0u8; 144];
data[0..2].copy_from_slice(&0x7BFFu16.to_le_bytes());
let interleaved = InterleavedQ4K::from_q4k(&data).expect("valid");
assert!(
(interleaved.d[0] - 65504.0).abs() < 1.0,
"Max f16 should be ~65504"
);
}
#[test]
fn test_q8k_superblock_dequantize_basic() {
let values = [1.0f32; 256];
let block = Q8KSuperBlock::quantize(&values);
let dequant = block.dequantize();
for (i, &v) in dequant.iter().enumerate() {
assert!(
(v - 1.0).abs() < 0.1,
"Index {}: expected ~1.0, got {}",
i,
v
);
}
}
#[test]
fn test_q8k_superblock_dequantize_zeros() {
let values = [0.0f32; 256];
let block = Q8KSuperBlock::quantize(&values);
let dequant = block.dequantize();
for (i, &v) in dequant.iter().enumerate() {
assert!(v.abs() < 1e-6, "Index {}: expected 0, got {}", i, v);
}
}
#[test]
fn test_q8k_superblock_dequantize_alternating() {
let mut values = [0.0f32; 256];
for i in 0..256 {
values[i] = if i % 2 == 0 { 10.0 } else { -10.0 };
}
let block = Q8KSuperBlock::quantize(&values);
let dequant = block.dequantize();
for (i, &v) in dequant.iter().enumerate() {
if i % 2 == 0 {
assert!(v > 0.0, "Even index {} should be positive: {}", i, v);
} else {
assert!(v < 0.0, "Odd index {} should be negative: {}", i, v);
}
}
}
#[test]
fn test_q8k_superblock_dequantize_varying() {
let values: [f32; 256] = std::array::from_fn(|i| (i as f32 - 128.0) * 0.5);
let block = Q8KSuperBlock::quantize(&values);
let dequant = block.dequantize();
for i in 1..256 {
assert!(
dequant[i] >= dequant[i - 1] - 1.0,
"Values should be roughly ascending at index {}",
i
);
}
}
#[test]
fn test_q8k_superblock_dequantize_extreme_values() {
let mut values = [0.0f32; 256];
values[0] = 1000.0;
values[255] = -1000.0;
let block = Q8KSuperBlock::quantize(&values);
let dequant = block.dequantize();
assert!(dequant[0] > 500.0, "First value should be large positive");
assert!(dequant[255] < -500.0, "Last value should be large negative");
}
#[test]
fn test_q8_0block_relative_error_near_zero_max() {
let values = [1e-12f32; 32]; let block = Q8_0Block::quantize(&values);
let error = block.relative_error(&values);
assert_eq!(
error, 0.0,
"Relative error should be 0 for near-zero values"
);
}
#[test]
fn test_q8_0block_relative_error_exactly_zero() {
let values = [0.0f32; 32];
let block = Q8_0Block::quantize(&values);
let error = block.relative_error(&values);
assert_eq!(error, 0.0, "Relative error should be 0 for zero values");
}
#[test]
fn test_q8_0block_relative_error_mixed_small() {
let mut values = [0.0f32; 32];
values[0] = 1e-11; let block = Q8_0Block::quantize(&values);
let error = block.relative_error(&values);
assert_eq!(error, 0.0);
}
#[test]
fn test_q8_0block_relative_error_normal() {
let values: [f32; 32] = std::array::from_fn(|i| (i as f32 - 16.0) * 0.1);
let block = Q8_0Block::quantize(&values);
let error = block.relative_error(&values);
assert!(
error > 0.0,
"Normal values should have some quantization error"
);
assert!(error < 0.1, "Relative error should be small: {}", error);
}
#[test]
fn test_q8_0block_quantization_error_basic() {
let values = [5.0f32; 32];
let block = Q8_0Block::quantize(&values);
let error = block.quantization_error(&values);
assert!(error < 0.1, "Quantization error should be small: {}", error);
}
#[test]
fn test_simd_backend_display_avx2() {
let backend = SimdBackend::Avx2;
assert_eq!(format!("{}", backend), "AVX2");
}
#[test]
fn test_simd_backend_display_sse2() {
let backend = SimdBackend::Sse2;
assert_eq!(format!("{}", backend), "SSE2");
}
#[test]
fn test_simd_backend_display_neon() {
let backend = SimdBackend::Neon;
assert_eq!(format!("{}", backend), "NEON");
}
#[test]
fn test_simd_backend_display_scalar() {
let backend = SimdBackend::Scalar;
assert_eq!(format!("{}", backend), "Scalar");
}
#[test]
fn test_simd_backend_default() {
let backend = SimdBackend::default();
assert_eq!(backend, SimdBackend::Scalar);
}
#[test]
fn test_simd_backend_equality() {
assert_eq!(SimdBackend::Avx2, SimdBackend::Avx2);
assert_ne!(SimdBackend::Avx2, SimdBackend::Sse2);
assert_ne!(SimdBackend::Neon, SimdBackend::Scalar);
}
#[test]
fn test_simd_backend_clone() {
let backend = SimdBackend::Avx2;
let cloned = backend;
assert_eq!(backend, cloned);
}
#[test]
fn test_simd_backend_copy() {
let backend = SimdBackend::Neon;
let copied: SimdBackend = backend;
assert_eq!(backend, copied);
}
#[test]
fn test_dequant_stats_default() {
let stats = DequantStats::default();
assert_eq!(stats.blocks_processed, 0);
assert_eq!(stats.bytes_processed, 0);
assert_eq!(stats.simd_backend, SimdBackend::Scalar);
}
#[test]
fn test_dequant_stats_clone() {
let mut stats = DequantStats::default();
stats.blocks_processed = 100;
stats.bytes_processed = 3200;
stats.simd_backend = SimdBackend::Avx2;
let cloned = stats.clone();
assert_eq!(cloned.blocks_processed, 100);
assert_eq!(cloned.bytes_processed, 3200);
assert_eq!(cloned.simd_backend, SimdBackend::Avx2);
}
#[test]
fn test_dequant_stats_debug() {
let stats = DequantStats {
blocks_processed: 42,
bytes_processed: 1344,
simd_backend: SimdBackend::Sse2,
};
let debug_str = format!("{:?}", stats);
assert!(debug_str.contains("42"));
assert!(debug_str.contains("1344"));
assert!(debug_str.contains("Sse2"));
}
#[test]
fn test_detect_simd_backend_runs() {
let backend = detect_simd_backend();
match backend {
SimdBackend::Avx2 | SimdBackend::Sse2 | SimdBackend::Neon | SimdBackend::Scalar => {},
}
}
#[test]
fn test_detect_simd_backend_consistent() {
let backend1 = detect_simd_backend();
let backend2 = detect_simd_backend();
assert_eq!(backend1, backend2);
}
#[test]
fn test_extract_scale_min_block_5() {
let mut scales = [0u8; 12];
scales[1] = 0b11_000000; scales[5] = 0b10_000000; scales[9] = 0b0011_0101;
let (s, m) = extract_scale_min(&scales, 5);
assert_eq!(s, 53.0, "Block 5 scale");
assert_eq!(m, 35.0, "Block 5 min");
}
#[test]
fn test_extract_scale_min_block_6() {
let mut scales = [0u8; 12];
scales[2] = 0b01_000000; scales[6] = 0b11_000000; scales[10] = 0b1001_0010;
let (s, m) = extract_scale_min(&scales, 6);
assert_eq!(s, 18.0, "Block 6 scale");
assert_eq!(m, 57.0, "Block 6 min");
}
#[test]
fn test_extract_scale_min_block_7() {
let mut scales = [0u8; 12];
scales[3] = 0b10_000000; scales[7] = 0b01_000000; scales[11] = 0b0100_1111;
let (s, m) = extract_scale_min(&scales, 7);
assert_eq!(s, 47.0, "Block 7 scale");
assert_eq!(m, 20.0, "Block 7 min");
}
include!("extract_scale_02.rs");
include!("quantize_activations_04.rs");