Skip to main content

fuel_quantized/
k_quants.rs

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