#[ensures(ret.as_ref().map_or(true, |v| v.len() == num_elements))]
pub(crate) fn dequantize_q6_k(data: &[u8], start: usize, num_elements: usize) -> Result<Vec<f32>> {
const SUPER_BLOCK_SIZE: usize = 256;
const SUPER_BLOCK_BYTES: usize = 210;
let num_blocks = num_elements.div_ceil(SUPER_BLOCK_SIZE);
let total_bytes = num_blocks * SUPER_BLOCK_BYTES;
if start + total_bytes > data.len() {
return Err(AprenderError::FormatError {
message: "Q6_K data exceeds file size".to_string(),
});
}
Ok(trueno_quant::dequantize_q6_k_to_f32(
&data[start..],
num_elements,
))
}
#[ensures(ret.as_ref().map_or(true, |v| v.len() == num_elements))]
pub fn dequantize_q4_1(data: &[u8], start: usize, num_elements: usize) -> Result<Vec<f32>> {
const BLOCK_SIZE: usize = 32;
const BLOCK_BYTES: usize = 2 + 2 + 16;
let num_blocks = num_elements.div_ceil(BLOCK_SIZE);
let total_bytes = num_blocks * BLOCK_BYTES;
if start + total_bytes > data.len() {
return Err(AprenderError::FormatError {
message: "Q4_1 data exceeds file size".to_string(),
});
}
let mut result = Vec::with_capacity(num_elements);
let mut offset = start;
for _ in 0..num_blocks {
let scale = safe_f16_scale(u16::from_le_bytes([data[offset], data[offset + 1]]));
let min = safe_f16_scale(u16::from_le_bytes([data[offset + 2], data[offset + 3]]));
offset += 4;
for i in 0..16 {
let byte = data[offset + i];
let v0 = f32::from(byte & 0x0F) * scale + min;
result.push(v0);
}
for i in 0..16 {
let byte = data[offset + i];
let v1 = f32::from(byte >> 4) * scale + min;
result.push(v1);
}
offset += 16;
}
result.truncate(num_elements);
Ok(result)
}
#[ensures(ret.as_ref().map_or(true, |v| v.len() == num_elements))]
pub(crate) fn dequantize_q2_k(data: &[u8], start: usize, num_elements: usize) -> Result<Vec<f32>> {
const SUPER_BLOCK_SIZE: usize = 256;
const SUPER_BLOCK_BYTES: usize = 2 + 2 + 16 + 64;
let num_blocks = num_elements.div_ceil(SUPER_BLOCK_SIZE);
let total_bytes = num_blocks * SUPER_BLOCK_BYTES;
if start + total_bytes > data.len() {
return Err(AprenderError::FormatError {
message: "Q2_K data exceeds file size".to_string(),
});
}
let mut result = Vec::with_capacity(num_elements);
let mut offset = start;
for _ in 0..num_blocks {
let scales_bytes = &data[offset..offset + 16];
offset += 16;
let qs = &data[offset..offset + 64];
offset += 64;
let d = safe_f16_scale(u16::from_le_bytes([data[offset], data[offset + 1]]));
let dmin = safe_f16_scale(u16::from_le_bytes([data[offset + 2], data[offset + 3]]));
offset += 4;
let mut is = 0usize;
for group in 0..2 {
let chunk = &qs[group * 32..group * 32 + 32];
let mut shift = 0u8;
for _ in 0..4 {
let sc = scales_bytes[is];
is += 1;
let dl = d * f32::from(sc & 0x0F);
let ml = dmin * f32::from(sc >> 4);
for &q in &chunk[0..16] {
result.push(dl * f32::from((q >> shift) & 0x03) - ml);
}
let sc = scales_bytes[is];
is += 1;
let dl = d * f32::from(sc & 0x0F);
let ml = dmin * f32::from(sc >> 4);
for &q in &chunk[16..32] {
result.push(dl * f32::from((q >> shift) & 0x03) - ml);
}
shift += 2;
}
}
}
result.truncate(num_elements);
Ok(result)
}
#[ensures(ret.as_ref().map_or(true, |v| v.len() == num_elements))]
pub(crate) fn dequantize_q3_k(data: &[u8], start: usize, num_elements: usize) -> Result<Vec<f32>> {
const SUPER_BLOCK_SIZE: usize = 256;
const SUPER_BLOCK_BYTES: usize = 32 + 64 + 12 + 2;
let num_blocks = num_elements.div_ceil(SUPER_BLOCK_SIZE);
let total_bytes = num_blocks * SUPER_BLOCK_BYTES;
if start + total_bytes > data.len() {
return Err(AprenderError::FormatError {
message: "Q3_K data exceeds file size".to_string(),
});
}
let mut result = Vec::with_capacity(num_elements);
let mut offset = start;
for _ in 0..num_blocks {
let hmask = &data[offset..offset + 32];
offset += 32;
let qs = &data[offset..offset + 64];
offset += 64;
let scales_bytes = &data[offset..offset + 12];
offset += 12;
let d = safe_f16_scale(u16::from_le_bytes([data[offset], data[offset + 1]]));
offset += 2;
const KMASK1: u32 = 0x0303_0303;
const KMASK2: u32 = 0x0f0f_0f0f;
let mut aux = [
u32::from_le_bytes([scales_bytes[0], scales_bytes[1], scales_bytes[2], scales_bytes[3]]),
u32::from_le_bytes([scales_bytes[4], scales_bytes[5], scales_bytes[6], scales_bytes[7]]),
u32::from_le_bytes([
scales_bytes[8],
scales_bytes[9],
scales_bytes[10],
scales_bytes[11],
]),
0u32,
];
let tmp = aux[2];
aux[2] = ((aux[0] >> 4) & KMASK2) | (((tmp >> 4) & KMASK1) << 4);
aux[3] = ((aux[1] >> 4) & KMASK2) | (((tmp >> 6) & KMASK1) << 4);
aux[0] = (aux[0] & KMASK2) | ((tmp & KMASK1) << 4);
aux[1] = (aux[1] & KMASK2) | (((tmp >> 2) & KMASK1) << 4);
let mut scales = [0i8; 16];
for (w, word) in aux.iter().enumerate() {
for (k, &b) in word.to_le_bytes().iter().enumerate() {
scales[w * 4 + k] = b as i8; }
}
let mut block_out = [0.0f32; 256];
let mut m: u32 = 1;
let mut is = 0usize;
for half in 0..2 {
let qs_half = &qs[half * 32..half * 32 + 32];
let out_half = half * 128;
let mut shift: u32 = 0;
for blk in 0..4 {
let out_blk = out_half + blk * 32;
for scale_index in 0..2 {
let dl = d * (f32::from(scales[is]) - 32.0);
let out_grp = out_blk + scale_index * 16;
for i in 0..16 {
let idx = i + 16 * scale_index;
let low = ((qs_half[idx] >> shift) & 3) as i8;
let high = if u32::from(hmask[idx]) & m == 0 { 4i8 } else { 0i8 };
block_out[out_grp + i] = dl * f32::from(low - high);
}
is += 1;
}
shift += 2;
m <<= 1;
}
}
result.extend_from_slice(&block_out);
}
result.truncate(num_elements);
Ok(result)
}