## Coverage Report

#### Created: 2026-01-25 15:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /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
    }