Skip to main content

fuel_quantized/
k_quants.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// Derived from candle (https://github.com/huggingface/candle, MIT OR Apache-2.0): `candle-core/src/quantized/k_quants.rs`
3// at commit 549eacb011f25b2c6fc765d6c3dbd26e42f72ee6, modified here. candle's code is itself a port of ggml / llama.cpp (MIT), which its own comments cite by commit.
4// Contributors, how this was verified and the licence texts: THIRD-PARTY-NOTICES.md (section "candle").
5use crate::utils::{
6    get_scale_min_k4, group_for_dequantization, group_for_quantization, make_q3_quants,
7    make_qkx1_quants, make_qkx3_quants, make_qp_quants, make_qx_quants, nearest_int,
8};
9use byteorder::{ByteOrder, LittleEndian};
10use fuel_ir::Result;
11use fuel_ir::quantized::GgmlDType;
12use half::{bf16, f16, slice::HalfFloatSliceExt};
13use rayon::prelude::*;
14
15// Default to QK_K 256 rather than 64.
16pub const QK_K: usize = 256;
17pub const K_SCALE_SIZE: usize = 12;
18
19pub const QK4_0: usize = 32;
20pub const QK4_1: usize = 32;
21pub const QK5_0: usize = 32;
22pub const QK5_1: usize = 32;
23pub const QK8_0: usize = 32;
24pub const QK8_1: usize = 32;
25
26/// A GGML block type (or a dense scalar standing in for one).
27///
28/// `bytemuck::Pod` is a supertrait on purpose: every implementor is
29/// `#[repr(C)]` plain data with no padding and no invalid bit pattern, so a
30/// byte slice of the right length and alignment IS a valid `[Self]`, and
31/// all-zero bytes ARE a valid `Self`. Making that a bound the compiler checks
32/// (the derive refuses a type with padding) replaces the hand-written
33/// `unsafe` casts that each asserted it in a comment.
34pub trait GgmlType: Sized + Clone + Send + Sync + bytemuck::Pod {
35    const DTYPE: GgmlDType;
36    const BLCK_SIZE: usize;
37    const DIRECT_COPY: bool = false;
38    type VecDotType: GgmlType;
39
40    /// The all-zero value. Safe by construction: `Self: Pod` implies `Zeroable`.
41    fn zeros() -> Self {
42        <Self as bytemuck::Zeroable>::zeroed()
43    }
44    fn to_float(xs: &[Self], ys: &mut [f32]);
45    fn from_float(xs: &[f32], ys: &mut [Self]);
46    fn from_float_imatrix(
47        _xs: &[f32],
48        _ys: &mut [Self],
49        _imatrix_weights: &[f32],
50        _n_per_row: usize,
51    ) {
52        panic!(
53            "`from_float_imatrix` is unimplemented for {:?}",
54            Self::DTYPE
55        );
56    }
57
58    fn direct_copy(_xs: &[f32], _ys: &mut [Self]) {}
59
60    /// Dot product used as a building block for quantized mat-mul.
61    /// n is the number of elements to be considered.
62    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32;
63
64    /// Generic implementation of the dot product without simd optimizations.
65    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32;
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
69#[repr(C)]
70pub struct BlockQ4_0 {
71    pub(crate) d: f16,
72    pub(crate) qs: [u8; QK4_0 / 2],
73}
74const _: () = assert!(std::mem::size_of::<BlockQ4_0>() == 18);
75
76#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
77#[repr(C)]
78pub struct BlockQ4_1 {
79    pub(crate) d: f16,
80    pub(crate) m: f16,
81    pub(crate) qs: [u8; QK4_1 / 2],
82}
83const _: () = assert!(std::mem::size_of::<BlockQ4_1>() == 20);
84
85#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
86#[repr(C)]
87pub struct BlockQ5_0 {
88    pub(crate) d: f16,
89    pub(crate) qh: [u8; 4],
90    pub(crate) qs: [u8; QK5_0 / 2],
91}
92const _: () = assert!(std::mem::size_of::<BlockQ5_0>() == 22);
93
94#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
95#[repr(C)]
96pub struct BlockQ5_1 {
97    pub(crate) d: f16,
98    pub(crate) m: f16,
99    pub(crate) qh: [u8; 4],
100    pub(crate) qs: [u8; QK5_1 / 2],
101}
102const _: () = assert!(std::mem::size_of::<BlockQ5_1>() == 24);
103
104#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
105#[repr(C)]
106pub struct BlockQ8_0 {
107    pub(crate) d: f16,
108    pub(crate) qs: [i8; QK8_0],
109}
110const _: () = assert!(std::mem::size_of::<BlockQ8_0>() == 34);
111
112#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
113#[repr(C)]
114pub struct BlockQ8_1 {
115    pub(crate) d: f16,
116    pub(crate) s: f16,
117    pub(crate) qs: [i8; QK8_1],
118}
119const _: () = assert!(std::mem::size_of::<BlockQ8_1>() == 36);
120
121#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
122#[repr(C)]
123pub struct BlockQ2K {
124    pub(crate) scales: [u8; QK_K / 16],
125    pub(crate) qs: [u8; QK_K / 4],
126    pub(crate) d: f16,
127    pub(crate) dmin: f16,
128}
129const _: () = assert!(QK_K / 16 + QK_K / 4 + 2 * 2 == std::mem::size_of::<BlockQ2K>());
130
131#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
132#[repr(C)]
133pub struct BlockQ3K {
134    pub(crate) hmask: [u8; QK_K / 8],
135    pub(crate) qs: [u8; QK_K / 4],
136    pub(crate) scales: [u8; 12],
137    pub(crate) d: f16,
138}
139const _: () = assert!(QK_K / 8 + QK_K / 4 + 12 + 2 == std::mem::size_of::<BlockQ3K>());
140
141#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
142// https://github.com/ggerganov/llama.cpp/blob/468ea24fb4633a0d681f7ac84089566c1c6190cb/k_quants.h#L82
143#[repr(C)]
144pub struct BlockQ4K {
145    pub(crate) d: f16,
146    pub(crate) dmin: f16,
147    pub(crate) scales: [u8; K_SCALE_SIZE],
148    pub(crate) qs: [u8; QK_K / 2],
149}
150const _: () = assert!(QK_K / 2 + K_SCALE_SIZE + 2 * 2 == std::mem::size_of::<BlockQ4K>());
151
152#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
153#[repr(C)]
154pub struct BlockQ5K {
155    pub(crate) d: f16,
156    pub(crate) dmin: f16,
157    pub(crate) scales: [u8; K_SCALE_SIZE],
158    pub(crate) qh: [u8; QK_K / 8],
159    pub(crate) qs: [u8; QK_K / 2],
160}
161const _: () =
162    assert!(QK_K / 8 + QK_K / 2 + 2 * 2 + K_SCALE_SIZE == std::mem::size_of::<BlockQ5K>());
163
164#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
165#[repr(C)]
166pub struct BlockQ6K {
167    pub(crate) ql: [u8; QK_K / 2],
168    pub(crate) qh: [u8; QK_K / 4],
169    pub(crate) scales: [i8; QK_K / 16],
170    pub(crate) d: f16,
171}
172const _: () = assert!(3 * QK_K / 4 + QK_K / 16 + 2 == std::mem::size_of::<BlockQ6K>());
173
174#[derive(Debug, Clone, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
175#[repr(C)]
176pub struct BlockQ8K {
177    pub(crate) d: f32,
178    pub(crate) qs: [i8; QK_K],
179    pub(crate) bsums: [i16; QK_K / 16],
180}
181const _: () = assert!(4 + QK_K + QK_K / 16 * 2 == std::mem::size_of::<BlockQ8K>());
182
183/// View a block slice as its raw bytes: GGUF's on-disk layout, byte for byte.
184///
185/// Infallible: `u8` has alignment 1 and every `T: GgmlType` is `Pod`, so this
186/// is a plain reinterpretation with no length or alignment condition.
187pub fn blocks_as_bytes<T: GgmlType>(blocks: &[T]) -> &[u8] {
188    bytemuck::cast_slice(blocks)
189}
190
191/// Reinterpret GGUF bytes as a dense `[T]` array.
192///
193/// Borrowed when `bytes` happens to be aligned for `T`, **copied** into an
194/// aligned `Vec<T>` otherwise: a `&[u8]` guarantees only 1-byte alignment, and
195/// a sub-slice taken at a tensor offset inside an mmap need not be aligned for
196/// the `f16`/`f32` fields of a block, so assuming it is would be unsound.
197///
198/// A trailing partial block is dropped, matching the pre-existing
199/// per-model `cpu_dequant_*_bytes` callers; callers that must reject a ragged
200/// length check `bytes.len() % size_of::<T>()` themselves.
201pub fn blocks_from_bytes_cow<T: GgmlType>(bytes: &[u8]) -> std::borrow::Cow<'_, [T]> {
202    let size = std::mem::size_of::<T>();
203    let whole = &bytes[..(bytes.len() / size) * size];
204    match bytemuck::try_cast_slice::<u8, T>(whole) {
205        Ok(blocks) => std::borrow::Cow::Borrowed(blocks),
206        Err(_) => std::borrow::Cow::Owned(
207            whole
208                .chunks_exact(size)
209                .map(bytemuck::pod_read_unaligned::<T>)
210                .collect(),
211        ),
212    }
213}
214
215impl GgmlType for BlockQ4_0 {
216    const DTYPE: GgmlDType = GgmlDType::Q4_0;
217    const BLCK_SIZE: usize = QK4_0;
218    type VecDotType = BlockQ8_0;
219
220    // https://github.com/ggerganov/llama.cpp/blob/468ea24fb4633a0d681f7ac84089566c1c6190cb/ggml.c#L1525
221    fn to_float(xs: &[Self], ys: &mut [f32]) {
222        let k = ys.len();
223        let qk = Self::BLCK_SIZE;
224        debug_assert!(
225            k.is_multiple_of(qk),
226            "dequantize_row_q4_0: {k} is not divisible by {qk}"
227        );
228
229        let nb = k / qk;
230        for i in 0..nb {
231            let d = xs[i].d.to_f32();
232
233            for j in 0..(qk / 2) {
234                let x0 = (xs[i].qs[j] & 0x0F) as i16 - 8;
235                let x1 = (xs[i].qs[j] >> 4) as i16 - 8;
236
237                ys[i * qk + j] = (x0 as f32) * d;
238                ys[i * qk + j + qk / 2] = (x1 as f32) * d;
239            }
240        }
241    }
242
243    fn from_float(xs: &[f32], ys: &mut [Self]) {
244        // quantize_row_q4_0
245        let qk = Self::BLCK_SIZE;
246        let k = xs.len();
247        debug_assert!(k.is_multiple_of(qk), "{k} is not divisible by {qk}");
248        debug_assert_eq!(
249            ys.len(),
250            k / qk,
251            "size mismatch {} {} {}",
252            xs.len(),
253            ys.len(),
254            qk,
255        );
256        for (i, ys) in ys.iter_mut().enumerate() {
257            let mut amax = 0f32;
258            let mut max = 0f32;
259
260            let xs = &xs[i * qk..(i + 1) * qk];
261            for &x in xs.iter() {
262                if amax < x.abs() {
263                    amax = x.abs();
264                    max = x;
265                }
266            }
267            let d = max / -8.0;
268            let id = if d != 0f32 { 1. / d } else { 0. };
269            ys.d = f16::from_f32(d);
270
271            for (j, q) in ys.qs.iter_mut().enumerate() {
272                let x0 = xs[j] * id;
273                let x1 = xs[qk / 2 + j] * id;
274                let xi0 = u8::min(15, (x0 + 8.5) as u8);
275                let xi1 = u8::min(15, (x1 + 8.5) as u8);
276                *q = xi0 | (xi1 << 4)
277            }
278        }
279    }
280
281    // https://github.com/ggerganov/llama.cpp/blob/b5ffb2849d23afe73647f68eec7b68187af09be6/ggml.c#L2361C10-L2361C122
282    #[allow(unreachable_code)]
283    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
284        #[cfg(target_feature = "avx2")]
285        return super::avx::vec_dot_q4_0_q8_0(n, xs, ys);
286
287        #[cfg(target_feature = "neon")]
288        return super::neon::vec_dot_q4_0_q8_0(n, xs, ys);
289
290        Self::vec_dot_unopt(n, xs, ys)
291    }
292
293    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
294        debug_assert!(
295            n.is_multiple_of(QK8_0),
296            "vec_dot_q4_0_q8_0: {n} is not divisible by {QK8_0}"
297        );
298        // Generic implementation.
299        let mut sumf = 0f32;
300        for (xs, ys) in xs.iter().zip(ys.iter()) {
301            let mut sum_i = 0;
302            for j in 0..QK8_0 / 2 {
303                let v0 = (xs.qs[j] & 0x0F) as i32 - 8;
304                let v1 = (xs.qs[j] >> 4) as i32 - 8;
305                sum_i += v0 * ys.qs[j] as i32 + v1 * ys.qs[j + QK8_0 / 2] as i32
306            }
307            sumf += sum_i as f32 * f16::to_f32(xs.d) * f16::to_f32(ys.d)
308        }
309        sumf
310    }
311}
312
313impl GgmlType for BlockQ4_1 {
314    const DTYPE: GgmlDType = GgmlDType::Q4_1;
315    const BLCK_SIZE: usize = QK4_1;
316    type VecDotType = BlockQ8_1;
317
318    #[allow(unreachable_code)]
319    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
320        #[cfg(target_feature = "avx2")]
321        return super::avx::vec_dot_q4_1_q8_1(n, xs, ys);
322
323        Self::vec_dot_unopt(n, xs, ys)
324    }
325
326    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
327        // ggml_vec_dot_q4_1_q8_1
328        let qk = QK8_1;
329        debug_assert!(
330            n.is_multiple_of(qk),
331            "vec_dot_q4_1_q8_1: {n} is not divisible by {qk}"
332        );
333        debug_assert!(
334            (n / qk).is_multiple_of(2),
335            "vec_dot_q4_1_q8_1: {n}, nb is not divisible by 2"
336        );
337
338        // Generic implementation.
339        let mut sumf = 0f32;
340
341        for (xs, ys) in xs.iter().zip(ys.iter()) {
342            let mut sumi = 0i32;
343
344            for j in 0..qk / 2 {
345                let v0 = xs.qs[j] as i32 & 0x0F;
346                let v1 = xs.qs[j] as i32 >> 4;
347                sumi += (v0 * ys.qs[j] as i32) + (v1 * ys.qs[j + qk / 2] as i32);
348            }
349
350            sumf += sumi as f32 * f16::to_f32(xs.d) * f16::to_f32(ys.d)
351                + f16::to_f32(xs.m) * f16::to_f32(ys.s)
352        }
353        sumf
354    }
355
356    fn from_float(xs: &[f32], ys: &mut [Self]) {
357        // quantize_row_q4_1
358        let qk = Self::BLCK_SIZE;
359
360        debug_assert_eq!(
361            ys.len() * qk,
362            xs.len(),
363            "size mismatch {} {} {}",
364            xs.len(),
365            ys.len(),
366            qk,
367        );
368        for (i, ys) in ys.iter_mut().enumerate() {
369            let xs = &xs[i * qk..(i + 1) * qk];
370
371            let mut min = f32::INFINITY;
372            let mut max = f32::NEG_INFINITY;
373            for &x in xs.iter() {
374                min = f32::min(x, min);
375                max = f32::max(x, max);
376            }
377            let d = (max - min) / ((1 << 4) - 1) as f32;
378            let id = if d != 0f32 { 1. / d } else { 0. };
379            ys.d = f16::from_f32(d);
380            ys.m = f16::from_f32(min);
381
382            for (j, q) in ys.qs.iter_mut().take(qk / 2).enumerate() {
383                let x0 = (xs[j] - min) * id;
384                let x1 = (xs[qk / 2 + j] - min) * id;
385
386                let xi0 = u8::min(15, (x0 + 0.5) as u8);
387                let xi1 = u8::min(15, (x1 + 0.5) as u8);
388
389                *q = xi0 | (xi1 << 4);
390            }
391        }
392    }
393
394    // https://github.com/ggerganov/llama.cpp/blob/468ea24fb4633a0d681f7ac84089566c1c6190cb/ggml.c#L1545
395    fn to_float(xs: &[Self], ys: &mut [f32]) {
396        let k = ys.len();
397        debug_assert!(
398            k.is_multiple_of(QK4_1),
399            "dequantize_row_q4_1: {k} is not divisible by {QK4_1}"
400        );
401
402        let nb = k / QK4_1;
403        for i in 0..nb {
404            let d = xs[i].d.to_f32();
405            let m = xs[i].m.to_f32();
406
407            for j in 0..(QK4_1 / 2) {
408                let x0 = xs[i].qs[j] & 0x0F;
409                let x1 = xs[i].qs[j] >> 4;
410
411                ys[i * QK4_1 + j] = (x0 as f32) * d + m;
412                ys[i * QK4_1 + j + QK4_1 / 2] = (x1 as f32) * d + m;
413            }
414        }
415    }
416}
417
418impl GgmlType for BlockQ5_0 {
419    const DTYPE: GgmlDType = GgmlDType::Q5_0;
420    const BLCK_SIZE: usize = QK5_0;
421    type VecDotType = BlockQ8_0;
422
423    #[allow(unreachable_code)]
424    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
425        let qk = Self::BLCK_SIZE;
426
427        debug_assert!(
428            n.is_multiple_of(qk),
429            "vec_dot_q5_0_q8_0: {n} is not divisible by {qk}"
430        );
431        debug_assert!(
432            (n / qk).is_multiple_of(2),
433            "vec_dot_q5_0_q8_0: {n}, nb is not divisible by 2"
434        );
435
436        #[cfg(target_feature = "avx2")]
437        return super::avx::vec_dot_q5_0_q8_0(n, xs, ys);
438
439        Self::vec_dot_unopt(n, xs, ys)
440    }
441
442    fn vec_dot_unopt(_n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
443        // Generic implementation.
444        let mut sumf = 0f32;
445
446        for (xs, ys) in xs.iter().zip(ys.iter()) {
447            let qh = LittleEndian::read_u32(&xs.qh);
448            let mut sumi = 0i32;
449
450            for j in 0..Self::BLCK_SIZE / 2 {
451                let xh_0 = (((qh & (1u32 << j)) >> j) << 4) as u8;
452                let xh_1 = ((qh & (1u32 << (j + 16))) >> (j + 12)) as u8;
453
454                let x0 = ((xs.qs[j] & 0x0F) as i32 | xh_0 as i32) - 16;
455                let x1 = ((xs.qs[j] >> 4) as i32 | xh_1 as i32) - 16;
456
457                sumi += (x0 * ys.qs[j] as i32) + (x1 * ys.qs[j + Self::BLCK_SIZE / 2] as i32);
458            }
459
460            sumf += sumi as f32 * f16::to_f32(xs.d) * f16::to_f32(ys.d)
461        }
462        sumf
463    }
464
465    fn from_float(xs: &[f32], ys: &mut [Self]) {
466        // quantize_row_q5_0
467        debug_assert_eq!(
468            ys.len() * Self::BLCK_SIZE,
469            xs.len(),
470            "size mismatch {} {} {}",
471            xs.len(),
472            ys.len(),
473            Self::BLCK_SIZE,
474        );
475        for (i, ys) in ys.iter_mut().enumerate() {
476            let xs = &xs[i * Self::BLCK_SIZE..(i + 1) * Self::BLCK_SIZE];
477
478            let mut amax = 0f32;
479            let mut max = 0f32;
480            for &x in xs.iter() {
481                if amax < x.abs() {
482                    amax = x.abs();
483                    max = x;
484                }
485            }
486            let d = max / -16.;
487            let id = if d != 0f32 { 1. / d } else { 0. };
488            ys.d = f16::from_f32(d);
489            let mut qh = 0u32;
490            for j in 0..Self::BLCK_SIZE / 2 {
491                let x0 = xs[j] * id;
492                let x1 = xs[j + Self::BLCK_SIZE / 2] * id;
493                let xi0 = ((x0 + 16.5) as i8).min(31) as u8;
494                let xi1 = ((x1 + 16.5) as i8).min(31) as u8;
495                ys.qs[j] = (xi0 & 0x0F) | ((xi1 & 0x0F) << 4);
496                qh |= ((xi0 as u32 & 0x10) >> 4) << j;
497                qh |= ((xi1 as u32 & 0x10) >> 4) << (j + Self::BLCK_SIZE / 2);
498            }
499            LittleEndian::write_u32(&mut ys.qh, qh)
500        }
501    }
502
503    // https://github.com/ggerganov/llama.cpp/blob/468ea24fb4633a0d681f7ac84089566c1c6190cb/ggml.c#L1566
504    fn to_float(xs: &[Self], ys: &mut [f32]) {
505        let k = ys.len();
506        debug_assert!(
507            k.is_multiple_of(QK5_0),
508            "dequantize_row_q5_0: {k} is not divisible by {QK5_0}"
509        );
510        let nb = k / QK5_0;
511        for i in 0..nb {
512            let d = xs[i].d.to_f32();
513            let qh: u32 = LittleEndian::read_u32(&xs[i].qh);
514
515            for j in 0..(QK5_0 / 2) {
516                let xh_0 = (((qh >> j) << 4) & 0x10) as u8;
517                let xh_1 = ((qh >> (j + 12)) & 0x10) as u8;
518
519                let x0 = ((xs[i].qs[j] & 0x0F) | xh_0) as i32 - 16;
520                let x1 = ((xs[i].qs[j] >> 4) | xh_1) as i32 - 16;
521
522                ys[i * QK5_0 + j] = (x0 as f32) * d;
523                ys[i * QK5_0 + j + QK5_0 / 2] = (x1 as f32) * d;
524            }
525        }
526    }
527}
528
529impl GgmlType for BlockQ5_1 {
530    const DTYPE: GgmlDType = GgmlDType::Q5_1;
531    const BLCK_SIZE: usize = QK5_1;
532    type VecDotType = BlockQ8_1;
533
534    #[allow(unreachable_code)]
535    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
536        #[cfg(target_feature = "avx2")]
537        return super::avx::vec_dot_q5_1_q8_1(n, xs, ys);
538
539        Self::vec_dot_unopt(n, xs, ys)
540    }
541
542    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
543        let qk = Self::BLCK_SIZE;
544        debug_assert!(
545            n.is_multiple_of(qk),
546            "vec_dot_q5_1_q8_1: {n} is not divisible by {qk}"
547        );
548        debug_assert!(
549            (n / qk).is_multiple_of(2),
550            "vec_dot_q5_1_q8_1: {n}, nb is not divisible by 2"
551        );
552
553        // Generic implementation.
554        let mut sumf = 0f32;
555
556        for (xs, ys) in xs.iter().zip(ys.iter()) {
557            let qh = LittleEndian::read_u32(&xs.qh);
558            let mut sumi = 0i32;
559
560            for j in 0..Self::BLCK_SIZE / 2 {
561                let xh_0 = ((qh >> j) << 4) & 0x10;
562                let xh_1 = (qh >> (j + 12)) & 0x10;
563
564                let x0 = (xs.qs[j] as i32 & 0xF) | xh_0 as i32;
565                let x1 = (xs.qs[j] as i32 >> 4) | xh_1 as i32;
566
567                sumi += (x0 * ys.qs[j] as i32) + (x1 * ys.qs[j + Self::BLCK_SIZE / 2] as i32);
568            }
569
570            sumf += sumi as f32 * f16::to_f32(xs.d) * f16::to_f32(ys.d)
571                + f16::to_f32(xs.m) * f16::to_f32(ys.s)
572        }
573        sumf
574    }
575
576    fn from_float(xs: &[f32], ys: &mut [Self]) {
577        // quantize_row_q5_1
578        let qk = Self::BLCK_SIZE;
579        debug_assert_eq!(
580            ys.len() * qk,
581            xs.len(),
582            "size mismatch {} {} {}",
583            xs.len(),
584            ys.len(),
585            qk,
586        );
587        for (i, ys) in ys.iter_mut().enumerate() {
588            let xs = &xs[i * qk..(i + 1) * qk];
589
590            let mut min = f32::INFINITY;
591            let mut max = f32::NEG_INFINITY;
592            for &x in xs.iter() {
593                min = f32::min(x, min);
594                max = f32::max(x, max);
595            }
596            let d = (max - min) / ((1 << 5) - 1) as f32;
597            let id = if d != 0f32 { 1. / d } else { 0. };
598            ys.d = f16::from_f32(d);
599            ys.m = f16::from_f32(min);
600
601            let mut qh = 0u32;
602            for (j, q) in ys.qs.iter_mut().take(qk / 2).enumerate() {
603                let x0 = (xs[j] - min) * id;
604                let x1 = (xs[qk / 2 + j] - min) * id;
605
606                let xi0 = (x0 + 0.5) as u8;
607                let xi1 = (x1 + 0.5) as u8;
608
609                *q = (xi0 & 0x0F) | ((xi1 & 0x0F) << 4);
610                // get the 5-th bit and store it in qh at the right position
611                qh |= ((xi0 as u32 & 0x10) >> 4) << j;
612                qh |= ((xi1 as u32 & 0x10) >> 4) << (j + qk / 2);
613            }
614            LittleEndian::write_u32(&mut ys.qh, qh);
615        }
616    }
617
618    // https://github.com/ggerganov/llama.cpp/blob/468ea24fb4633a0d681f7ac84089566c1c6190cb/ggml.c#L1592
619    fn to_float(xs: &[Self], ys: &mut [f32]) {
620        let k = ys.len();
621        debug_assert!(
622            k.is_multiple_of(QK5_1),
623            "dequantize_row_q5_1: {k} is not divisible by {QK5_1}"
624        );
625
626        let nb = k / QK5_1;
627        for i in 0..nb {
628            let d = xs[i].d.to_f32();
629            let m = xs[i].m.to_f32();
630            let qh: u32 = LittleEndian::read_u32(&xs[i].qh);
631
632            for j in 0..(QK5_1 / 2) {
633                let xh_0 = (((qh >> j) << 4) & 0x10) as u8;
634                let xh_1 = ((qh >> (j + 12)) & 0x10) as u8;
635
636                let x0 = (xs[i].qs[j] & 0x0F) | xh_0;
637                let x1 = (xs[i].qs[j] >> 4) | xh_1;
638
639                ys[i * QK5_1 + j] = (x0 as f32) * d + m;
640                ys[i * QK5_1 + j + QK5_1 / 2] = (x1 as f32) * d + m;
641            }
642        }
643    }
644}
645
646impl GgmlType for BlockQ8_0 {
647    const DTYPE: GgmlDType = GgmlDType::Q8_0;
648    const BLCK_SIZE: usize = QK8_0;
649    type VecDotType = BlockQ8_0;
650
651    // https://github.com/ggerganov/llama.cpp/blob/468ea24fb4633a0d681f7ac84089566c1c6190cb/ggml.c#L1619
652    fn to_float(xs: &[Self], ys: &mut [f32]) {
653        let k = ys.len();
654        debug_assert!(
655            k.is_multiple_of(QK8_0),
656            "dequantize_row_q8_0: {k} is not divisible by {QK8_0}"
657        );
658
659        let nb = k / QK8_0;
660
661        for i in 0..nb {
662            let d = xs[i].d.to_f32();
663
664            for j in 0..QK8_0 {
665                ys[i * QK8_0 + j] = xs[i].qs[j] as f32 * d;
666            }
667        }
668    }
669
670    fn from_float(xs: &[f32], ys: &mut [Self]) {
671        // quantize_row_q8_0
672        let k = xs.len();
673        debug_assert!(
674            k.is_multiple_of(Self::BLCK_SIZE),
675            "{k} is not divisible by {}",
676            Self::BLCK_SIZE
677        );
678        debug_assert_eq!(
679            ys.len(),
680            k / Self::BLCK_SIZE,
681            "size mismatch {} {} {}",
682            xs.len(),
683            ys.len(),
684            Self::BLCK_SIZE
685        );
686        for (i, ys) in ys.iter_mut().enumerate() {
687            let mut amax = 0f32;
688            let xs = &xs[i * Self::BLCK_SIZE..(i + 1) * Self::BLCK_SIZE];
689            for &x in xs.iter() {
690                amax = amax.max(x.abs())
691            }
692            let d = amax / ((1 << 7) - 1) as f32;
693            let id = if d != 0f32 { 1. / d } else { 0. };
694            ys.d = f16::from_f32(d);
695            for (y, &x) in ys.qs.iter_mut().zip(xs.iter()) {
696                *y = f32::round(x * id) as i8
697            }
698        }
699    }
700
701    #[allow(unreachable_code)]
702    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
703        #[cfg(target_feature = "avx2")]
704        return super::avx::vec_dot_q8_0_q8_0(n, xs, ys);
705
706        #[cfg(target_feature = "neon")]
707        return super::neon::vec_dot_q8_0_q8_0(n, xs, ys);
708
709        Self::vec_dot_unopt(n, xs, ys)
710    }
711
712    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
713        debug_assert!(
714            n.is_multiple_of(QK8_0),
715            "vec_dot_q8_0_q8_0: {n} is not divisible by {QK8_0}"
716        );
717
718        // Generic implementation.
719        let mut sumf = 0f32;
720        for (xs, ys) in xs.iter().zip(ys.iter()) {
721            let sum_i = xs
722                .qs
723                .iter()
724                .zip(ys.qs.iter())
725                .map(|(&x, &y)| x as i32 * y as i32)
726                .sum::<i32>();
727            sumf += sum_i as f32 * f16::to_f32(xs.d) * f16::to_f32(ys.d)
728        }
729        sumf
730    }
731}
732
733impl GgmlType for BlockQ8_1 {
734    const DTYPE: GgmlDType = GgmlDType::Q8_1;
735    const BLCK_SIZE: usize = QK8_1;
736    type VecDotType = BlockQ8_1;
737
738    #[allow(unreachable_code)]
739    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
740        #[cfg(target_feature = "avx2")]
741        return super::avx::vec_dot_q8_1_q8_1(n, xs, ys);
742
743        Self::vec_dot_unopt(n, xs, ys)
744    }
745
746    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
747        debug_assert!(
748            n.is_multiple_of(QK8_1),
749            "vec_dot_q8_1_q8_1: {n} is not divisible by {QK8_1}"
750        );
751
752        // Generic implementation.
753        let mut sumf = 0f32;
754        for (xs, ys) in xs.iter().zip(ys.iter()) {
755            let sum_i = xs
756                .qs
757                .iter()
758                .zip(ys.qs.iter())
759                .map(|(&x, &y)| x as i32 * y as i32)
760                .sum::<i32>();
761            sumf += sum_i as f32 * f16::to_f32(xs.d) * f16::to_f32(ys.d)
762        }
763        sumf
764    }
765
766    fn from_float(xs: &[f32], ys: &mut [Self]) {
767        // quantize_row_q8_1
768        debug_assert_eq!(
769            ys.len() * Self::BLCK_SIZE,
770            xs.len(),
771            "size mismatch {} {} {}",
772            xs.len(),
773            ys.len(),
774            Self::BLCK_SIZE
775        );
776        for (i, ys) in ys.iter_mut().enumerate() {
777            let mut amax = 0f32;
778            let xs = &xs[i * Self::BLCK_SIZE..(i + 1) * Self::BLCK_SIZE];
779            for &x in xs.iter() {
780                amax = amax.max(x.abs())
781            }
782            let d = amax / ((1 << 7) - 1) as f32;
783            let id = if d != 0f32 { 1. / d } else { 0. };
784            ys.d = f16::from_f32(d);
785            let mut sum = 0i32;
786            for j in 0..Self::BLCK_SIZE / 2 {
787                let v0 = xs[j] * id;
788                let v1 = xs[j + Self::BLCK_SIZE / 2] * id;
789                ys.qs[j] = f32::round(v0) as i8;
790                ys.qs[j + Self::BLCK_SIZE / 2] = f32::round(v1) as i8;
791                sum += ys.qs[j] as i32 + ys.qs[j + Self::BLCK_SIZE / 2] as i32;
792            }
793            ys.s = f16::from_f32(sum as f32) * ys.d;
794        }
795    }
796
797    fn to_float(_xs: &[Self], _ys: &mut [f32]) {
798        unimplemented!("no support for vec-dot on Q8_1") // GAP(GAP-125)
799    }
800}
801
802impl GgmlType for BlockQ2K {
803    const DTYPE: GgmlDType = GgmlDType::Q2K;
804    const BLCK_SIZE: usize = QK_K;
805    type VecDotType = BlockQ8K;
806
807    #[allow(unreachable_code)]
808    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
809        #[cfg(target_feature = "avx2")]
810        return super::avx::vec_dot_q2k_q8k(n, xs, ys);
811
812        #[cfg(target_feature = "neon")]
813        return super::neon::vec_dot_q2k_q8k(n, xs, ys);
814
815        Self::vec_dot_unopt(n, xs, ys)
816    }
817
818    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
819        debug_assert!(
820            n.is_multiple_of(QK_K),
821            "vec_dot_q2k_q8k: {n} is not divisible by {QK_K}"
822        );
823
824        let mut sumf = 0.0;
825        for (x, y) in xs.iter().zip(ys.iter()) {
826            let mut q2: &[_] = &x.qs;
827            let mut q8: &[_] = &y.qs;
828            let sc = &x.scales;
829
830            let mut summs = 0;
831            for (bsum, scale) in y.bsums.iter().zip(sc) {
832                summs += *bsum as i32 * ((scale >> 4) as i32);
833            }
834
835            let dall = y.d * x.d.to_f32();
836            let dmin = y.d * x.dmin.to_f32();
837
838            let mut isum = 0;
839            let mut is = 0;
840            for _ in 0..(QK_K / 128) {
841                let mut shift = 0;
842                for _ in 0..4 {
843                    let d = (sc[is] & 0xF) as i32;
844                    is += 1;
845                    let mut isuml = 0;
846                    for l in 0..16 {
847                        isuml += q8[l] as i32 * (((q2[l] >> shift) & 3) as i32);
848                    }
849                    isum += d * isuml;
850                    let d = (sc[is] & 0xF) as i32;
851                    is += 1;
852                    isuml = 0;
853                    for l in 16..32 {
854                        isuml += q8[l] as i32 * (((q2[l] >> shift) & 3) as i32);
855                    }
856                    isum += d * isuml;
857                    shift += 2;
858                    // adjust the indexing
859                    q8 = &q8[32..];
860                }
861                // adjust the indexing
862                q2 = &q2[32..];
863            }
864            sumf += dall * isum as f32 - dmin * summs as f32;
865        }
866
867        sumf
868    }
869
870    // https://github.com/ggerganov/llama.cpp/blob/8183159cf3def112f6d1fe94815fce70e1bffa12/k_quants.c#L279
871    fn from_float(xs: &[f32], ys: &mut [Self]) {
872        const Q4SCALE: f32 = 15.0;
873
874        for (block, x) in group_for_quantization(xs, ys) {
875            //calculate scales and mins
876            let mut mins: [f32; QK_K / 16] = [0.0; QK_K / 16];
877            let mut scales: [f32; QK_K / 16] = [0.0; QK_K / 16];
878
879            for (j, x_scale_slice) in x.chunks(16).enumerate() {
880                (scales[j], mins[j]) = make_qkx1_quants(3, 5, x_scale_slice);
881            }
882            // get max scale and max min and ensure they are >= 0.0
883            let max_scale = scales.iter().fold(0.0, |max, &val| val.max(max));
884            let max_min = mins.iter().fold(0.0, |max, &val| val.max(max));
885
886            if max_scale > 0.0 {
887                let iscale = Q4SCALE / max_scale;
888                for (j, scale) in scales.iter().enumerate().take(QK_K / 16) {
889                    block.scales[j] = nearest_int(iscale * scale) as u8;
890                }
891                block.d = f16::from_f32(max_scale / Q4SCALE);
892            } else {
893                for j in 0..QK_K / 16 {
894                    block.scales[j] = 0;
895                }
896                block.d = f16::from_f32(0.0);
897            }
898
899            if max_min > 0.0 {
900                let iscale = Q4SCALE / max_min;
901                for (j, scale) in block.scales.iter_mut().enumerate() {
902                    let l = nearest_int(iscale * mins[j]) as u8;
903                    *scale |= l << 4;
904                }
905                block.dmin = f16::from_f32(max_min / Q4SCALE);
906            } else {
907                block.dmin = f16::from_f32(0.0);
908            }
909
910            let mut big_l: [u8; QK_K] = [0; QK_K];
911
912            for j in 0..QK_K / 16 {
913                let d = block.d.to_f32() * (block.scales[j] & 0xF) as f32;
914                if d == 0.0 {
915                    continue;
916                }
917                let dm = block.dmin.to_f32() * (block.scales[j] >> 4) as f32;
918                for ii in 0..16 {
919                    let ll = nearest_int((x[16 * j + ii] + dm) / d).clamp(0, 3);
920                    big_l[16 * j + ii] = ll as u8;
921                }
922            }
923
924            for j in (0..QK_K).step_by(128) {
925                for ll in 0..32 {
926                    block.qs[j / 4 + ll] = big_l[j + ll]
927                        | (big_l[j + ll + 32] << 2)
928                        | (big_l[j + ll + 64] << 4)
929                        | (big_l[j + ll + 96] << 6);
930                }
931            }
932        }
933    }
934
935    fn from_float_imatrix(xs: &[f32], ys: &mut [Self], imatrix_weights: &[f32], n_per_row: usize) {
936        for (sblk_idx, (block, x)) in group_for_quantization(xs, ys).into_iter().enumerate() {
937            let mut mins: [f32; QK_K / 16] = [0.0; QK_K / 16];
938            let mut scales: [f32; QK_K / 16] = [0.0; QK_K / 16];
939            let mut weights: [f32; 16] = [0.0; 16];
940            let mut sw: [f32; QK_K / 16] = [0.0; QK_K / 16];
941            let mut ls: [u8; QK_K / 16] = [0; QK_K / 16];
942            let mut lm: [u8; QK_K / 16] = [0; QK_K / 16];
943
944            let sum_x2 = x.iter().map(|x| x * x).sum::<f32>();
945            let sigma2 = sum_x2 / QK_K as f32;
946            for (j, x_scale_slice) in x.as_chunks::<16>().0.iter().enumerate() {
947                for (l, (w_elem, x_elem)) in weights.iter_mut().zip(x_scale_slice).enumerate() {
948                    let imatrix_row = sblk_idx % (n_per_row / QK_K);
949                    let imatrix_w = imatrix_weights[imatrix_row * QK_K + 16 * j + l];
950                    *w_elem = imatrix_w * (sigma2 + x_elem * x_elem).sqrt();
951                }
952                let sumw = weights.iter().sum::<f32>();
953                sw[j] = sumw;
954                (scales[j], mins[j]) =
955                    make_qkx3_quants(3, x_scale_slice, Some(&weights), -0.9, 0.05, 36, false);
956            }
957
958            let d_block = make_qp_quants(QK_K / 16, 15, &scales, &mut ls, &sw);
959            let m_block = make_qp_quants(QK_K / 16, 15, &mins, &mut lm, &sw);
960
961            block.d = f16::from_f32(d_block);
962            block.dmin = f16::from_f32(m_block);
963
964            for j in 0..QK_K / 16 {
965                block.scales[j] = ls[j] | (lm[j] << 4);
966            }
967
968            let mut big_l: [u8; QK_K] = [0; QK_K];
969
970            for j in 0..QK_K / 16 {
971                let d = block.d.to_f32() * (block.scales[j] & 0xF) as f32;
972                if d == 0.0 {
973                    continue;
974                }
975                let dm = block.dmin.to_f32() * (block.scales[j] >> 4) as f32;
976                for ii in 0..16 {
977                    let ll = nearest_int((x[16 * j + ii] + dm) / d).clamp(0, 3);
978                    big_l[16 * j + ii] = ll as u8;
979                }
980            }
981
982            for j in (0..QK_K).step_by(128) {
983                for ll in 0..32 {
984                    block.qs[j / 4 + ll] = big_l[j + ll]
985                        | (big_l[j + ll + 32] << 2)
986                        | (big_l[j + ll + 64] << 4)
987                        | (big_l[j + ll + 96] << 6);
988                }
989            }
990        }
991    }
992    // https://github.com/ggerganov/llama.cpp/blob/8183159cf3def112f6d1fe94815fce70e1bffa12/k_quants.c#L354
993    fn to_float(xs: &[Self], ys: &mut [f32]) {
994        for (block, y) in group_for_dequantization(xs, ys) {
995            let d = block.d.to_f32();
996            let min = block.dmin.to_f32();
997
998            let mut is = 0;
999
1000            for (y_block, qs) in y
1001                .as_chunks_mut::<128>()
1002                .0
1003                .iter_mut()
1004                .zip(block.qs.as_chunks::<32>().0.iter())
1005            {
1006                // Step by 32 over q.
1007                let mut shift = 0;
1008                let mut y_block_index = 0;
1009                for _j in 0..4 {
1010                    let sc = block.scales[is];
1011                    is += 1;
1012                    let dl = d * (sc & 0xF) as f32;
1013                    let ml = min * (sc >> 4) as f32;
1014                    for q in &qs[..16] {
1015                        let y = dl * ((q >> shift) & 3) as f32 - ml;
1016                        y_block[y_block_index] = y;
1017                        y_block_index += 1;
1018                    }
1019
1020                    let sc = block.scales[is];
1021                    is += 1;
1022                    let dl = d * (sc & 0xF) as f32;
1023                    let ml = min * (sc >> 4) as f32;
1024                    for q in &qs[16..] {
1025                        let y = dl * ((q >> shift) & 3) as f32 - ml;
1026                        y_block[y_block_index] = y;
1027                        y_block_index += 1;
1028                    }
1029
1030                    shift += 2;
1031                }
1032            }
1033        }
1034    }
1035}
1036
1037impl GgmlType for BlockQ3K {
1038    const DTYPE: GgmlDType = GgmlDType::Q3K;
1039    const BLCK_SIZE: usize = QK_K;
1040    type VecDotType = BlockQ8K;
1041
1042    #[allow(unreachable_code)]
1043    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1044        #[cfg(target_feature = "avx2")]
1045        return super::avx::vec_dot_q3k_q8k(n, xs, ys);
1046
1047        #[cfg(target_feature = "neon")]
1048        return super::neon::vec_dot_q3k_q8k(n, xs, ys);
1049
1050        Self::vec_dot_unopt(n, xs, ys)
1051    }
1052
1053    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1054        debug_assert!(
1055            n.is_multiple_of(QK_K),
1056            "vec_dot_q3k_q8k: {n} is not divisible by {QK_K}"
1057        );
1058
1059        const KMASK1: u32 = 0x03030303;
1060        const KMASK2: u32 = 0x0f0f0f0f;
1061
1062        let mut aux8: [i8; QK_K] = [0; QK_K];
1063        let mut aux16: [i16; 8] = [0; 8];
1064        let mut sums: [f32; 8] = [0.0; 8];
1065        let mut aux32: [i32; 8] = [0; 8];
1066
1067        let mut auxs: [u32; 4] = [0; 4];
1068
1069        for (x, y) in xs.iter().zip(ys.iter()) {
1070            let mut q3: &[u8] = &x.qs;
1071            let hmask: &[u8] = &x.hmask;
1072            let mut q8: &[i8] = &y.qs;
1073
1074            aux32.fill(0);
1075            let mut a = &mut aux8[..];
1076
1077            let mut m = 1;
1078            //Like the GGML original this is written this way to enable the compiler to vectorize it.
1079            for _ in 0..QK_K / 128 {
1080                a.iter_mut()
1081                    .take(32)
1082                    .zip(q3)
1083                    .for_each(|(a_val, q3_val)| *a_val = (q3_val & 3) as i8);
1084                a.iter_mut()
1085                    .take(32)
1086                    .zip(hmask)
1087                    .for_each(|(a_val, hmask_val)| {
1088                        *a_val -= if hmask_val & m != 0 { 0 } else { 4 }
1089                    });
1090                a = &mut a[32..];
1091                m <<= 1;
1092
1093                a.iter_mut()
1094                    .take(32)
1095                    .zip(q3)
1096                    .for_each(|(a_val, q3_val)| *a_val = ((q3_val >> 2) & 3) as i8);
1097                a.iter_mut()
1098                    .take(32)
1099                    .zip(hmask)
1100                    .for_each(|(a_val, hmask_val)| {
1101                        *a_val -= if hmask_val & m != 0 { 0 } else { 4 }
1102                    });
1103                a = &mut a[32..];
1104                m <<= 1;
1105
1106                a.iter_mut()
1107                    .take(32)
1108                    .zip(q3)
1109                    .for_each(|(a_val, q3_val)| *a_val = ((q3_val >> 4) & 3) as i8);
1110                a.iter_mut()
1111                    .take(32)
1112                    .zip(hmask)
1113                    .for_each(|(a_val, hmask_val)| {
1114                        *a_val -= if hmask_val & m != 0 { 0 } else { 4 }
1115                    });
1116                a = &mut a[32..];
1117                m <<= 1;
1118
1119                a.iter_mut()
1120                    .take(32)
1121                    .zip(q3)
1122                    .for_each(|(a_val, q3_val)| *a_val = ((q3_val >> 6) & 3) as i8);
1123                a.iter_mut()
1124                    .take(32)
1125                    .zip(hmask)
1126                    .for_each(|(a_val, hmask_val)| {
1127                        *a_val -= if hmask_val & m != 0 { 0 } else { 4 }
1128                    });
1129                a = &mut a[32..];
1130                m <<= 1;
1131                q3 = &q3[32..];
1132            }
1133
1134            a = &mut aux8[..];
1135
1136            LittleEndian::read_u32_into(&x.scales, &mut auxs[0..3]);
1137
1138            let tmp = auxs[2];
1139            auxs[2] = ((auxs[0] >> 4) & KMASK2) | (((tmp >> 4) & KMASK1) << 4);
1140            auxs[3] = ((auxs[1] >> 4) & KMASK2) | (((tmp >> 6) & KMASK1) << 4);
1141            auxs[0] = (auxs[0] & KMASK2) | (((tmp) & KMASK1) << 4);
1142            auxs[1] = (auxs[1] & KMASK2) | (((tmp >> 2) & KMASK1) << 4);
1143
1144            for aux in auxs {
1145                for scale in aux.to_le_bytes() {
1146                    let scale = i8::from_be_bytes([scale]);
1147                    for l in 0..8 {
1148                        aux16[l] = q8[l] as i16 * a[l] as i16;
1149                    }
1150                    for l in 0..8 {
1151                        aux32[l] += (scale as i32 - 32) * aux16[l] as i32;
1152                    }
1153                    q8 = &q8[8..];
1154                    a = &mut a[8..];
1155
1156                    for l in 0..8 {
1157                        aux16[l] = q8[l] as i16 * a[l] as i16;
1158                    }
1159                    for l in 0..8 {
1160                        aux32[l] += (scale as i32 - 32) * aux16[l] as i32;
1161                    }
1162                    q8 = &q8[8..];
1163                    a = &mut a[8..];
1164                }
1165            }
1166            let d = x.d.to_f32() * y.d;
1167            for l in 0..8 {
1168                sums[l] += d * aux32[l] as f32;
1169            }
1170        }
1171
1172        sums.iter().sum()
1173    }
1174
1175    fn from_float(xs: &[f32], ys: &mut [Self]) {
1176        for (block, x) in group_for_quantization(xs, ys) {
1177            let mut scales: [f32; QK_K / 16] = [0.0; QK_K / 16];
1178            for (j, x_scale_slice) in x.as_chunks::<16>().0.iter().enumerate() {
1179                scales[j] = make_q3_quants(x_scale_slice, 4, true);
1180            }
1181
1182            // Get max scale by absolute value.
1183            let mut max_scale: f32 = 0.0;
1184            for &scale in scales.iter() {
1185                if scale.abs() > max_scale.abs() {
1186                    max_scale = scale;
1187                }
1188            }
1189
1190            block.scales.fill(0);
1191
1192            if max_scale != 0.0 {
1193                let iscale = -32.0 / max_scale;
1194                for (j, scale) in scales.iter().enumerate() {
1195                    let l_val = nearest_int(iscale * scale);
1196                    let l_val = l_val.clamp(-32, 31) + 32;
1197                    if j < 8 {
1198                        block.scales[j] = (l_val & 0xF) as u8;
1199                    } else {
1200                        block.scales[j - 8] |= ((l_val & 0xF) << 4) as u8;
1201                    }
1202                    let l_val = l_val >> 4;
1203                    block.scales[j % 4 + 8] |= (l_val << (2 * (j / 4))) as u8;
1204                }
1205                block.d = f16::from_f32(1.0 / iscale);
1206            } else {
1207                block.d = f16::from_f32(0.0);
1208            }
1209
1210            let mut l: [i8; QK_K] = [0; QK_K];
1211
1212            for j in 0..QK_K / 16 {
1213                let sc = if j < 8 {
1214                    block.scales[j] & 0xF
1215                } else {
1216                    block.scales[j - 8] >> 4
1217                };
1218                let sc = (sc | (((block.scales[8 + j % 4] >> (2 * (j / 4))) & 3) << 4)) as i8 - 32;
1219                let d = block.d.to_f32() * sc as f32;
1220                if d != 0.0 {
1221                    for ii in 0..16 {
1222                        let l_val = nearest_int(x[16 * j + ii] / d);
1223                        l[16 * j + ii] = (l_val.clamp(-4, 3) + 4) as i8;
1224                    }
1225                }
1226            }
1227
1228            block.hmask.fill(0);
1229            let mut m = 0;
1230            let mut hm = 1;
1231
1232            for ll in l.iter_mut() {
1233                if *ll > 3 {
1234                    block.hmask[m] |= hm;
1235                    *ll -= 4;
1236                }
1237                m += 1;
1238                if m == QK_K / 8 {
1239                    m = 0;
1240                    hm <<= 1;
1241                }
1242            }
1243
1244            for j in (0..QK_K).step_by(128) {
1245                for l_val in 0..32 {
1246                    block.qs[j / 4 + l_val] = (l[j + l_val]
1247                        | (l[j + l_val + 32] << 2)
1248                        | (l[j + l_val + 64] << 4)
1249                        | (l[j + l_val + 96] << 6))
1250                        as u8;
1251                }
1252            }
1253        }
1254    }
1255
1256    fn from_float_imatrix(xs: &[f32], ys: &mut [Self], imatrix_weights: &[f32], n_per_row: usize) {
1257        for (sblk_idx, (block, x)) in group_for_quantization(xs, ys).into_iter().enumerate() {
1258            let mut scales: [f32; QK_K / 16] = [0.0; QK_K / 16];
1259            let mut weights: [f32; 16] = [0.0; 16];
1260            let mut sw: [f32; QK_K / 16] = [0.0; QK_K / 16];
1261            let mut ls: [i8; QK_K / 16] = [0; QK_K / 16];
1262            let mut l: [i8; QK_K] = [0; QK_K];
1263
1264            let sum_x2 = x.iter().map(|x| x * x).sum::<f32>();
1265            let sigma2 = 2. * sum_x2 / QK_K as f32;
1266
1267            for (j, x_scale_slice) in x.as_chunks::<16>().0.iter().enumerate() {
1268                for (l_idx, (w_elem, x_elem)) in weights.iter_mut().zip(x_scale_slice).enumerate() {
1269                    let imatrix_row = sblk_idx % (n_per_row / QK_K);
1270                    let imatrix_w = imatrix_weights[imatrix_row * QK_K + 16 * j + l_idx];
1271                    *w_elem = imatrix_w * (sigma2 + x_elem * x_elem).sqrt();
1272                }
1273                let sumw = weights.iter().sum::<f32>();
1274                sw[j] = sumw;
1275                scales[j] = unsafe {
1276                    make_qx_quants(
1277                        16,
1278                        4,
1279                        x_scale_slice.as_ptr(),
1280                        l.as_mut_ptr().add(16 * j),
1281                        1,
1282                        weights.as_ptr(),
1283                    )
1284                };
1285            }
1286
1287            block.scales.fill(0);
1288            let d_block = unsafe {
1289                make_qx_quants(
1290                    QK_K / 16,
1291                    32,
1292                    scales.as_ptr(),
1293                    ls.as_mut_ptr(),
1294                    1,
1295                    sw.as_ptr(),
1296                )
1297            };
1298            block.d = f16::from_f32(d_block);
1299            for (j, l_val) in ls.iter().enumerate().take(QK_K / 16) {
1300                if j < 8 {
1301                    block.scales[j] = (l_val & 0xF) as u8;
1302                } else {
1303                    block.scales[j - 8] |= ((l_val & 0xF) << 4) as u8;
1304                }
1305                let l_val = l_val >> 4;
1306                block.scales[j % 4 + 8] |= (l_val << (2 * (j / 4))) as u8;
1307            }
1308
1309            for j in 0..QK_K / 16 {
1310                let sc = if j < 8 {
1311                    block.scales[j] & 0xF
1312                } else {
1313                    block.scales[j - 8] >> 4
1314                };
1315                let sc = (sc | (((block.scales[8 + j % 4] >> (2 * (j / 4))) & 3) << 4)) as i8 - 32;
1316                let d = block.d.to_f32() * sc as f32;
1317                if d != 0.0 {
1318                    for ii in 0..16 {
1319                        let l_val = nearest_int(x[16 * j + ii] / d);
1320                        l[16 * j + ii] = (l_val.clamp(-4, 3) + 4) as i8;
1321                    }
1322                }
1323            }
1324
1325            block.hmask.fill(0);
1326            let mut m = 0;
1327            let mut hm = 1;
1328
1329            for ll in l.iter_mut() {
1330                if *ll > 3 {
1331                    block.hmask[m] |= hm;
1332                    *ll -= 4;
1333                }
1334                m += 1;
1335                if m == QK_K / 8 {
1336                    m = 0;
1337                    hm <<= 1;
1338                }
1339            }
1340
1341            for j in (0..QK_K).step_by(128) {
1342                for l_val in 0..32 {
1343                    block.qs[j / 4 + l_val] = (l[j + l_val]
1344                        | (l[j + l_val + 32] << 2)
1345                        | (l[j + l_val + 64] << 4)
1346                        | (l[j + l_val + 96] << 6))
1347                        as u8;
1348                }
1349            }
1350        }
1351    }
1352
1353    // https://github.com/ggerganov/llama.cpp/blob/8183159cf3def112f6d1fe94815fce70e1bffa12/k_quants.c#L533
1354    fn to_float(xs: &[Self], ys: &mut [f32]) {
1355        const KMASK1: u32 = 0x03030303;
1356        const KMASK2: u32 = 0x0f0f0f0f;
1357
1358        for (block, y) in group_for_dequantization(xs, ys) {
1359            //Reconstruct the scales
1360            let mut aux = [0; 4];
1361            LittleEndian::read_u32_into(&block.scales, &mut aux[0..3]);
1362
1363            let tmp = aux[2];
1364            aux[2] = ((aux[0] >> 4) & KMASK2) | (((tmp >> 4) & KMASK1) << 4);
1365            aux[3] = ((aux[1] >> 4) & KMASK2) | (((tmp >> 6) & KMASK1) << 4);
1366            aux[0] = (aux[0] & KMASK2) | (((tmp) & KMASK1) << 4);
1367            aux[1] = (aux[1] & KMASK2) | (((tmp >> 2) & KMASK1) << 4);
1368
1369            //Transfer the scales into an i8 array
1370            let scales: &mut [i8] =
1371                unsafe { std::slice::from_raw_parts_mut(aux.as_mut_ptr() as *mut i8, 16) };
1372
1373            let d_all = block.d.to_f32();
1374            let mut m = 1;
1375            let mut is = 0;
1376
1377            // Dequantize both 128 long blocks
1378            // 32 qs values per 128 long block
1379            // Each 16 elements get a scale
1380            for (y, qs) in y
1381                .as_chunks_mut::<128>()
1382                .0
1383                .iter_mut()
1384                .zip(block.qs.as_chunks::<32>().0.iter())
1385            {
1386                let mut shift = 0;
1387                for shift_scoped_y in y.as_chunks_mut::<32>().0.iter_mut() {
1388                    for (scale_index, scale_scoped_y) in shift_scoped_y
1389                        .as_chunks_mut::<16>()
1390                        .0
1391                        .iter_mut()
1392                        .enumerate()
1393                    {
1394                        let dl = d_all * (scales[is] as f32 - 32.0);
1395                        for (i, inner_y) in scale_scoped_y.iter_mut().enumerate() {
1396                            let new_y = dl
1397                                * (((qs[i + 16 * scale_index] >> shift) & 3) as i8
1398                                    - if (block.hmask[i + 16 * scale_index] & m) == 0 {
1399                                        4
1400                                    } else {
1401                                        0
1402                                    }) as f32;
1403                            *inner_y = new_y;
1404                        }
1405                        // 16 block finished => advance scale index
1406                        is += 1;
1407                    }
1408                    // 32 block finished => increase shift and m
1409                    shift += 2;
1410                    m <<= 1;
1411                }
1412            }
1413        }
1414    }
1415}
1416
1417impl GgmlType for BlockQ4K {
1418    const DTYPE: GgmlDType = GgmlDType::Q4K;
1419    const BLCK_SIZE: usize = QK_K;
1420    type VecDotType = BlockQ8K;
1421
1422    #[allow(unreachable_code)]
1423    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1424        #[cfg(target_feature = "avx2")]
1425        return super::avx::vec_dot_q4k_q8k(n, xs, ys);
1426
1427        #[cfg(target_feature = "neon")]
1428        return super::neon::vec_dot_q4k_q8k(n, xs, ys);
1429
1430        Self::vec_dot_unopt(n, xs, ys)
1431    }
1432
1433    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1434        debug_assert!(
1435            n.is_multiple_of(QK_K),
1436            "vec_dot_q4k_q8k: {n} is not divisible by {QK_K}"
1437        );
1438
1439        const KMASK1: u32 = 0x3f3f3f3f;
1440        const KMASK2: u32 = 0x0f0f0f0f;
1441        const KMASK3: u32 = 0x03030303;
1442
1443        let mut utmp: [u32; 4] = [0; 4];
1444        let mut scales: [u8; 8] = [0; 8];
1445        let mut mins: [u8; 8] = [0; 8];
1446
1447        let mut aux8: [i8; QK_K] = [0; QK_K];
1448        let mut aux16: [i16; 8] = [0; 8];
1449        let mut sums: [f32; 8] = [0.0; 8];
1450        let mut aux32: [i32; 8] = [0; 8];
1451
1452        let mut sumf = 0.0;
1453        for (y, x) in ys.iter().zip(xs.iter()) {
1454            let q4 = &x.qs;
1455            let q8 = &y.qs;
1456            aux32.fill(0);
1457
1458            let mut a = &mut aux8[..];
1459            let mut q4 = &q4[..];
1460            for _ in 0..QK_K / 64 {
1461                for l in 0..32 {
1462                    a[l] = (q4[l] & 0xF) as i8;
1463                }
1464                a = &mut a[32..];
1465                for l in 0..32 {
1466                    a[l] = (q4[l] >> 4) as i8;
1467                }
1468                a = &mut a[32..];
1469                q4 = &q4[32..];
1470            }
1471
1472            LittleEndian::read_u32_into(&x.scales, &mut utmp[0..3]);
1473
1474            utmp[3] = ((utmp[2] >> 4) & KMASK2) | (((utmp[1] >> 6) & KMASK3) << 4);
1475            let uaux = utmp[1] & KMASK1;
1476            utmp[1] = (utmp[2] & KMASK2) | (((utmp[0] >> 6) & KMASK3) << 4);
1477            utmp[2] = uaux;
1478            utmp[0] &= KMASK1;
1479
1480            //extract scales and mins
1481            LittleEndian::write_u32_into(&utmp[0..2], &mut scales);
1482            LittleEndian::write_u32_into(&utmp[2..4], &mut mins);
1483
1484            let mut sumi = 0;
1485            for j in 0..QK_K / 16 {
1486                sumi += y.bsums[j] as i32 * mins[j / 2] as i32;
1487            }
1488
1489            let mut a = &mut aux8[..];
1490            let mut q8 = &q8[..];
1491
1492            for scale in scales {
1493                let scale = scale as i32;
1494                for _ in 0..4 {
1495                    for l in 0..8 {
1496                        aux16[l] = q8[l] as i16 * a[l] as i16;
1497                    }
1498                    for l in 0..8 {
1499                        aux32[l] += scale * aux16[l] as i32;
1500                    }
1501                    q8 = &q8[8..];
1502                    a = &mut a[8..];
1503                }
1504            }
1505            let d = x.d.to_f32() * y.d;
1506            for l in 0..8 {
1507                sums[l] += d * aux32[l] as f32;
1508            }
1509            let dmin = x.dmin.to_f32() * y.d;
1510            sumf -= dmin * sumi as f32;
1511        }
1512        sumf + sums.iter().sum::<f32>()
1513    }
1514
1515    fn from_float(xs: &[f32], ys: &mut [Self]) {
1516        for (block, x) in group_for_quantization(xs, ys) {
1517            let mut mins: [f32; QK_K / 32] = [0.0; QK_K / 32];
1518            let mut scales: [f32; QK_K / 32] = [0.0; QK_K / 32];
1519
1520            for (j, x_scale_slice) in x.as_chunks::<32>().0.iter().enumerate() {
1521                (scales[j], mins[j]) = make_qkx1_quants(15, 5, x_scale_slice);
1522            }
1523
1524            // get max scale and max min and ensure they are >= 0.0
1525            let max_scale = scales.iter().fold(0.0, |max, &val| val.max(max));
1526            let max_min = mins.iter().fold(0.0, |max, &val| val.max(max));
1527
1528            let inv_scale = if max_scale > 0.0 {
1529                63.0 / max_scale
1530            } else {
1531                0.0
1532            };
1533            let inv_min = if max_min > 0.0 { 63.0 / max_min } else { 0.0 };
1534
1535            for j in 0..QK_K / 32 {
1536                let ls = nearest_int(inv_scale * scales[j]).min(63) as u8;
1537                let lm = nearest_int(inv_min * mins[j]).min(63) as u8;
1538                if j < 4 {
1539                    block.scales[j] = ls;
1540                    block.scales[j + 4] = lm;
1541                } else {
1542                    block.scales[j + 4] = (ls & 0xF) | ((lm & 0xF) << 4);
1543                    block.scales[j - 4] |= (ls >> 4) << 6;
1544                    block.scales[j] |= (lm >> 4) << 6;
1545                }
1546            }
1547
1548            block.d = f16::from_f32(max_scale / 63.0);
1549            block.dmin = f16::from_f32(max_min / 63.0);
1550
1551            let mut l: [u8; QK_K] = [0; QK_K];
1552
1553            for j in 0..QK_K / 32 {
1554                let (sc, m) = get_scale_min_k4(j, &block.scales);
1555                let d = block.d.to_f32() * sc as f32;
1556                if d != 0.0 {
1557                    let dm = block.dmin.to_f32() * m as f32;
1558                    for ii in 0..32 {
1559                        let l_val = nearest_int((x[32 * j + ii] + dm) / d);
1560                        l[32 * j + ii] = l_val.clamp(0, 15) as u8;
1561                    }
1562                }
1563            }
1564
1565            let q = &mut block.qs;
1566            for j in (0..QK_K).step_by(64) {
1567                for l_val in 0..32 {
1568                    let offset_index = (j / 64) * 32 + l_val;
1569                    q[offset_index] = l[j + l_val] | (l[j + l_val + 32] << 4);
1570                }
1571            }
1572        }
1573    }
1574
1575    fn from_float_imatrix(xs: &[f32], ys: &mut [Self], imatrix_weights: &[f32], n_per_row: usize) {
1576        for (sblk_idx, (block, x)) in group_for_quantization(xs, ys).into_iter().enumerate() {
1577            let mut mins: [f32; QK_K / 32] = [0.0; QK_K / 32];
1578            let mut scales: [f32; QK_K / 32] = [0.0; QK_K / 32];
1579            let mut weights: [f32; 32] = [0.0; 32];
1580            let mut sw: [f32; QK_K / 32] = [0.0; QK_K / 32];
1581            let mut ls: [u8; QK_K / 32] = [0; QK_K / 32];
1582            let mut lm: [u8; QK_K / 32] = [0; QK_K / 32];
1583
1584            let sum_x2 = x.iter().map(|x| x * x).sum::<f32>();
1585            let sigma2 = 2. * sum_x2 / QK_K as f32;
1586
1587            for (j, x_scale_slice) in x.as_chunks::<32>().0.iter().enumerate() {
1588                for (l, (w_elem, x_elem)) in weights.iter_mut().zip(x_scale_slice).enumerate() {
1589                    let imatrix_row = sblk_idx % (n_per_row / QK_K);
1590                    let imatrix_w = imatrix_weights[imatrix_row * QK_K + 32 * j + l];
1591                    *w_elem = imatrix_w * (sigma2 + x_elem * x_elem).sqrt();
1592                }
1593                let sumw = weights.iter().sum::<f32>();
1594                sw[j] = sumw;
1595                (scales[j], mins[j]) =
1596                    make_qkx3_quants(15, x_scale_slice, Some(&weights), -0.9, 0.05, 36, false);
1597            }
1598
1599            let d_block = make_qp_quants(QK_K / 32, 63, &scales, &mut ls, &sw);
1600            let m_block = make_qp_quants(QK_K / 32, 63, &mins, &mut lm, &sw);
1601            for j in 0..QK_K / 32 {
1602                let ls_val = ls[j];
1603                let lm_val = lm[j];
1604                if j < 4 {
1605                    block.scales[j] = ls_val;
1606                    block.scales[j + 4] = lm_val;
1607                } else {
1608                    block.scales[j + 4] = (ls_val & 0xF) | ((lm_val & 0xF) << 4);
1609                    block.scales[j - 4] |= (ls_val >> 4) << 6;
1610                    block.scales[j] |= (lm_val >> 4) << 6;
1611                }
1612            }
1613
1614            block.d = f16::from_f32(d_block);
1615            block.dmin = f16::from_f32(m_block);
1616
1617            let mut l: [u8; QK_K] = [0; QK_K];
1618            for j in 0..QK_K / 32 {
1619                let (sc, m) = get_scale_min_k4(j, &block.scales);
1620                let d = block.d.to_f32() * sc as f32;
1621                if d != 0.0 {
1622                    let dm = block.dmin.to_f32() * m as f32;
1623                    for ii in 0..32 {
1624                        let l_val = nearest_int((x[32 * j + ii] + dm) / d);
1625                        l[32 * j + ii] = l_val.clamp(0, 15) as u8;
1626                    }
1627                }
1628            }
1629
1630            let q = &mut block.qs;
1631            for j in (0..QK_K).step_by(64) {
1632                for l_val in 0..32 {
1633                    let offset_index = (j / 64) * 32 + l_val;
1634                    q[offset_index] = l[j + l_val] | (l[j + l_val + 32] << 4);
1635                }
1636            }
1637        }
1638    }
1639    // https://github.com/ggerganov/llama.cpp/blob/8183159cf3def112f6d1fe94815fce70e1bffa12/k_quants.c#L735
1640    fn to_float(xs: &[Self], ys: &mut [f32]) {
1641        for (block, y) in group_for_dequantization(xs, ys) {
1642            let d = block.d.to_f32();
1643            let min = block.dmin.to_f32();
1644            let q = &block.qs;
1645            let mut is = 0;
1646            let mut ys_index = 0;
1647
1648            for j in (0..QK_K).step_by(64) {
1649                let q = &q[j / 2..j / 2 + 32];
1650                let (sc, m) = get_scale_min_k4(is, &block.scales);
1651                let d1 = d * sc as f32;
1652                let m1 = min * m as f32;
1653                let (sc, m) = get_scale_min_k4(is + 1, &block.scales);
1654                let d2 = d * sc as f32;
1655                let m2 = min * m as f32;
1656                for q in q {
1657                    y[ys_index] = d1 * (q & 0xF) as f32 - m1;
1658                    ys_index += 1;
1659                }
1660                for q in q {
1661                    y[ys_index] = d2 * (q >> 4) as f32 - m2;
1662                    ys_index += 1;
1663                }
1664                is += 2;
1665            }
1666        }
1667    }
1668}
1669
1670// https://github.com/ggerganov/llama.cpp/blob/8183159cf3def112f6d1fe94815fce70e1bffa12/k_quants.c#L928
1671impl GgmlType for BlockQ5K {
1672    const DTYPE: GgmlDType = GgmlDType::Q5K;
1673    const BLCK_SIZE: usize = QK_K;
1674    type VecDotType = BlockQ8K;
1675
1676    #[allow(unreachable_code)]
1677    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1678        #[cfg(target_feature = "avx2")]
1679        return super::avx::vec_dot_q5k_q8k(n, xs, ys);
1680
1681        #[cfg(target_feature = "neon")]
1682        return super::neon::vec_dot_q5k_q8k(n, xs, ys);
1683
1684        Self::vec_dot_unopt(n, xs, ys)
1685    }
1686
1687    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1688        debug_assert!(
1689            n.is_multiple_of(QK_K),
1690            "vec_dot_q5k_q8k: {n} is not divisible by {QK_K}"
1691        );
1692
1693        const KMASK1: u32 = 0x3f3f3f3f;
1694        const KMASK2: u32 = 0x0f0f0f0f;
1695        const KMASK3: u32 = 0x03030303;
1696
1697        let mut utmp: [u32; 4] = [0; 4];
1698        let mut scales: [u8; 8] = [0; 8];
1699        let mut mins: [u8; 8] = [0; 8];
1700
1701        let mut aux8: [i8; QK_K] = [0; QK_K];
1702        let mut aux16: [i16; 8] = [0; 8];
1703        let mut sums: [f32; 8] = [0.0; 8];
1704        let mut aux32: [i32; 8] = [0; 8];
1705
1706        let mut sumf = 0.0;
1707        for (y, x) in ys.iter().zip(xs.iter()) {
1708            let q5 = &x.qs;
1709            let hm = &x.qh;
1710            let q8 = &y.qs;
1711            aux32.fill(0);
1712
1713            let mut a = &mut aux8[..];
1714            let mut q5 = &q5[..];
1715            let mut m = 1u8;
1716
1717            for _ in 0..QK_K / 64 {
1718                for l in 0..32 {
1719                    a[l] = (q5[l] & 0xF) as i8;
1720                    a[l] += if hm[l] & m != 0 { 16 } else { 0 };
1721                }
1722                a = &mut a[32..];
1723                m <<= 1;
1724                for l in 0..32 {
1725                    a[l] = (q5[l] >> 4) as i8;
1726                    a[l] += if hm[l] & m != 0 { 16 } else { 0 };
1727                }
1728                a = &mut a[32..];
1729                m <<= 1;
1730                q5 = &q5[32..];
1731            }
1732
1733            LittleEndian::read_u32_into(&x.scales, &mut utmp[0..3]);
1734
1735            utmp[3] = ((utmp[2] >> 4) & KMASK2) | (((utmp[1] >> 6) & KMASK3) << 4);
1736            let uaux = utmp[1] & KMASK1;
1737            utmp[1] = (utmp[2] & KMASK2) | (((utmp[0] >> 6) & KMASK3) << 4);
1738            utmp[2] = uaux;
1739            utmp[0] &= KMASK1;
1740
1741            //extract scales and mins
1742            LittleEndian::write_u32_into(&utmp[0..2], &mut scales);
1743            LittleEndian::write_u32_into(&utmp[2..4], &mut mins);
1744
1745            let mut sumi = 0;
1746            for j in 0..QK_K / 16 {
1747                sumi += y.bsums[j] as i32 * mins[j / 2] as i32;
1748            }
1749
1750            let mut a = &mut aux8[..];
1751            let mut q8 = &q8[..];
1752
1753            for scale in scales {
1754                let scale = scale as i32;
1755                for _ in 0..4 {
1756                    for l in 0..8 {
1757                        aux16[l] = q8[l] as i16 * a[l] as i16;
1758                    }
1759                    for l in 0..8 {
1760                        aux32[l] += scale * aux16[l] as i32;
1761                    }
1762                    q8 = &q8[8..];
1763                    a = &mut a[8..];
1764                }
1765            }
1766            let d = x.d.to_f32() * y.d;
1767            for l in 0..8 {
1768                sums[l] += d * aux32[l] as f32;
1769            }
1770            let dmin = x.dmin.to_f32() * y.d;
1771            sumf -= dmin * sumi as f32;
1772        }
1773        sumf + sums.iter().sum::<f32>()
1774    }
1775
1776    // https://github.com/ggerganov/llama.cpp/blob/8183159cf3def112f6d1fe94815fce70e1bffa12/k_quants.c#L793
1777    fn from_float(xs: &[f32], ys: &mut [Self]) {
1778        for (block, x) in group_for_quantization(xs, ys) {
1779            let mut mins: [f32; QK_K / 32] = [0.0; QK_K / 32];
1780            let mut scales: [f32; QK_K / 32] = [0.0; QK_K / 32];
1781
1782            for (j, x_scale_slice) in x.as_chunks::<32>().0.iter().enumerate() {
1783                (scales[j], mins[j]) = make_qkx1_quants(31, 5, x_scale_slice);
1784            }
1785
1786            // get max scale and max min and ensure they are >= 0.0
1787            let max_scale = scales.iter().fold(0.0, |max, &val| val.max(max));
1788            let max_min = mins.iter().fold(0.0, |max, &val| val.max(max));
1789
1790            let inv_scale = if max_scale > 0.0 {
1791                63.0 / max_scale
1792            } else {
1793                0.0
1794            };
1795            let inv_min = if max_min > 0.0 { 63.0 / max_min } else { 0.0 };
1796            for j in 0..QK_K / 32 {
1797                let ls = nearest_int(inv_scale * scales[j]).min(63) as u8;
1798                let lm = nearest_int(inv_min * mins[j]).min(63) as u8;
1799                if j < 4 {
1800                    block.scales[j] = ls;
1801                    block.scales[j + 4] = lm;
1802                } else {
1803                    block.scales[j + 4] = (ls & 0xF) | ((lm & 0xF) << 4);
1804                    block.scales[j - 4] |= (ls >> 4) << 6;
1805                    block.scales[j] |= (lm >> 4) << 6;
1806                }
1807            }
1808            block.d = f16::from_f32(max_scale / 63.0);
1809            block.dmin = f16::from_f32(max_min / 63.0);
1810
1811            let mut l: [u8; QK_K] = [0; QK_K];
1812            for j in 0..QK_K / 32 {
1813                let (sc, m) = get_scale_min_k4(j, &block.scales);
1814                let d = block.d.to_f32() * sc as f32;
1815                if d == 0.0 {
1816                    continue;
1817                }
1818                let dm = block.dmin.to_f32() * m as f32;
1819                for ii in 0..32 {
1820                    let ll = nearest_int((x[32 * j + ii] + dm) / d);
1821                    l[32 * j + ii] = ll.clamp(0, 31) as u8;
1822                }
1823            }
1824
1825            let qh = &mut block.qh;
1826            let ql = &mut block.qs;
1827            qh.fill(0);
1828
1829            let mut m1 = 1;
1830            let mut m2 = 2;
1831            for n in (0..QK_K).step_by(64) {
1832                let offset = (n / 64) * 32;
1833                for j in 0..32 {
1834                    let mut l1 = l[n + j];
1835                    if l1 > 15 {
1836                        l1 -= 16;
1837                        qh[j] |= m1;
1838                    }
1839                    let mut l2 = l[n + j + 32];
1840                    if l2 > 15 {
1841                        l2 -= 16;
1842                        qh[j] |= m2;
1843                    }
1844                    ql[offset + j] = l1 | (l2 << 4);
1845                }
1846                m1 <<= 2;
1847                m2 <<= 2;
1848            }
1849        }
1850    }
1851
1852    fn from_float_imatrix(xs: &[f32], ys: &mut [Self], imatrix_weights: &[f32], n_per_row: usize) {
1853        for (sblk_idx, (block, x)) in group_for_quantization(xs, ys).into_iter().enumerate() {
1854            let mut mins: [f32; QK_K / 32] = [0.0; QK_K / 32];
1855            let mut scales: [f32; QK_K / 32] = [0.0; QK_K / 32];
1856            let mut weights: [f32; 32] = [0.0; 32];
1857            let mut sw: [f32; QK_K / 32] = [0.0; QK_K / 32];
1858            let mut ls: [u8; QK_K / 32] = [0; QK_K / 32];
1859            let mut lm: [u8; QK_K / 32] = [0; QK_K / 32];
1860
1861            let sum_x2 = x.iter().map(|x| x * x).sum::<f32>();
1862            let sigma2 = 2. * sum_x2 / QK_K as f32;
1863
1864            for (j, x_scale_slice) in x.as_chunks::<32>().0.iter().enumerate() {
1865                for (l, (w_elem, x_elem)) in weights.iter_mut().zip(x_scale_slice).enumerate() {
1866                    let imatrix_row = sblk_idx % (n_per_row / QK_K);
1867                    let imatrix_w = imatrix_weights[imatrix_row * QK_K + 32 * j + l];
1868                    *w_elem = imatrix_w * (sigma2 + x_elem * x_elem).sqrt();
1869                }
1870                let sumw = weights.iter().sum::<f32>();
1871                sw[j] = sumw;
1872                (scales[j], mins[j]) =
1873                    make_qkx3_quants(31, x_scale_slice, Some(&weights), -0.9, 0.05, 36, false);
1874            }
1875
1876            let d_block = make_qp_quants(QK_K / 32, 63, &scales, &mut ls, &sw);
1877            let m_block = make_qp_quants(QK_K / 32, 63, &mins, &mut lm, &sw);
1878            for j in 0..QK_K / 32 {
1879                let ls_val = ls[j].min(63);
1880                let lm_val = lm[j].min(63);
1881                if j < 4 {
1882                    block.scales[j] = ls_val;
1883                    block.scales[j + 4] = lm_val;
1884                } else {
1885                    block.scales[j + 4] = (ls_val & 0xF) | ((lm_val & 0xF) << 4);
1886                    block.scales[j - 4] |= (ls_val >> 4) << 6;
1887                    block.scales[j] |= (lm_val >> 4) << 6;
1888                }
1889            }
1890
1891            block.d = f16::from_f32(d_block);
1892            block.dmin = f16::from_f32(m_block);
1893
1894            let mut l: [u8; QK_K] = [0; QK_K];
1895            for j in 0..QK_K / 32 {
1896                let (sc, m) = get_scale_min_k4(j, &block.scales);
1897                let d = block.d.to_f32() * sc as f32;
1898                if d != 0.0 {
1899                    let dm = block.dmin.to_f32() * m as f32;
1900                    for ii in 0..32 {
1901                        let l_val = nearest_int((x[32 * j + ii] + dm) / d);
1902                        l[32 * j + ii] = l_val.clamp(0, 31) as u8;
1903                    }
1904                }
1905            }
1906
1907            let qh = &mut block.qh;
1908            let ql = &mut block.qs;
1909            qh.fill(0);
1910
1911            let mut m1 = 1;
1912            let mut m2 = 2;
1913            for n in (0..QK_K).step_by(64) {
1914                let offset = (n / 64) * 32;
1915                for j in 0..32 {
1916                    let mut l1 = l[n + j];
1917                    if l1 > 15 {
1918                        l1 -= 16;
1919                        qh[j] |= m1;
1920                    }
1921                    let mut l2 = l[n + j + 32];
1922                    if l2 > 15 {
1923                        l2 -= 16;
1924                        qh[j] |= m2;
1925                    }
1926                    ql[offset + j] = l1 | (l2 << 4);
1927                }
1928                m1 <<= 2;
1929                m2 <<= 2;
1930            }
1931        }
1932    }
1933
1934    // https://github.com/ggerganov/llama.cpp/blob/8183159cf3def112f6d1fe94815fce70e1bffa12/k_quants.c#L928
1935    fn to_float(xs: &[Self], ys: &mut [f32]) {
1936        for (block, y) in group_for_dequantization(xs, ys) {
1937            let d = block.d.to_f32();
1938            let min = block.dmin.to_f32();
1939            let ql = &block.qs;
1940            let qh = &block.qh;
1941            let mut is = 0;
1942            let mut u1 = 1;
1943            let mut u2 = 2;
1944            let mut ys_index = 0;
1945
1946            for j in (0..QK_K).step_by(64) {
1947                let ql = &ql[j / 2..j / 2 + 32];
1948                let (sc, m) = get_scale_min_k4(is, &block.scales);
1949                let d1 = d * sc as f32;
1950                let m1 = min * m as f32;
1951                let (sc, m) = get_scale_min_k4(is + 1, &block.scales);
1952                let d2 = d * sc as f32;
1953                let m2 = min * m as f32;
1954                for (ql, qh) in ql.iter().zip(qh) {
1955                    let to_add = if qh & u1 != 0 { 16f32 } else { 0f32 };
1956                    y[ys_index] = d1 * ((ql & 0xF) as f32 + to_add) - m1;
1957                    ys_index += 1;
1958                }
1959                for (ql, qh) in ql.iter().zip(qh) {
1960                    let to_add = if qh & u2 != 0 { 16f32 } else { 0f32 };
1961                    y[ys_index] = d2 * ((ql >> 4) as f32 + to_add) - m2;
1962                    ys_index += 1;
1963                }
1964                is += 2;
1965                u1 <<= 2;
1966                u2 <<= 2;
1967            }
1968        }
1969    }
1970}
1971
1972impl GgmlType for BlockQ6K {
1973    const DTYPE: GgmlDType = GgmlDType::Q6K;
1974    const BLCK_SIZE: usize = QK_K;
1975    type VecDotType = BlockQ8K;
1976
1977    #[allow(unreachable_code)]
1978    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1979        #[cfg(target_feature = "avx2")]
1980        return super::avx::vec_dot_q6k_q8k(n, xs, ys);
1981
1982        #[cfg(target_feature = "neon")]
1983        return super::neon::vec_dot_q6k_q8k(n, xs, ys);
1984
1985        Self::vec_dot_unopt(n, xs, ys)
1986    }
1987
1988    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
1989        debug_assert!(
1990            n.is_multiple_of(QK_K),
1991            "vec_dot_q6k_q8k: {n} is not divisible by {QK_K}"
1992        );
1993
1994        let mut aux8 = [0i8; QK_K];
1995        let mut aux16 = [0i16; 8];
1996        let mut sums = [0f32; 8];
1997        let mut aux32 = [0f32; 8];
1998
1999        for (x, y) in xs.iter().zip(ys.iter()) {
2000            let q4 = &x.ql;
2001            let qh = &x.qh;
2002            let q8 = &y.qs;
2003            aux32.fill(0f32);
2004
2005            for j in (0..QK_K).step_by(128) {
2006                let aux8 = &mut aux8[j..];
2007                let q4 = &q4[j / 2..];
2008                let qh = &qh[j / 4..];
2009                for l in 0..32 {
2010                    aux8[l] = (((q4[l] & 0xF) | ((qh[l] & 3) << 4)) as i32 - 32) as i8;
2011                    aux8[l + 32] =
2012                        (((q4[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) as i32 - 32) as i8;
2013                    aux8[l + 64] = (((q4[l] >> 4) | (((qh[l] >> 4) & 3) << 4)) as i32 - 32) as i8;
2014                    aux8[l + 96] =
2015                        (((q4[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) as i32 - 32) as i8;
2016                }
2017            }
2018
2019            for (j, &scale) in x.scales.iter().enumerate() {
2020                let scale = scale as f32;
2021                let q8 = &q8[16 * j..];
2022                let aux8 = &aux8[16 * j..];
2023                for l in 0..8 {
2024                    aux16[l] = q8[l] as i16 * aux8[l] as i16;
2025                }
2026                for l in 0..8 {
2027                    aux32[l] += scale * aux16[l] as f32
2028                }
2029                let q8 = &q8[8..];
2030                let aux8 = &aux8[8..];
2031                for l in 0..8 {
2032                    aux16[l] = q8[l] as i16 * aux8[l] as i16;
2033                }
2034                for l in 0..8 {
2035                    aux32[l] += scale * aux16[l] as f32
2036                }
2037            }
2038
2039            let d = x.d.to_f32() * y.d;
2040            for (sum, &a) in sums.iter_mut().zip(aux32.iter()) {
2041                *sum += a * d;
2042            }
2043        }
2044        sums.iter().sum()
2045    }
2046
2047    fn from_float(xs: &[f32], ys: &mut [Self]) {
2048        debug_assert_eq!(
2049            xs.len(),
2050            ys.len() * Self::BLCK_SIZE,
2051            "quantize_row_q6k: size mismatch {} {} {}",
2052            xs.len(),
2053            ys.len(),
2054            Self::BLCK_SIZE
2055        );
2056        let mut l = [0i8; QK_K];
2057        let mut scales = [0f32; QK_K / 16];
2058        let mut x = xs.as_ptr();
2059        let l = l.as_mut_ptr();
2060        unsafe {
2061            for y in ys.iter_mut() {
2062                let mut max_scale = 0f32;
2063                let mut max_abs_scale = 0f32;
2064                for (ib, scale_) in scales.iter_mut().enumerate() {
2065                    let scale =
2066                        make_qx_quants(16, 32, x.add(16 * ib), l.add(16 * ib), 1, std::ptr::null());
2067                    *scale_ = scale;
2068                    let abs_scale = scale.abs();
2069                    if abs_scale > max_abs_scale {
2070                        max_abs_scale = abs_scale;
2071                        max_scale = scale
2072                    }
2073                }
2074
2075                let iscale = -128f32 / max_scale;
2076                y.d = f16::from_f32(1.0 / iscale);
2077
2078                for (y_scale, scale) in y.scales.iter_mut().zip(scales.iter()) {
2079                    *y_scale = nearest_int(iscale * scale).min(127) as i8
2080                }
2081
2082                for (j, &y_scale) in y.scales.iter().enumerate() {
2083                    let d = y.d.to_f32() * y_scale as f32;
2084                    if d == 0. {
2085                        continue;
2086                    }
2087                    for ii in 0..16 {
2088                        let ll = nearest_int(*x.add(16 * j + ii) / d).clamp(-32, 31);
2089                        *l.add(16 * j + ii) = (ll + 32) as i8
2090                    }
2091                }
2092
2093                let mut ql = y.ql.as_mut_ptr();
2094                let mut qh = y.qh.as_mut_ptr();
2095
2096                for j in (0..QK_K).step_by(128) {
2097                    for l_idx in 0..32 {
2098                        let q1 = *l.add(j + l_idx) & 0xF;
2099                        let q2 = *l.add(j + l_idx + 32) & 0xF;
2100                        let q3 = *l.add(j + l_idx + 64) & 0xF;
2101                        let q4 = *l.add(j + l_idx + 96) & 0xF;
2102                        *ql.add(l_idx) = (q1 | (q3 << 4)) as u8;
2103                        *ql.add(l_idx + 32) = (q2 | (q4 << 4)) as u8;
2104                        *qh.add(l_idx) = ((*l.add(j + l_idx) >> 4)
2105                            | ((*l.add(j + l_idx + 32) >> 4) << 2)
2106                            | ((*l.add(j + l_idx + 64) >> 4) << 4)
2107                            | ((*l.add(j + l_idx + 96) >> 4) << 6))
2108                            as u8;
2109                    }
2110                    ql = ql.add(64);
2111                    qh = qh.add(32);
2112                }
2113
2114                x = x.add(QK_K)
2115            }
2116        }
2117    }
2118
2119    fn from_float_imatrix(xs: &[f32], ys: &mut [Self], imatrix_weights: &[f32], n_per_row: usize) {
2120        debug_assert_eq!(
2121            xs.len(),
2122            ys.len() * Self::BLCK_SIZE,
2123            "quantize_row_q6k imatrix: size mismatch {} {} {}",
2124            xs.len(),
2125            ys.len(),
2126            Self::BLCK_SIZE
2127        );
2128        let mut l = [0i8; QK_K];
2129        let mut scales = [0f32; QK_K / 16];
2130        let mut x = xs.as_ptr();
2131        let imatrix_weights = imatrix_weights.as_ptr();
2132        let l = l.as_mut_ptr();
2133        unsafe {
2134            for (sblk_idx, y) in ys.iter_mut().enumerate() {
2135                let mut max_scale = 0f32;
2136                let mut max_abs_scale = 0f32;
2137                for (ib, scale_) in scales.iter_mut().enumerate() {
2138                    let imatrix_row = sblk_idx % (n_per_row / QK_K);
2139                    let scale = make_qx_quants(
2140                        16,
2141                        32,
2142                        x.add(16 * ib),
2143                        l.add(16 * ib),
2144                        1,
2145                        imatrix_weights.add(QK_K * imatrix_row + 16 * ib),
2146                    );
2147                    *scale_ = scale;
2148                    let abs_scale = scale.abs();
2149                    if abs_scale > max_abs_scale {
2150                        max_abs_scale = abs_scale;
2151                        max_scale = scale
2152                    }
2153                }
2154
2155                let iscale = -128f32 / max_scale;
2156                y.d = f16::from_f32(1.0 / iscale);
2157
2158                for (y_scale, scale) in y.scales.iter_mut().zip(scales.iter()) {
2159                    *y_scale = nearest_int(iscale * scale).min(127) as i8
2160                }
2161
2162                for (j, &y_scale) in y.scales.iter().enumerate() {
2163                    let d = y.d.to_f32() * y_scale as f32;
2164                    if d == 0. {
2165                        continue;
2166                    }
2167                    for ii in 0..16 {
2168                        let ll = nearest_int(*x.add(16 * j + ii) / d).clamp(-32, 31);
2169                        *l.add(16 * j + ii) = (ll + 32) as i8
2170                    }
2171                }
2172
2173                let mut ql = y.ql.as_mut_ptr();
2174                let mut qh = y.qh.as_mut_ptr();
2175
2176                for j in (0..QK_K).step_by(128) {
2177                    for l_idx in 0..32 {
2178                        let q1 = *l.add(j + l_idx) & 0xF;
2179                        let q2 = *l.add(j + l_idx + 32) & 0xF;
2180                        let q3 = *l.add(j + l_idx + 64) & 0xF;
2181                        let q4 = *l.add(j + l_idx + 96) & 0xF;
2182                        *ql.add(l_idx) = (q1 | (q3 << 4)) as u8;
2183                        *ql.add(l_idx + 32) = (q2 | (q4 << 4)) as u8;
2184                        *qh.add(l_idx) = ((*l.add(j + l_idx) >> 4)
2185                            | ((*l.add(j + l_idx + 32) >> 4) << 2)
2186                            | ((*l.add(j + l_idx + 64) >> 4) << 4)
2187                            | ((*l.add(j + l_idx + 96) >> 4) << 6))
2188                            as u8;
2189                    }
2190                    ql = ql.add(64);
2191                    qh = qh.add(32);
2192                }
2193
2194                x = x.add(QK_K)
2195            }
2196        }
2197    }
2198
2199    // https://github.com/ggerganov/llama.cpp/blob/8183159cf3def112f6d1fe94815fce70e1bffa12/k_quants.c#L1067
2200    fn to_float(xs: &[Self], ys: &mut [f32]) {
2201        let k = ys.len();
2202        debug_assert!(
2203            k.is_multiple_of(QK_K),
2204            "dequantize_row_q6k: {k} is not divisible by {QK_K}"
2205        );
2206
2207        for (idx_x, x) in xs.iter().enumerate() {
2208            let d = x.d.to_f32();
2209            let ql = &x.ql;
2210            let qh = &x.qh;
2211            let sc = &x.scales;
2212            for n in (0..QK_K).step_by(128) {
2213                let idx = n / 128;
2214                let ys = &mut ys[idx_x * QK_K + n..];
2215                let sc = &sc[8 * idx..];
2216                let ql = &ql[64 * idx..];
2217                let qh = &qh[32 * idx..];
2218                for l in 0..32 {
2219                    let is = l / 16;
2220                    let q1 = ((ql[l] & 0xF) | ((qh[l] & 3) << 4)) as i8 - 32;
2221                    let q2 = ((ql[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) as i8 - 32;
2222                    let q3 = ((ql[l] >> 4) | (((qh[l] >> 4) & 3) << 4)) as i8 - 32;
2223                    let q4 = ((ql[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) as i8 - 32;
2224                    ys[l] = d * sc[is] as f32 * q1 as f32;
2225                    ys[l + 32] = d * sc[is + 2] as f32 * q2 as f32;
2226                    ys[l + 64] = d * sc[is + 4] as f32 * q3 as f32;
2227                    ys[l + 96] = d * sc[is + 6] as f32 * q4 as f32;
2228                }
2229            }
2230        }
2231    }
2232}
2233
2234impl GgmlType for BlockQ8K {
2235    const DTYPE: GgmlDType = GgmlDType::Q8K;
2236    const BLCK_SIZE: usize = QK_K;
2237    type VecDotType = BlockQ8K;
2238
2239    #[allow(unreachable_code)]
2240    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2241        #[cfg(target_feature = "avx2")]
2242        return super::avx::vec_dot_q8k_q8k(n, xs, ys);
2243
2244        #[cfg(target_feature = "neon")]
2245        return super::neon::vec_dot_q8k_q8k(n, xs, ys);
2246
2247        Self::vec_dot_unopt(n, xs, ys)
2248    }
2249
2250    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2251        debug_assert!(
2252            n.is_multiple_of(QK_K),
2253            "vec_dot_q8k_q8k: {n} is not divisible by {QK_K}"
2254        );
2255        // Generic implementation.
2256        let mut sumf = 0f32;
2257        for (xs, ys) in xs.iter().zip(ys.iter()) {
2258            let sum_i = xs
2259                .qs
2260                .iter()
2261                .zip(ys.qs.iter())
2262                .map(|(&x, &y)| x as i32 * y as i32)
2263                .sum::<i32>();
2264            sumf += sum_i as f32 * xs.d * ys.d
2265        }
2266        sumf
2267    }
2268
2269    fn from_float(xs: &[f32], ys: &mut [Self]) {
2270        let k = xs.len();
2271        debug_assert!(
2272            k.is_multiple_of(QK_K),
2273            "quantize_row_q8k: {k} is not divisible by {QK_K}"
2274        );
2275        for (i, y) in ys.iter_mut().enumerate() {
2276            let mut max = 0f32;
2277            let mut amax = 0f32;
2278            let xs = &xs[i * QK_K..(i + 1) * QK_K];
2279            for &x in xs.iter() {
2280                if amax < x.abs() {
2281                    amax = x.abs();
2282                    max = x;
2283                }
2284            }
2285            if amax == 0f32 {
2286                y.d = 0f32;
2287                y.qs.fill(0)
2288            } else {
2289                let iscale = -128f32 / max;
2290                for (j, q) in y.qs.iter_mut().enumerate() {
2291                    // ggml uses nearest_int with bit magic here, maybe we want the same
2292                    // but we would have to test and benchmark it.
2293                    let v = (iscale * xs[j]).round();
2294                    *q = v.min(127.) as i8
2295                }
2296                for j in 0..QK_K / 16 {
2297                    let mut sum = 0i32;
2298                    for ii in 0..16 {
2299                        sum += y.qs[j * 16 + ii] as i32
2300                    }
2301                    y.bsums[j] = sum as i16
2302                }
2303                y.d = 1.0 / iscale
2304            }
2305        }
2306    }
2307
2308    fn to_float(xs: &[Self], ys: &mut [f32]) {
2309        let k = ys.len();
2310        debug_assert!(
2311            k.is_multiple_of(QK_K),
2312            "dequantize_row_q8k: {k} is not divisible by {QK_K}"
2313        );
2314        for (i, x) in xs.iter().enumerate() {
2315            for (j, &q) in x.qs.iter().enumerate() {
2316                ys[i * QK_K + j] = x.d * q as f32
2317            }
2318        }
2319    }
2320}
2321
2322// https://github.com/ggml-org/llama.cpp/blob/aa3ee0eb0b80efca126cedf9bcb4fb5864b46ce3/ggml/src/ggml-cpu/ggml-cpu.c#L1205
2323pub fn matmul<T: GgmlType>(
2324    (m, k, n): (usize, usize, usize),
2325    lhs: &[f32],
2326    rhs_t: &[T],
2327    dst: &mut [f32],
2328) -> Result<()> {
2329    debug_assert_eq!(
2330        T::BLCK_SIZE,
2331        T::VecDotType::BLCK_SIZE,
2332        "Mismatched block sizes"
2333    );
2334    debug_assert_eq!(
2335        m * k,
2336        lhs.len(),
2337        "unexpected lhs length {} ({m},{k},{n})",
2338        lhs.len()
2339    );
2340    if cfg!(feature = "float-dot") {
2341        return matmul_float_dot((m, k, n), lhs, rhs_t, dst);
2342    }
2343    let k_in_blocks = k.div_ceil(T::BLCK_SIZE);
2344
2345    // TODO: Pre-allocate this.
2346    let mut lhs_b = vec![T::VecDotType::zeros(); m * k_in_blocks];
2347    // f32, f16, and bf16 support direct copy
2348    if T::DIRECT_COPY {
2349        T::VecDotType::direct_copy(lhs, &mut lhs_b);
2350    } else {
2351        for row_idx in 0..m {
2352            let lhs_b_mut = &mut lhs_b[row_idx * k_in_blocks..(row_idx + 1) * k_in_blocks];
2353            let lhs = &lhs[row_idx * k..(row_idx + 1) * k];
2354            T::VecDotType::from_float(lhs, lhs_b_mut)
2355        }
2356    }
2357
2358    for row_idx in 0..m {
2359        let lhs_row = &lhs_b[row_idx * k_in_blocks..(row_idx + 1) * k_in_blocks];
2360        let dst_row = &mut dst[row_idx * n..(row_idx + 1) * n];
2361
2362        dst_row
2363            .into_par_iter()
2364            .enumerate()
2365            .with_min_len(128)
2366            .with_max_len(512)
2367            .for_each(|(col_idx, dst)| {
2368                let rhs_col = &rhs_t[col_idx * k_in_blocks..(col_idx + 1) * k_in_blocks];
2369                *dst = T::vec_dot(k, rhs_col, lhs_row);
2370            });
2371    }
2372    Ok(())
2373}
2374
2375/// Whether this build replaced the integer block dot products with floating point (the
2376/// `float-dot` feature). A probe prints it so two builds can be told apart.
2377pub const FLOAT_DOT: bool = cfg!(feature = "float-dot");
2378
2379/// Plain f32 dot product, eight independent lanes so the compiler can vectorise it.
2380fn dot_f32(a: &[f32], b: &[f32]) -> f32 {
2381    let mut acc = [0f32; 8];
2382    let ((ca, ra), (cb, rb)) = (a.as_chunks::<8>(), b.as_chunks::<8>());
2383    let tail: f32 = ra.iter().zip(rb).map(|(x, y)| x * y).sum();
2384    for (xa, xb) in ca.iter().zip(cb) {
2385        for l in 0..8 {
2386            acc[l] += xa[l] * xb[l];
2387        }
2388    }
2389    acc.iter().sum::<f32>() + tail
2390}
2391
2392/// The `float-dot` matmul: every weight row is converted to f32 (`to_float`, the block scale is
2393/// applied to each value here, BEFORE any multiply) and dotted with the f32 activation row. No
2394/// activation quantisation, no integer multiplies, no per-block scaling of an integer sum.
2395fn matmul_float_dot<T: GgmlType>(
2396    (m, k, n): (usize, usize, usize),
2397    lhs: &[f32],
2398    rhs_t: &[T],
2399    dst: &mut [f32],
2400) -> Result<()> {
2401    if m * k != lhs.len() || m * n != dst.len() {
2402        fuel_ir::bail!(
2403            "float-dot matmul: bad lengths lhs {} dst {} for ({m},{k},{n})",
2404            lhs.len(),
2405            dst.len()
2406        );
2407    }
2408    let k_in_blocks = k.div_ceil(T::BLCK_SIZE);
2409    // Result laid out column-major (one chunk of `m` values per weight row) so each parallel task
2410    // owns a disjoint chunk; transposed into `dst` afterwards (a no-op copy for m == 1).
2411    let mut tmp = vec![0f32; m * n];
2412    tmp.par_chunks_mut(m)
2413        .enumerate()
2414        .with_min_len(64)
2415        .for_each_init(
2416            || vec![0f32; k_in_blocks * T::BLCK_SIZE],
2417            |buf, (col, out)| {
2418                T::to_float(&rhs_t[col * k_in_blocks..(col + 1) * k_in_blocks], buf);
2419                for (row, o) in out.iter_mut().enumerate() {
2420                    *o = dot_f32(&buf[..k], &lhs[row * k..(row + 1) * k]);
2421                }
2422            },
2423        );
2424    for col in 0..n {
2425        for row in 0..m {
2426            dst[row * n + col] = tmp[col * m + row];
2427        }
2428    }
2429    Ok(())
2430}
2431
2432pub fn matmul_f16<T: GgmlType>(
2433    mkn: (usize, usize, usize),
2434    lhs: &[f16],
2435    rhs_t: &[T],
2436    dst: &mut [f16],
2437) -> Result<()> {
2438    let (m, k, n) = mkn;
2439    if m * k != lhs.len() {
2440        fuel_ir::bail!("unexpected lhs length {} {mkn:?}", lhs.len());
2441    }
2442    if cfg!(feature = "float-dot") {
2443        let lhs32: Vec<f32> = lhs.iter().map(|x| x.to_f32()).collect();
2444        let mut dst32 = vec![0f32; m * n];
2445        matmul_float_dot(mkn, &lhs32, rhs_t, &mut dst32)?;
2446        for (d, s) in dst.iter_mut().zip(dst32) {
2447            *d = f16::from_f32(s);
2448        }
2449        return Ok(());
2450    }
2451
2452    let k_in_lhs_blocks = k.div_ceil(T::BLCK_SIZE);
2453    let k_in_rhs_blocks = k.div_ceil(T::VecDotType::BLCK_SIZE);
2454    let mut lhs_b = vec![T::VecDotType::zeros(); m * k_in_lhs_blocks];
2455    let mut lhs_f32 = vec![0f32; k];
2456    for row_idx in 0..m {
2457        let lhs_b = &mut lhs_b[row_idx * k_in_lhs_blocks..(row_idx + 1) * k_in_lhs_blocks];
2458        let lhs = &lhs[row_idx * k..(row_idx + 1) * k];
2459        for (dst, &src) in lhs_f32.iter_mut().zip(lhs.iter()) {
2460            *dst = src.to_f32();
2461        }
2462        T::VecDotType::from_float(&lhs_f32, lhs_b);
2463    }
2464    let lhs_b = lhs_b.as_slice();
2465
2466    for row_idx in 0..m {
2467        let lhs_row = &lhs_b[row_idx * k_in_lhs_blocks..(row_idx + 1) * k_in_lhs_blocks];
2468        let dst_row = &mut dst[row_idx * n..(row_idx + 1) * n];
2469
2470        dst_row
2471            .into_par_iter()
2472            .enumerate()
2473            .with_min_len(128)
2474            .with_max_len(512)
2475            .for_each(|(col_idx, dst)| {
2476                let rhs_col = &rhs_t[col_idx * k_in_rhs_blocks..(col_idx + 1) * k_in_rhs_blocks];
2477                let value = T::vec_dot(k, rhs_col, lhs_row);
2478                *dst = f16::from_f32(value);
2479            });
2480    }
2481    Ok(())
2482}
2483
2484impl GgmlType for f32 {
2485    const DTYPE: GgmlDType = GgmlDType::F32;
2486    const BLCK_SIZE: usize = 1;
2487    const DIRECT_COPY: bool = true;
2488    type VecDotType = f32;
2489
2490    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2491        Self::vec_dot_unopt(n, xs, ys)
2492    }
2493
2494    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2495        debug_assert!(xs.len() >= n, "size mismatch xs {} < {n}", xs.len());
2496        debug_assert!(ys.len() >= n, "size mismatch ys {} < {n}", ys.len());
2497        let mut res = 0f32;
2498        unsafe { fuel_cpu_kernels::vec_dot_f32(xs.as_ptr(), ys.as_ptr(), &mut res, n) };
2499        res
2500    }
2501
2502    fn from_float(xs: &[f32], ys: &mut [Self]) {
2503        debug_assert_eq!(
2504            xs.len(),
2505            ys.len(),
2506            "size mismatch xs {} != ys {}",
2507            xs.len(),
2508            ys.len()
2509        );
2510        ys.copy_from_slice(xs);
2511    }
2512
2513    fn to_float(xs: &[Self], ys: &mut [f32]) {
2514        debug_assert_eq!(
2515            xs.len(),
2516            ys.len(),
2517            "size mismatch xs {} != ys {}",
2518            xs.len(),
2519            ys.len()
2520        );
2521        ys.copy_from_slice(xs);
2522    }
2523
2524    fn direct_copy(xs: &[f32], ys: &mut [Self]) {
2525        Self::from_float(xs, ys)
2526    }
2527}
2528
2529impl GgmlType for f16 {
2530    const DTYPE: GgmlDType = GgmlDType::F16;
2531    const BLCK_SIZE: usize = 1;
2532    const DIRECT_COPY: bool = true;
2533    type VecDotType = f16;
2534
2535    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2536        Self::vec_dot_unopt(n, xs, ys)
2537    }
2538
2539    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2540        debug_assert!(xs.len() >= n, "size mismatch xs {} < {n}", xs.len());
2541        debug_assert!(ys.len() >= n, "size mismatch ys {} < {n}", ys.len());
2542        let mut res = 0f32;
2543        unsafe { fuel_cpu_kernels::vec_dot_f16(xs.as_ptr(), ys.as_ptr(), &mut res, n) };
2544        res
2545    }
2546
2547    fn from_float(xs: &[f32], ys: &mut [Self]) {
2548        debug_assert_eq!(
2549            xs.len(),
2550            ys.len(),
2551            "size mismatch xs {} != ys {}",
2552            xs.len(),
2553            ys.len()
2554        );
2555        ys.convert_from_f32_slice(xs);
2556    }
2557
2558    fn to_float(xs: &[Self], ys: &mut [f32]) {
2559        debug_assert_eq!(
2560            xs.len(),
2561            ys.len(),
2562            "size mismatch xs {} != ys {}",
2563            xs.len(),
2564            ys.len()
2565        );
2566        xs.convert_to_f32_slice(ys);
2567    }
2568
2569    fn direct_copy(xs: &[f32], ys: &mut [Self]) {
2570        Self::from_float(xs, ys)
2571    }
2572}
2573
2574impl GgmlType for bf16 {
2575    const DTYPE: GgmlDType = GgmlDType::BF16;
2576    const BLCK_SIZE: usize = 1;
2577    const DIRECT_COPY: bool = true;
2578    type VecDotType = bf16;
2579
2580    fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2581        Self::vec_dot_unopt(n, xs, ys)
2582    }
2583
2584    fn vec_dot_unopt(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32 {
2585        debug_assert!(xs.len() >= n, "size mismatch xs {} < {n}", xs.len());
2586        debug_assert!(ys.len() >= n, "size mismatch ys {} < {n}", ys.len());
2587        let mut res = 0f32;
2588        unsafe { fuel_cpu_kernels::vec_dot_bf16(xs.as_ptr(), ys.as_ptr(), &mut res, n) };
2589        res
2590    }
2591
2592    fn from_float(xs: &[f32], ys: &mut [Self]) {
2593        debug_assert_eq!(
2594            xs.len(),
2595            ys.len(),
2596            "size mismatch xs {} != ys {}",
2597            xs.len(),
2598            ys.len()
2599        );
2600        ys.convert_from_f32_slice(xs);
2601    }
2602
2603    fn to_float(xs: &[Self], ys: &mut [f32]) {
2604        debug_assert_eq!(
2605            xs.len(),
2606            ys.len(),
2607            "size mismatch xs {} != ys {}",
2608            xs.len(),
2609            ys.len()
2610        );
2611        xs.convert_to_f32_slice(ys);
2612    }
2613
2614    fn direct_copy(xs: &[f32], ys: &mut [Self]) {
2615        Self::from_float(xs, ys)
2616    }
2617}
2618
2619macro_rules! verify_block_size {
2620    ( $block_type:ident ) => {
2621        const _: () =
2622            assert!($block_type::BLCK_SIZE == <$block_type as GgmlType>::VecDotType::BLCK_SIZE);
2623    };
2624}
2625
2626macro_rules! verify_block_sizes {
2627    ( $( $block_type:ident ),* ) => {
2628        $(
2629            verify_block_size!($block_type);
2630        )*
2631    };
2632}
2633
2634verify_block_sizes!(
2635    BlockQ4_0, BlockQ4_1, BlockQ5_0, BlockQ5_1, BlockQ8_0, BlockQ8_1, BlockQ2K, BlockQ3K, BlockQ4K,
2636    BlockQ5K, BlockQ6K, BlockQ8K, f32, f16, bf16
2637);
2638
2639#[cfg(test)]
2640mod float_dot_tests {
2641    use super::*;
2642
2643    /// A small deterministic matrix: values in about [-1, 1], no two rows alike.
2644    fn fill(len: usize, seed: u32) -> Vec<f32> {
2645        (0..len as u32)
2646            .map(|i| {
2647                let x = (i
2648                    .wrapping_mul(2654435761)
2649                    .wrapping_add(seed.wrapping_mul(40503)))
2650                    >> 8;
2651                (x % 2001) as f32 / 1000.0 - 1.0
2652            })
2653            .collect()
2654    }
2655
2656    /// The float-dot driver is the matmul of the DEQUANTISED weights with the f32 activations (so it
2657    /// agrees with a plain f32 reference to rounding), for several rows of activations at once.
2658    #[test]
2659    fn float_dot_equals_the_f32_matmul_of_the_dequantised_weights() {
2660        let (m, k, n) = (3usize, 64usize, 8usize);
2661        let w = fill(n * k, 7);
2662        let x = fill(m * k, 11);
2663        let mut blocks = vec![BlockQ4_0::zeros(); n * k / QK4_0];
2664        BlockQ4_0::from_float(&w, &mut blocks);
2665        let mut deq = vec![0f32; n * k];
2666        BlockQ4_0::to_float(&blocks, &mut deq);
2667        let mut want = vec![0f32; m * n];
2668        for r in 0..m {
2669            for c in 0..n {
2670                want[r * n + c] = (0..k).map(|i| x[r * k + i] * deq[c * k + i]).sum();
2671            }
2672        }
2673        let mut got = vec![0f32; m * n];
2674        matmul_float_dot((m, k, n), &x, &blocks, &mut got).expect("float-dot matmul");
2675        assert!(
2676            want.iter().any(|v| v.abs() > 0.1),
2677            "control: the reference is not all zeros"
2678        );
2679        for (g, w) in got.iter().zip(&want) {
2680            assert!(
2681                (g - w).abs() <= 1e-3 * w.abs().max(1.0),
2682                "float-dot {g} vs reference {w}"
2683            );
2684        }
2685    }
2686
2687    /// The integer path (the default build) stays within the activation-quantisation error of the
2688    /// same reference, so the two builds can be compared on one fixture.
2689    #[test]
2690    fn the_default_matmul_is_close_to_the_f32_reference() {
2691        let (m, k, n) = (2usize, 64usize, 8usize);
2692        let w = fill(n * k, 3);
2693        let x = fill(m * k, 5);
2694        let mut blocks = vec![BlockQ4_0::zeros(); n * k / QK4_0];
2695        BlockQ4_0::from_float(&w, &mut blocks);
2696        let mut deq = vec![0f32; n * k];
2697        BlockQ4_0::to_float(&blocks, &mut deq);
2698        let mut got = vec![0f32; m * n];
2699        matmul((m, k, n), &x, &blocks, &mut got).expect("matmul");
2700        for r in 0..m {
2701            for c in 0..n {
2702                let want: f32 = (0..k).map(|i| x[r * k + i] * deq[c * k + i]).sum();
2703                assert!(
2704                    (got[r * n + c] - want).abs() <= 0.05 * want.abs().max(1.0),
2705                    "matmul {} vs reference {want} (float-dot build: {FLOAT_DOT})",
2706                    got[r * n + c]
2707                );
2708            }
2709        }
2710    }
2711}