use half::f16;
use rayon::prelude::*;
pub const QK8_0: usize = 32;
pub const BLOCK_BYTES: usize = 2 + QK8_0;
pub fn quantize(src: &[f32], n_per_row: usize, _imatrix: Option<&[f32]>) -> Vec<u8> {
assert!(
n_per_row % QK8_0 == 0,
"n_per_row {} not multiple of QK8_0 {}",
n_per_row,
QK8_0
);
assert!(
src.len() % n_per_row == 0,
"src len {} not multiple of n_per_row {}",
src.len(),
n_per_row
);
let total_blocks = src.len() / QK8_0;
let mut out = vec![0u8; total_blocks * BLOCK_BYTES];
out.par_chunks_exact_mut(BLOCK_BYTES)
.enumerate()
.for_each(|(block_idx, dst)| {
let block = &src[block_idx * QK8_0..(block_idx + 1) * QK8_0];
let mut amax = 0.0f32;
for &v in block {
let a = v.abs();
if a > amax {
amax = a;
}
}
let d = amax / 127.0;
let id = if d != 0.0 { 1.0 / d } else { 0.0 };
let d_f16 = f16::from_f32(d);
dst[0..2].copy_from_slice(&d_f16.to_le_bytes());
for (i, &v) in block.iter().enumerate() {
let q = (v * id).round() as i8;
dst[2 + i] = q as u8;
}
});
out
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use std::path::PathBuf;
fn fixture_path(name: &str) -> PathBuf {
let manifest =
std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set by cargo test");
PathBuf::from(manifest)
.join("tests/fixtures/ggml_quants")
.join(name)
}
fn read_f32s(name: &str) -> Vec<f32> {
let bytes = fs::read(fixture_path(name)).expect("read fixture");
assert!(
bytes.len() % 4 == 0,
"fixture {} not a multiple of 4 bytes",
name
);
let mut out = Vec::with_capacity(bytes.len() / 4);
for chunk in bytes.chunks_exact(4) {
out.push(f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]));
}
out
}
fn read_bytes(name: &str) -> Vec<u8> {
fs::read(fixture_path(name)).expect("read fixture")
}
#[test]
fn byte_cmp_noim() {
let input = read_f32s("q8_0_64_noim_input.bin");
let expected = read_bytes("q8_0_64_noim_expected.bin");
let got = quantize(&input, 64, None);
assert_eq!(got.len(), expected.len(), "Q8_0 noim length mismatch");
assert_eq!(got, expected, "Q8_0 noim byte-cmp failed");
}
#[test]
fn byte_cmp_im() {
let input = read_f32s("q8_0_64_im_input.bin");
let expected = read_bytes("q8_0_64_im_expected.bin");
let imatrix = vec![1.0f32; 64];
let got = quantize(&input, 64, Some(&imatrix));
assert_eq!(
got, expected,
"Q8_0 im byte-cmp failed (Q8_0 must ignore imatrix per ggml-quants.c:2220)"
);
}
}