pub const BLOCK_SIZE: usize = 256;
pub const BLOCK_BYTES: usize = 210;
pub fn dequantize(bytes: &[u8]) -> Vec<f32> {
assert!(
bytes.len() % BLOCK_BYTES == 0,
"Q6_K: byte count {} not multiple of {}",
bytes.len(),
BLOCK_BYTES
);
let n_blocks = bytes.len() / BLOCK_BYTES;
let mut out = vec![0f32; n_blocks * BLOCK_SIZE];
for blk in 0..n_blocks {
let base = blk * BLOCK_BYTES;
let ql = &bytes[base..base + 128];
let qh = &bytes[base + 128..base + 192];
let scales = &bytes[base + 192..base + 208];
let d_bits = u16::from_le_bytes([bytes[base + 208], bytes[base + 209]]);
let d = half::f16::from_bits(d_bits).to_f32();
let y = &mut out[blk * BLOCK_SIZE..(blk + 1) * BLOCK_SIZE];
for half in 0..2 {
let ql_off = half * 64;
let qh_off = half * 32;
let sc_off = half * 8;
let y_off = half * 128;
for l in 0..32 {
let is = l / 16;
let qh_byte = qh[qh_off + l];
let q1 = ((ql[ql_off + l] & 0x0F) as i32
| (((qh_byte & 0x03) as i32) << 4)) - 32;
let q2 = ((ql[ql_off + l + 32] & 0x0F) as i32
| (((qh_byte & 0x0C) as i32) << 2)) - 32;
let q3 = ((ql[ql_off + l] >> 4) as i32
| (((qh_byte & 0x30) as i32) << 0)) - 32;
let q4 = ((ql[ql_off + l + 32] >> 4) as i32
| (((qh_byte & 0xC0) as i32) >> 2)) - 32;
let s1 = scales[sc_off + is + 0] as i8 as f32;
let s2 = scales[sc_off + is + 2] as i8 as f32;
let s3 = scales[sc_off + is + 4] as i8 as f32;
let s4 = scales[sc_off + is + 6] as i8 as f32;
y[y_off + l + 0] = d * s1 * q1 as f32;
y[y_off + l + 32] = d * s2 * q2 as f32;
y[y_off + l + 64] = d * s3 * q3 as f32;
y[y_off + l + 96] = d * s4 * q4 as f32;
}
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zero_block_gives_zero_when_d_zero() {
let block = vec![0u8; BLOCK_BYTES];
let out = dequantize(&block);
assert_eq!(out.len(), BLOCK_SIZE);
for v in out {
assert_eq!(v, 0.0);
}
}
#[test]
fn d_one_with_zero_q_gives_negative_32_times_scale() {
let mut block = vec![0u8; BLOCK_BYTES];
let d_bits = half::f16::from_f32(1.0).to_bits();
block[208] = (d_bits & 0xFF) as u8;
block[209] = (d_bits >> 8) as u8;
for i in 192..208 {
block[i] = 1;
}
let out = dequantize(&block);
for v in out {
assert!((v - (-32.0)).abs() < 1e-6, "got {v}");
}
}
#[test]
fn byte_count_validation() {
let bytes = vec![0u8; BLOCK_BYTES + 1];
assert!(std::panic::catch_unwind(|| dequantize(&bytes)).is_err());
}
}