/home/noah/src/trueno/src/backends/q4k/dequant.rs
Line | Count | Source |
1 | | //! Q4_K dequantization to F32. |
2 | | //! |
3 | | //! Provides full dequantization of Q4_K compressed data for golden test comparison. |
4 | | |
5 | | use super::{parse_q4k_header, SUPER_BLOCK_BYTES, SUPER_BLOCK_SIZE}; |
6 | | |
7 | | /// Dequantize Q4_K data to F32 (for golden test comparison) |
8 | | /// |
9 | | /// This function fully dequantizes Q4K data to F32, matching the |
10 | | /// `dequantize_q4_k_to_f32` in aprender/src/format/converter.rs. |
11 | 0 | pub fn dequantize_q4k_to_f32(data: &[u8], num_elements: usize) -> Vec<f32> { |
12 | 0 | let num_blocks = (num_elements + SUPER_BLOCK_SIZE - 1) / SUPER_BLOCK_SIZE; |
13 | 0 | let mut result = vec![0.0f32; num_blocks * SUPER_BLOCK_SIZE]; |
14 | | |
15 | 0 | for sb_idx in 0..num_blocks { |
16 | 0 | let sb_start = sb_idx * SUPER_BLOCK_BYTES; |
17 | 0 | let out_start = sb_idx * SUPER_BLOCK_SIZE; |
18 | | |
19 | 0 | if sb_start + SUPER_BLOCK_BYTES > data.len() { |
20 | 0 | break; |
21 | 0 | } |
22 | | |
23 | 0 | let sb_data = &data[sb_start..sb_start + SUPER_BLOCK_BYTES]; |
24 | 0 | let (d, dmin, scales, mins) = parse_q4k_header(sb_data); |
25 | 0 | let qs = &sb_data[16..144]; |
26 | | |
27 | 0 | let mut ys_index = out_start; |
28 | | |
29 | 0 | for chunk in 0..4 { |
30 | 0 | let q = &qs[chunk * 32..(chunk + 1) * 32]; |
31 | | |
32 | 0 | let scale_idx_low = chunk * 2; |
33 | 0 | let scale_idx_high = chunk * 2 + 1; |
34 | | |
35 | 0 | let d1 = d * f32::from(scales[scale_idx_low]); |
36 | 0 | let dm1 = dmin * f32::from(mins[scale_idx_low]); |
37 | 0 | let d2 = d * f32::from(scales[scale_idx_high]); |
38 | 0 | let dm2 = dmin * f32::from(mins[scale_idx_high]); |
39 | | |
40 | | // First pass: 32 low nibbles |
41 | 0 | for &byte in q { |
42 | 0 | result[ys_index] = d1 * (byte & 0xF) as f32 - dm1; |
43 | 0 | ys_index += 1; |
44 | 0 | } |
45 | | |
46 | | // Second pass: 32 high nibbles |
47 | 0 | for &byte in q { |
48 | 0 | result[ys_index] = d2 * (byte >> 4) as f32 - dm2; |
49 | 0 | ys_index += 1; |
50 | 0 | } |
51 | | } |
52 | | } |
53 | | |
54 | 0 | result.truncate(num_elements); |
55 | 0 | result |
56 | 0 | } |