Skip to main content

logicaffeine_compile/model/
quant.rs

1//! The GGUF weight formats, and their dequantization to `f32`.
2//!
3//! Each format is a run of fixed-size blocks; a block holds a fixed count of weights and the scales that turn its
4//! packed integers back into numbers. The dequantizers here follow ggml's own reference definitions
5//! (`ggml/src/ggml-quants.c`, `dequantize_row_*`) operation for operation, in the order those definitions write
6//! them, so their output is the reference's to the bit (`model_quant_lock` compiles the reference and compares).
7
8/// A ggml tensor type this crate reads, by its GGUF type id.
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10pub enum GgmlType {
11    F32,
12    F16,
13    Bf16,
14    Q4_0,
15    Q4_1,
16    Q5_0,
17    Q5_1,
18    Q8_0,
19    Q2K,
20    Q3K,
21    Q4K,
22    Q5K,
23    Q6K,
24    Iq4Nl,
25    Iq4Xs,
26    Mxfp4,
27}
28
29/// Weights per super-block of the K-quant formats.
30const QK_K: usize = 256;
31
32impl GgmlType {
33    /// The type for a GGUF type id, or the id back when this crate does not read that format.
34    pub fn from_id(id: u32) -> Result<GgmlType, u32> {
35        Ok(match id {
36            0 => GgmlType::F32,
37            1 => GgmlType::F16,
38            2 => GgmlType::Q4_0,
39            3 => GgmlType::Q4_1,
40            6 => GgmlType::Q5_0,
41            7 => GgmlType::Q5_1,
42            8 => GgmlType::Q8_0,
43            10 => GgmlType::Q2K,
44            11 => GgmlType::Q3K,
45            12 => GgmlType::Q4K,
46            13 => GgmlType::Q5K,
47            14 => GgmlType::Q6K,
48            20 => GgmlType::Iq4Nl,
49            23 => GgmlType::Iq4Xs,
50            30 => GgmlType::Bf16,
51            39 => GgmlType::Mxfp4,
52            other => return Err(other),
53        })
54    }
55
56    /// The GGUF type id.
57    pub fn id(self) -> u32 {
58        match self {
59            GgmlType::F32 => 0,
60            GgmlType::F16 => 1,
61            GgmlType::Q4_0 => 2,
62            GgmlType::Q4_1 => 3,
63            GgmlType::Q5_0 => 6,
64            GgmlType::Q5_1 => 7,
65            GgmlType::Q8_0 => 8,
66            GgmlType::Q2K => 10,
67            GgmlType::Q3K => 11,
68            GgmlType::Q4K => 12,
69            GgmlType::Q5K => 13,
70            GgmlType::Q6K => 14,
71            GgmlType::Iq4Nl => 20,
72            GgmlType::Iq4Xs => 23,
73            GgmlType::Bf16 => 30,
74            GgmlType::Mxfp4 => 39,
75        }
76    }
77
78    /// The name ggml gives the type.
79    pub fn name(self) -> &'static str {
80        match self {
81            GgmlType::F32 => "f32",
82            GgmlType::F16 => "f16",
83            GgmlType::Bf16 => "bf16",
84            GgmlType::Q4_0 => "q4_0",
85            GgmlType::Q4_1 => "q4_1",
86            GgmlType::Q5_0 => "q5_0",
87            GgmlType::Q5_1 => "q5_1",
88            GgmlType::Q8_0 => "q8_0",
89            GgmlType::Q2K => "q2_K",
90            GgmlType::Q3K => "q3_K",
91            GgmlType::Q4K => "q4_K",
92            GgmlType::Q5K => "q5_K",
93            GgmlType::Q6K => "q6_K",
94            GgmlType::Iq4Nl => "iq4_nl",
95            GgmlType::Iq4Xs => "iq4_xs",
96            GgmlType::Mxfp4 => "mxfp4",
97        }
98    }
99
100    /// Weights per block.
101    pub fn block_len(self) -> usize {
102        match self {
103            GgmlType::F32 | GgmlType::F16 | GgmlType::Bf16 => 1,
104            GgmlType::Q4_0
105            | GgmlType::Q4_1
106            | GgmlType::Q5_0
107            | GgmlType::Q5_1
108            | GgmlType::Q8_0
109            | GgmlType::Iq4Nl
110            | GgmlType::Mxfp4 => 32,
111            GgmlType::Q2K | GgmlType::Q3K | GgmlType::Q4K | GgmlType::Q5K | GgmlType::Q6K | GgmlType::Iq4Xs => QK_K,
112        }
113    }
114
115    /// Bytes per block.
116    pub fn block_bytes(self) -> usize {
117        match self {
118            GgmlType::F32 => 4,
119            GgmlType::F16 | GgmlType::Bf16 => 2,
120            GgmlType::Q4_0 => 2 + 16,
121            GgmlType::Q4_1 => 2 + 2 + 16,
122            GgmlType::Q5_0 => 2 + 4 + 16,
123            GgmlType::Q5_1 => 2 + 2 + 4 + 16,
124            GgmlType::Q8_0 => 2 + 32,
125            GgmlType::Mxfp4 => 1 + 16,
126            GgmlType::Q2K => QK_K / 16 + QK_K / 4 + 2 + 2,
127            GgmlType::Q3K => QK_K / 8 + QK_K / 4 + 12 + 2,
128            GgmlType::Q4K => 2 + 2 + 12 + QK_K / 2,
129            GgmlType::Q5K => 2 + 2 + 12 + QK_K / 8 + QK_K / 2,
130            GgmlType::Q6K => QK_K / 2 + QK_K / 4 + QK_K / 16 + 2,
131            GgmlType::Iq4Nl => 2 + 16,
132            GgmlType::Iq4Xs => 2 + 2 + QK_K / 64 + QK_K / 2,
133        }
134    }
135
136    /// Bytes holding `n` weights (`n` a whole number of blocks).
137    pub fn bytes_for(self, n: usize) -> usize {
138        assert!(
139            n % self.block_len() == 0,
140            "{n} weights are not a whole number of {} blocks of {}",
141            self.name(),
142            self.block_len()
143        );
144        n / self.block_len() * self.block_bytes()
145    }
146
147    /// Dequantize `bytes` (whole blocks) to `f32`, appending to `out`.
148    pub fn dequantize(self, bytes: &[u8], out: &mut Vec<f32>) {
149        let bb = self.block_bytes();
150        assert!(
151            bytes.len() % bb == 0,
152            "{} bytes are not a whole number of {} blocks",
153            bytes.len(),
154            self.name()
155        );
156        out.reserve(bytes.len() / bb * self.block_len());
157        for b in bytes.chunks_exact(bb) {
158            match self {
159                GgmlType::F32 => out.push(f32::from_le_bytes([b[0], b[1], b[2], b[3]])),
160                GgmlType::F16 => out.push(f16_to_f32(u16::from_le_bytes([b[0], b[1]]))),
161                GgmlType::Bf16 => out.push(bf16_to_f32(u16::from_le_bytes([b[0], b[1]]))),
162                GgmlType::Q4_0 => q4_0(b, out),
163                GgmlType::Q4_1 => q4_1(b, out),
164                GgmlType::Q5_0 => q5_0(b, out),
165                GgmlType::Q5_1 => q5_1(b, out),
166                GgmlType::Q8_0 => q8_0(b, out),
167                GgmlType::Mxfp4 => mxfp4(b, out),
168                GgmlType::Q2K => q2_k(b, out),
169                GgmlType::Q3K => q3_k(b, out),
170                GgmlType::Q4K => q4_k(b, out),
171                GgmlType::Q5K => q5_k(b, out),
172                GgmlType::Q6K => q6_k(b, out),
173                GgmlType::Iq4Nl => iq4_nl(b, out),
174                GgmlType::Iq4Xs => iq4_xs(b, out),
175            }
176        }
177    }
178}
179
180/// `x` rounded to binary16, to nearest with ties to even: subnormals kept, past the largest finite value infinite, a
181/// NaN quiet.
182pub fn f32_to_f16(x: f32) -> u16 {
183    let b = x.to_bits();
184    let sign = ((b >> 16) & 0x8000) as u16;
185    let exp = ((b >> 23) & 0xff) as i32;
186    let mant = b & 0x7f_ffff;
187    if exp == 0xff {
188        return sign | 0x7c00 | if mant != 0 { 0x0200 } else { 0 };
189    }
190    if exp == 0 {
191        return sign;
192    }
193    let e = exp - 127;
194    if e > 15 {
195        return sign | 0x7c00;
196    }
197    if e >= -14 {
198        let (m, rem) = (mant >> 13, mant & 0x1fff);
199        let h = (((e + 15) as u32) << 10) | m;
200        let up = rem > 0x1000 || (rem == 0x1000 && m & 1 == 1);
201        return sign | (h + u32::from(up)) as u16;
202    }
203    // A subnormal counts units of 2^-24: the 24-bit significand shifted right by -(e + 1).
204    let s = (-(e + 1)) as u32;
205    if s > 24 {
206        return sign;
207    }
208    let sig = 0x80_0000 | mant;
209    let (n, rem, half) = (sig >> s, sig & ((1u32 << s) - 1), 1u32 << (s - 1));
210    let up = rem > half || (rem == half && n & 1 == 1);
211    sign | (n + u32::from(up)) as u16
212}
213
214/// IEEE-754 binary16 → binary32, exactly (subnormals included).
215pub fn f16_to_f32(h: u16) -> f32 {
216    let sign = ((h >> 15) & 1) as u32;
217    let exp = ((h >> 10) & 0x1f) as u32;
218    let mant = (h & 0x3ff) as u32;
219    let bits = match (exp, mant) {
220        (0, 0) => sign << 31,
221        (0, _) => {
222            let mut e: i32 = -1;
223            let mut m = mant;
224            while m & 0x400 == 0 {
225                m <<= 1;
226                e -= 1;
227            }
228            (sign << 31) | (((e + 1 + 127 - 14) as u32) << 23) | ((m & 0x3ff) << 13)
229        }
230        (0x1f, 0) => (sign << 31) | 0x7f80_0000,
231        (0x1f, _) => (sign << 31) | 0x7fc0_0000 | (mant << 13),
232        _ => (sign << 31) | ((exp + 127 - 15) << 23) | (mant << 13),
233    };
234    f32::from_bits(bits)
235}
236
237/// bfloat16 → binary32: the high half of the word.
238pub fn bf16_to_f32(h: u16) -> f32 {
239    f32::from_bits((h as u32) << 16)
240}
241
242/// `x` rounded to bfloat16, to nearest with ties to even; a NaN stays a quiet NaN.
243pub fn f32_to_bf16(x: f32) -> u16 {
244    let b = x.to_bits();
245    if x.is_nan() {
246        return ((b >> 16) | 0x0040) as u16;
247    }
248    ((b + 0x7fff + ((b >> 16) & 1)) >> 16) as u16
249}
250
251/// An `e4m3fn` float's value as `torch` widens it: bias 7, no infinities, `S.1111.111` a NaN keeping its sign and
252/// mantissa bits.
253pub fn e4m3fn_to_f32(b: u8) -> f32 {
254    let sign = u32::from(b >> 7) << 31;
255    let (e, m) = (u32::from((b >> 3) & 0xf), u32::from(b & 7));
256    if e == 0xf && m == 7 {
257        return f32::from_bits(sign | 0x7f80_0000 | m << 20);
258    }
259    let magnitude = if e == 0 { m as f32 / 8.0 * 2f32.powi(-6) } else { (1.0 + m as f32 / 8.0) * 2f32.powi(e as i32 - 7) };
260    f32::from_bits(sign | magnitude.to_bits())
261}
262
263/// An `e5m2` float's value: the high byte of a binary16.
264pub fn e5m2_to_f32(b: u8) -> f32 {
265    f16_to_f32(u16::from(b) << 8)
266}
267
268/// The scale of a scaled-float tensor (an FP8 checkpoint's `weight_scale_inv`) broadcast over the weight's elements, as
269/// the Hugging Face converter's `dequant_simple` broadcasts it before `weight.float() * scale`: with a block size, each
270/// of the scale's trailing axes repeated a block's length and cropped to the weight's; then axes of length 1 appended
271/// until the scale has the weight's rank, every axis either 1 (broadcast) or the weight's length.
272#[derive(Clone, Debug)]
273pub struct ScaleGrid {
274    weight: Vec<usize>,
275    values: Vec<f32>,
276    /// Per weight axis: the divisor of its index and the stored scale's stride on it, or `None` where it broadcasts.
277    axes: Vec<Option<(usize, usize)>>,
278}
279
280impl ScaleGrid {
281    /// The grid of a scale of axes `dims` and row-major `values` over a weight of axes `weight`, its trailing axes in
282    /// blocks of `block` where one is given. A shape `dequant_simple` would not broadcast is refused.
283    pub fn new(weight: &[usize], dims: &[usize], values: Vec<f32>, block: Option<&[usize]>) -> Result<ScaleGrid, String> {
284        let count: usize = dims.iter().product();
285        if values.len() != count {
286            return Err(format!("a scale of axes {dims:?} holds {count} values, not {}", values.len()));
287        }
288        if dims.len() > weight.len() {
289            return Err(format!("a scale of axes {dims:?} has more axes than its weight's {weight:?}"));
290        }
291        let repeat: Vec<usize> = match block {
292            None => vec![1; dims.len()],
293            Some(b) if b.len() <= dims.len() && b.iter().all(|&x| x > 0) => {
294                let offset = dims.len() - b.len();
295                (0..dims.len()).map(|d| if d < offset { 1 } else { b[d - offset] }).collect()
296            }
297            Some(b) => return Err(format!("a block of {b:?} over a scale of axes {dims:?}")),
298        };
299        let mut stride = vec![1usize; dims.len()];
300        for d in (0..dims.len().saturating_sub(1)).rev() {
301            stride[d] = stride[d + 1] * dims[d + 1];
302        }
303        let mut axes = Vec::with_capacity(weight.len());
304        for (d, &w) in weight.iter().enumerate() {
305            let expanded = if d < dims.len() { (dims[d] * repeat[d]).min(w) } else { 1 };
306            axes.push(if expanded == w && w != 1 {
307                Some((repeat[d], stride[d]))
308            } else if expanded == 1 {
309                None
310            } else {
311                return Err(format!(
312                    "a scale of axes {dims:?} in blocks of {block:?} spans {expanded} on axis {d} of a weight of {weight:?}"
313                ));
314            });
315        }
316        Ok(ScaleGrid { weight: weight.to_vec(), values, axes })
317    }
318
319    /// `values`, the weight's elements from `first` on in row-major order widened to f32, each multiplied by its scale.
320    pub fn apply(&self, first: usize, values: &mut [f32]) {
321        let mut index = vec![0usize; self.weight.len()];
322        let mut rest = first;
323        for d in (0..self.weight.len()).rev() {
324            index[d] = rest % self.weight[d].max(1);
325            rest /= self.weight[d].max(1);
326        }
327        for v in values.iter_mut() {
328            let at: usize = self.axes.iter().zip(&index).map(|(a, &i)| a.map_or(0, |(div, stride)| i / div * stride)).sum();
329            *v *= self.values[at];
330            for d in (0..index.len()).rev() {
331                index[d] += 1;
332                if index[d] < self.weight[d] {
333                    break;
334                }
335                index[d] = 0;
336            }
337        }
338    }
339}
340
341fn half(b: &[u8], at: usize) -> f32 {
342    f16_to_f32(u16::from_le_bytes([b[at], b[at + 1]]))
343}
344
345fn q4_0(b: &[u8], y: &mut Vec<f32>) {
346    let d = half(b, 0);
347    let qs = &b[2..18];
348    let (lo, hi): (Vec<f32>, Vec<f32>) = qs
349        .iter()
350        .map(|&q| (((q & 0x0f) as i32 - 8) as f32 * d, ((q >> 4) as i32 - 8) as f32 * d))
351        .unzip();
352    y.extend(lo);
353    y.extend(hi);
354}
355
356fn q4_1(b: &[u8], y: &mut Vec<f32>) {
357    let (d, m) = (half(b, 0), half(b, 2));
358    let qs = &b[4..20];
359    y.extend(qs.iter().map(|&q| (q & 0x0f) as f32 * d + m));
360    y.extend(qs.iter().map(|&q| (q >> 4) as f32 * d + m));
361}
362
363fn q5_0(b: &[u8], y: &mut Vec<f32>) {
364    let d = half(b, 0);
365    let qh = u32::from_le_bytes([b[2], b[3], b[4], b[5]]);
366    let qs = &b[6..22];
367    let x = |j: usize, q: u8| -> (f32, f32) {
368        let xh0 = (((qh >> j) << 4) & 0x10) as u8;
369        let xh1 = ((qh >> (j + 12)) & 0x10) as u8;
370        (
371            (((q & 0x0f) | xh0) as i32 - 16) as f32 * d,
372            (((q >> 4) | xh1) as i32 - 16) as f32 * d,
373        )
374    };
375    let (lo, hi): (Vec<f32>, Vec<f32>) = qs.iter().enumerate().map(|(j, &q)| x(j, q)).unzip();
376    y.extend(lo);
377    y.extend(hi);
378}
379
380fn q5_1(b: &[u8], y: &mut Vec<f32>) {
381    let (d, m) = (half(b, 0), half(b, 2));
382    let qh = u32::from_le_bytes([b[4], b[5], b[6], b[7]]);
383    let qs = &b[8..24];
384    let x = |j: usize, q: u8| -> (f32, f32) {
385        let xh0 = (((qh >> j) << 4) & 0x10) as u8;
386        let xh1 = ((qh >> (j + 12)) & 0x10) as u8;
387        (
388            ((q & 0x0f) | xh0) as f32 * d + m,
389            ((q >> 4) | xh1) as f32 * d + m,
390        )
391    };
392    let (lo, hi): (Vec<f32>, Vec<f32>) = qs.iter().enumerate().map(|(j, &q)| x(j, q)).unzip();
393    y.extend(lo);
394    y.extend(hi);
395}
396
397fn q8_0(b: &[u8], y: &mut Vec<f32>) {
398    let d = half(b, 0);
399    y.extend(b[2..34].iter().map(|&q| (q as i8) as f32 * d));
400}
401
402/// The non-linear levels an IQ4 nibble indexes (ggml's `kvalues_iq4nl`).
403pub const KVALUES_IQ4NL: [i8; 16] = [-127, -104, -83, -65, -49, -35, -22, -10, 1, 13, 25, 38, 53, 69, 89, 113];
404
405fn iq4_nl(b: &[u8], y: &mut Vec<f32>) {
406    let d = half(b, 0);
407    let qs = &b[2..18];
408    y.extend(qs.iter().map(|&q| d * KVALUES_IQ4NL[(q & 0x0f) as usize] as f32));
409    y.extend(qs.iter().map(|&q| d * KVALUES_IQ4NL[(q >> 4) as usize] as f32));
410}
411
412fn iq4_xs(b: &[u8], y: &mut Vec<f32>) {
413    let d = half(b, 0);
414    let scales_h = u16::from_le_bytes([b[2], b[3]]);
415    let scales_l = &b[4..8];
416    let qs = &b[8..136];
417    for ib in 0..QK_K / 32 {
418        let ls = ((scales_l[ib / 2] >> (4 * (ib % 2))) & 0xf) as i32 | ((((scales_h >> (2 * ib)) & 3) as i32) << 4);
419        let dl = d * (ls - 32) as f32;
420        let q = &qs[16 * ib..16 * ib + 16];
421        y.extend(q.iter().map(|&v| dl * KVALUES_IQ4NL[(v & 0x0f) as usize] as f32));
422        y.extend(q.iter().map(|&v| dl * KVALUES_IQ4NL[(v >> 4) as usize] as f32));
423    }
424}
425
426/// The doubled E2M1 values of an MXFP4 nibble (ggml's `kvalues_mxfp4`).
427const KVALUES_MXFP4: [i8; 16] = [0, 1, 2, 3, 4, 6, 8, 12, 0, -1, -2, -3, -4, -6, -8, -12];
428
429/// Half of the E8M0 scale `2^(x-127)` — ggml's `ggml_e8m0_to_fp32_half`, halved to undo the doubled table.
430fn e8m0_half(x: u8) -> f32 {
431    let bits = if x < 2 {
432        0x0020_0000u32 << x
433    } else {
434        ((x - 1) as u32) << 23
435    };
436    f32::from_bits(bits)
437}
438
439fn mxfp4(b: &[u8], y: &mut Vec<f32>) {
440    let d = e8m0_half(b[0]);
441    let qs = &b[1..17];
442    y.extend(qs.iter().map(|&q| KVALUES_MXFP4[(q & 0x0f) as usize] as f32 * d));
443    y.extend(qs.iter().map(|&q| KVALUES_MXFP4[(q >> 4) as usize] as f32 * d));
444}
445
446fn q2_k(b: &[u8], y: &mut Vec<f32>) {
447    let scales = &b[0..16];
448    let qs = &b[16..80];
449    let (d, min) = (half(b, 80), half(b, 82));
450    let mut is = 0;
451    for n in (0..QK_K).step_by(128) {
452        let q = &qs[n / 4..n / 4 + 32];
453        let mut shift = 0;
454        for _ in 0..4 {
455            for half_block in [0usize, 16] {
456                let sc = scales[is];
457                is += 1;
458                let (dl, ml) = (d * (sc & 0xf) as f32, min * (sc >> 4) as f32);
459                for l in 0..16 {
460                    y.push(dl * (((q[l + half_block] >> shift) & 3) as i8) as f32 - ml);
461                }
462            }
463            shift += 2;
464        }
465    }
466}
467
468fn q3_k(b: &[u8], y: &mut Vec<f32>) {
469    let hm = &b[0..32];
470    let qs = &b[32..96];
471    let packed = &b[96..108];
472    let d_all = half(b, 108);
473    let (kmask1, kmask2) = (0x0303_0303u32, 0x0f0f_0f0fu32);
474    let mut aux = [0u32; 4];
475    for (k, a) in aux.iter_mut().take(3).enumerate() {
476        *a = u32::from_le_bytes([
477            packed[4 * k],
478            packed[4 * k + 1],
479            packed[4 * k + 2],
480            packed[4 * k + 3],
481        ]);
482    }
483    let tmp = aux[2];
484    aux[2] = ((aux[0] >> 4) & kmask2) | (((tmp >> 4) & kmask1) << 4);
485    aux[3] = ((aux[1] >> 4) & kmask2) | (((tmp >> 6) & kmask1) << 4);
486    aux[0] = (aux[0] & kmask2) | ((tmp & kmask1) << 4);
487    aux[1] = (aux[1] & kmask2) | (((tmp >> 2) & kmask1) << 4);
488    let scales: Vec<i8> = aux
489        .iter()
490        .flat_map(|a| a.to_le_bytes())
491        .map(|v| v as i8)
492        .collect();
493    let mut is = 0;
494    let mut m = 1u8;
495    for n in (0..QK_K).step_by(128) {
496        let q = &qs[n / 4..n / 4 + 32];
497        let mut shift = 0;
498        for _ in 0..4 {
499            for half_block in [0usize, 16] {
500                let dl = d_all * (scales[is] as i32 - 32) as f32;
501                is += 1;
502                for l in 0..16 {
503                    let low = ((q[l + half_block] >> shift) & 3) as i8;
504                    let high = if hm[l + half_block] & m != 0 { 0 } else { 4 };
505                    y.push(dl * (low - high) as f32);
506                }
507            }
508            shift += 2;
509            m <<= 1;
510        }
511    }
512}
513
514/// ggml's `get_scale_min_k4`: the 6-bit scale and min of sub-block `j` from a K-quant's 12 packed bytes.
515fn scale_min_k4(j: usize, q: &[u8]) -> (u8, u8) {
516    if j < 4 {
517        (q[j] & 63, q[j + 4] & 63)
518    } else {
519        (
520            (q[j + 4] & 0xf) | ((q[j - 4] >> 6) << 4),
521            (q[j + 4] >> 4) | ((q[j] >> 6) << 4),
522        )
523    }
524}
525
526fn q4_k(b: &[u8], y: &mut Vec<f32>) {
527    let (d, min) = (half(b, 0), half(b, 2));
528    let scales = &b[4..16];
529    let qs = &b[16..144];
530    let mut is = 0;
531    for j in (0..QK_K).step_by(64) {
532        let q = &qs[j / 2..j / 2 + 32];
533        let (sc, m) = scale_min_k4(is, scales);
534        let (d1, m1) = (d * sc as f32, min * m as f32);
535        let (sc, m) = scale_min_k4(is + 1, scales);
536        let (d2, m2) = (d * sc as f32, min * m as f32);
537        y.extend(q.iter().map(|&v| d1 * (v & 0xf) as f32 - m1));
538        y.extend(q.iter().map(|&v| d2 * (v >> 4) as f32 - m2));
539        is += 2;
540    }
541}
542
543fn q5_k(b: &[u8], y: &mut Vec<f32>) {
544    let (d, min) = (half(b, 0), half(b, 2));
545    let scales = &b[4..16];
546    let qh = &b[16..48];
547    let qs = &b[48..176];
548    let mut is = 0;
549    let (mut u1, mut u2) = (1u8, 2u8);
550    for j in (0..QK_K).step_by(64) {
551        let ql = &qs[j / 2..j / 2 + 32];
552        let (sc, m) = scale_min_k4(is, scales);
553        let (d1, m1) = (d * sc as f32, min * m as f32);
554        let (sc, m) = scale_min_k4(is + 1, scales);
555        let (d2, m2) = (d * sc as f32, min * m as f32);
556        for l in 0..32 {
557            let hi = if qh[l] & u1 != 0 { 16 } else { 0 };
558            y.push(d1 * ((ql[l] & 0xf) as i32 + hi) as f32 - m1);
559        }
560        for l in 0..32 {
561            let hi = if qh[l] & u2 != 0 { 16 } else { 0 };
562            y.push(d2 * ((ql[l] >> 4) as i32 + hi) as f32 - m2);
563        }
564        is += 2;
565        u1 <<= 2;
566        u2 <<= 2;
567    }
568}
569
570fn q6_k(b: &[u8], y: &mut Vec<f32>) {
571    let ql_all = &b[0..128];
572    let qh_all = &b[128..192];
573    let sc_all: Vec<i8> = b[192..208].iter().map(|&v| v as i8).collect();
574    let d = half(b, 208);
575    let mut block = [0f32; QK_K];
576    for (part, n) in (0..QK_K).step_by(128).enumerate() {
577        let ql = &ql_all[part * 64..part * 64 + 64];
578        let qh = &qh_all[part * 32..part * 32 + 32];
579        let sc = &sc_all[part * 8..part * 8 + 8];
580        for l in 0..32 {
581            let is = l / 16;
582            let q1 = (((ql[l] & 0xf) | ((qh[l] & 3) << 4)) as i8) - 32;
583            let q2 = (((ql[l + 32] & 0xf) | (((qh[l] >> 2) & 3) << 4)) as i8) - 32;
584            let q3 = (((ql[l] >> 4) | (((qh[l] >> 4) & 3) << 4)) as i8) - 32;
585            let q4 = (((ql[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) as i8) - 32;
586            block[n + l] = d * sc[is] as f32 * q1 as f32;
587            block[n + l + 32] = d * sc[is + 2] as f32 * q2 as f32;
588            block[n + l + 64] = d * sc[is + 4] as f32 * q3 as f32;
589            block[n + l + 96] = d * sc[is + 6] as f32 * q4 as f32;
590        }
591    }
592    y.extend_from_slice(&block);
593}