1use 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
12pub 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
23pub 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 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 fn vec_dot(n: usize, xs: &[Self], ys: &[Self::VecDotType]) -> f32;
60
61 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#[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
180pub fn blocks_as_bytes<T: GgmlType>(blocks: &[T]) -> &[u8] {
185 bytemuck::cast_slice(blocks)
186}
187
188pub 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 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 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 #[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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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") }
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 q8 = &q8[32..];
857 }
858 q2 = &q2[32..];
860 }
861 sumf += dall * isum as f32 - dmin * summs as f32;
862 }
863
864 sumf
865 }
866
867 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 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 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 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 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 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 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 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 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 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 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 is += 1;
1404 }
1405 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 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 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 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
1667impl 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 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 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 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 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 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 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 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
2319pub 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 let mut lhs_b = vec![T::VecDotType::zeros(); m * k_in_blocks];
2341 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);