1pub(super) fn nearest_int(v: f32) -> i32 {
6 v.round() as i32
7}
8
9pub(super) fn group_for_quantization<'a, 'b, T: super::k_quants::GgmlType>(
13 xs: &'b [f32],
14 ys: &'a mut [T],
15) -> Vec<(&'a mut T, &'b [f32])> {
16 let block_size = T::BLCK_SIZE;
17 let dtype = T::DTYPE;
18
19 let expected_blocks = xs.len() / block_size;
20 let actual_blocks = ys.len();
21
22 debug_assert_eq!(
24 expected_blocks, actual_blocks,
25 "quantize {dtype:?}: expected {expected_blocks} blocks but only {actual_blocks} were provided!"
26 );
27
28 ys.iter_mut().zip(xs.chunks_exact(block_size)).collect()
29}
30
31pub(super) fn group_for_dequantization<'a, 'b, T: super::k_quants::GgmlType>(
35 xs: &'a [T],
36 ys: &'b mut [f32],
37) -> Vec<(&'a T, &'b mut [f32])> {
38 let block_size = T::BLCK_SIZE;
39 let dtype = T::DTYPE;
40
41 let actual_output_len = ys.len();
42 let expected_output_len = xs.len() * block_size;
43 debug_assert_eq!(
45 expected_output_len, actual_output_len,
46 "dequantize {dtype:?}: ys (len = {actual_output_len}) does not match the expected length of {expected_output_len}!"
47 );
48
49 xs.iter().zip(ys.chunks_exact_mut(block_size)).collect()
51}
52
53pub(super) fn get_scale_min_k4(j: usize, q: &[u8]) -> (u8, u8) {
54 if j < 4 {
55 let d = q[j] & 63;
56 let m = q[j + 4] & 63;
57 (d, m)
58 } else {
59 let d = (q[j + 4] & 0xF) | ((q[j - 4] >> 6) << 4);
60 let m = (q[j + 4] >> 4) | ((q[j] >> 6) << 4);
61 (d, m)
62 }
63}
64
65pub(super) unsafe fn make_qx_quants(
66 n: usize,
67 nmax: i32,
68 x: *const f32,
69 ls: *mut i8,
70 rmse_type: i32,
71 qw: *const f32,
72) -> f32 {
73 unsafe {
74 let mut max = 0f32;
75 let mut amax = 0f32;
76 for i in 0..n {
77 let x = *x.add(i);
78 let ax = x.abs();
79 if ax > amax {
80 amax = ax;
81 max = x;
82 }
83 }
84 if amax == 0. {
85 for i in 0..n {
87 *ls.add(i) = 0;
88 }
89 return 0.;
90 }
91 let mut iscale = -(nmax as f32) / max;
92 if rmse_type == 0 {
93 for i in 0..n {
94 let x = *x.add(i);
95 let l = nearest_int(iscale * x);
96 *ls.add(i) = (nmax + l.clamp(-nmax, nmax - 1)) as i8;
97 }
98 return 1.0 / iscale;
99 }
100 let weight_type = rmse_type % 2;
101 let mut sumlx = 0f32;
102 let mut suml2 = 0f32;
103 for i in 0..n {
104 let x = *x.add(i);
105 let l = nearest_int(iscale * x);
106 let l = l.clamp(-nmax, nmax - 1);
107 *ls.add(i) = (l + nmax) as i8;
108 let w = if !qw.is_null() {
109 *qw.add(i)
110 } else if weight_type == 1 {
111 x * x
112 } else {
113 1.0
114 };
115 let l = l as f32;
116 sumlx += w * x * l;
117 suml2 += w * l * l;
118 }
119 let mut scale = sumlx / suml2;
120 let mut best = scale * sumlx;
121 for _itry in 0..3 {
122 let iscale = 1.0 / scale;
123 let mut slx = 0f32;
124 let mut sl2 = 0f32;
125 let mut changed = false;
126 for i in 0..n {
127 let x = *x.add(i);
128 let l = nearest_int(iscale * x);
129 let l = l.clamp(-nmax, nmax - 1);
130 if l + nmax != *ls.add(i) as i32 {
131 changed = true;
132 }
133 let w = if !qw.is_null() {
134 *qw.add(i)
135 } else if weight_type == 1 {
136 x * x
137 } else {
138 1.0
139 };
140 let l = l as f32;
141 slx += w * x * l;
142 sl2 += w * l * l;
143 }
144 if !changed || sl2 == 0.0 || slx * slx <= best * sl2 {
145 break;
146 }
147 for i in 0..n {
148 let x = *x.add(i);
149 let l = nearest_int(iscale * x);
150 *ls.add(i) = (nmax + l.clamp(-nmax, nmax - 1)) as i8;
151 }
152 sumlx = slx;
153 suml2 = sl2;
154 scale = sumlx / suml2;
155 best = scale * sumlx;
156 }
157 for _itry in 0..5 {
158 let mut n_changed = 0;
159 for i in 0..n {
160 let x = *x.add(i);
161 let w = if !qw.is_null() {
162 *qw.add(i)
163 } else if weight_type == 1 {
164 x * x
165 } else {
166 1.0
167 };
168 let l = *ls.add(i) as i32 - nmax;
169 let mut slx = sumlx - w * x * l as f32;
170 if slx > 0. {
171 let mut sl2 = suml2 - w * l as f32 * l as f32;
172 let new_l = nearest_int(x * sl2 / slx);
173 let new_l = new_l.clamp(-nmax, nmax - 1);
174 if new_l != l {
175 slx += w * x * new_l as f32;
176 sl2 += w * new_l as f32 * new_l as f32;
177 if sl2 > 0. && slx * slx * suml2 > sumlx * sumlx * sl2 {
178 *ls.add(i) = (nmax + new_l) as i8;
179 sumlx = slx;
180 suml2 = sl2;
181 scale = sumlx / suml2;
182 best = scale * sumlx;
183 n_changed += 1;
184 }
185 }
186 }
187 }
188 if n_changed == 0 {
189 break;
190 }
191 }
192 if rmse_type < 3 {
193 return scale;
194 }
195 for is in -4..4 {
196 if is == 0 {
197 continue;
198 }
199 iscale = -(nmax as f32 + 0.1f32 * is as f32) / max;
200 let mut sumlx = 0.;
201 let mut suml2 = 0.;
202 for i in 0..n {
203 let x = *x.add(i);
204 let l = nearest_int(iscale * x);
205 let l = l.clamp(-nmax, nmax - 1);
206 let w = if !qw.is_null() {
207 *qw.add(i)
208 } else if weight_type == 1 {
209 x * x
210 } else {
211 1.0
212 };
213 let l = l as f32;
214 sumlx += w * x * l;
215 suml2 += w * l * l;
216 }
217 if suml2 > 0. && sumlx * sumlx > best * suml2 {
218 for i in 0..n {
219 let x = *x.add(i);
220 let l = nearest_int(iscale * x);
221 *ls.add(i) = (nmax + l.clamp(-nmax, nmax - 1)) as i8;
222 }
223 scale = sumlx / suml2;
224 best = scale * sumlx;
225 }
226 }
227 scale
228 }
229}
230
231pub(super) fn make_qkx1_quants(nmax: i32, ntry: usize, x: &[f32]) -> (f32, f32) {
233 let n = x.len();
234 let mut l = vec![0; n];
235 let min = *x
237 .iter()
238 .take(n)
239 .min_by(|a, b| a.total_cmp(b))
240 .unwrap_or(&x[0]);
241 let max = *x.iter().max_by(|a, b| a.total_cmp(b)).unwrap_or(&x[0]);
242
243 if max == min {
245 return (0.0, 0.0);
246 }
247
248 let mut min = min.min(0.);
250
251 let mut iscale = nmax as f32 / (max - min);
253 let mut scale = 1.0 / iscale;
254
255 for _ in 0..ntry {
256 let mut sumlx = 0.0;
257 let mut suml2 = 0;
258 let mut did_change = false;
259
260 for (i, value) in x.iter().enumerate().take(n) {
261 let li = nearest_int(iscale * (value - min)).clamp(0, nmax);
262 let clamped_li = li as u8;
263 if clamped_li != l[i] {
264 l[i] = clamped_li;
265 did_change = true;
266 }
267 sumlx += (value - min) * li as f32;
268 suml2 += li * li;
269 }
270 scale = sumlx / suml2 as f32;
271
272 let sum: f32 = x
273 .iter()
274 .take(n)
275 .zip(l.iter().take(n))
276 .map(|(xi, &li)| xi - scale * li as f32)
277 .sum();
278
279 min = sum / n as f32;
280 if min > 0.0 {
281 min = 0.0;
282 }
283 iscale = 1.0 / scale;
284 if !did_change {
285 break;
286 }
287 }
288 (scale, -min)
289}
290
291pub(super) fn make_q3_quants(x: &[f32], nmax: i32, do_rmse: bool) -> f32 {
293 let n = x.len();
294 let mut l = vec![0i8; n];
295
296 let mut max = 0.0;
297 let mut amax = 0.0;
298 for &xi in x.iter().take(n) {
299 let ax = xi.abs();
300 if ax > amax {
301 amax = ax;
302 max = xi;
303 }
304 }
305
306 if amax == 0.0 {
307 return 0.0;
308 }
309
310 let iscale = -(nmax as f32) / max;
311 if do_rmse {
312 let mut sumlx = 0.0;
313 let mut suml2 = 0.0;
314 for i in 0..n {
315 let li = (iscale * x[i]).round() as i32;
316 let li = li.clamp(-nmax, nmax - 1);
317 l[i] = li as i8;
318 let w = x[i] * x[i];
319 sumlx += w * x[i] * li as f32;
320 suml2 += w * (li * li) as f32;
321 }
322 for _ in 0..5 {
323 let mut n_changed = 0;
324 for i in 0..n {
325 let w = x[i] * x[i];
326 let mut slx = sumlx - w * x[i] * l[i] as f32;
327 if slx > 0.0 {
328 let mut sl2 = suml2 - w * (l[i] as i32 * l[i] as i32) as f32;
329 let mut new_l = (x[i] * sl2 / slx).round() as i32;
330 new_l = new_l.clamp(-nmax, nmax - 1);
331 if new_l != l[i] as i32 {
332 slx += w * x[i] * new_l as f32;
333 sl2 += w * (new_l * new_l) as f32;
334 if sl2 > 0.0 && slx * slx * suml2 > sumlx * sumlx * sl2 {
335 l[i] = new_l as i8;
336 sumlx = slx;
337 suml2 = sl2;
338 n_changed += 1;
339 }
340 }
341 }
342 }
343 if n_changed == 0 {
344 break;
345 }
346 }
347 for li in l.iter_mut() {
348 *li += nmax as i8;
349 }
350 return sumlx / suml2;
351 }
352 for i in 0..n {
353 let li = (iscale * x[i]).round() as i32;
354 l[i] = (li.clamp(-nmax, nmax - 1) + nmax) as i8;
355 }
356 1.0 / iscale
357}
358
359pub(super) fn make_qkx3_quants(
362 nmax: i32,
363 x: &[f32],
364 weights: Option<&[f32]>,
365 rmin: f32,
366 rdelta: f32,
367 nstep: usize,
368 use_mad: bool,
369) -> (f32, f32) {
370 let n = x.len();
371 let mut l: [u8; 32] = [0; 32];
372 let mut l_aux: [u8; 32] = [0; 32];
373
374 let mut min_val = x[0];
375 let mut max_val = x[0];
376 let mut sum_w = match weights {
377 Some(w) => w[0],
378 None => x[0] * x[0],
379 };
380 let mut sum_x = sum_w * x[0];
381
382 for i in 1..n {
383 if x[i] < min_val {
384 min_val = x[i];
385 }
386 if x[i] > max_val {
387 max_val = x[i];
388 }
389 let w = match weights {
390 Some(w) => w[i],
391 None => x[i] * x[i],
392 };
393 sum_w += w;
394 sum_x += w * x[i];
395 }
396
397 if min_val > 0.0 {
398 min_val = 0.0;
399 }
400
401 if max_val <= min_val {
402 return (0.0, -min_val);
403 }
404
405 let mut iscale = nmax as f32 / (max_val - min_val);
406 let mut scale = 1.0 / iscale;
407 let mut best_mad = 0.0;
408
409 for i in 0..n {
410 let l_val = nearest_int(iscale * (x[i] - min_val)).clamp(0, nmax) as u8;
411 l[i] = l_val;
412 let diff = scale * (l_val as f32) + min_val - x[i];
413 let diff = if use_mad { diff.abs() } else { diff * diff };
414 let w = match weights {
415 Some(w) => w[i],
416 None => x[i] * x[i],
417 };
418 best_mad += w * diff;
419 }
420
421 if nstep < 1 {
422 return (scale, -min_val);
423 }
424
425 for is in 0..=nstep {
426 iscale = (rmin + rdelta * is as f32 + nmax as f32) / (max_val - min_val);
427 let (mut sum_l, mut sum_l2, mut sum_xl) = (0.0, 0.0, 0.0);
428
429 for i in 0..n {
430 let l_val = nearest_int(iscale * (x[i] - min_val)).clamp(0, nmax) as u8;
431 l_aux[i] = l_val;
432 let w = match weights {
433 Some(w) => w[i],
434 None => x[i] * x[i],
435 };
436 sum_l += w * l_val as f32;
437 sum_l2 += w * (l_val as f32).powi(2);
438 sum_xl += w * l_val as f32 * x[i];
439 }
440
441 let d = sum_w * sum_l2 - sum_l * sum_l;
442 if d > 0.0 {
443 let mut this_scale = (sum_w * sum_xl - sum_x * sum_l) / d;
444 let mut this_min = (sum_l2 * sum_x - sum_l * sum_xl) / d;
445
446 if this_min > 0.0 {
447 this_min = 0.0;
448 this_scale = sum_xl / sum_l2;
449 }
450
451 let mut mad = 0.0;
452 for i in 0..n {
453 let diff = this_scale * (l_aux[i] as f32) + this_min - x[i];
454 let diff = if use_mad { diff.abs() } else { diff * diff };
455 let w = match weights {
456 Some(w) => w[i],
457 None => x[i] * x[i],
458 };
459 mad += w * diff;
460 }
461
462 if mad < best_mad {
463 l.copy_from_slice(&l_aux);
464 best_mad = mad;
465 scale = this_scale;
466 min_val = this_min;
467 }
468 }
469 }
470
471 (scale, -min_val)
472}
473
474pub(super) fn make_qp_quants(
476 n: usize,
477 nmax: u8,
478 x: &[f32],
479 l: &mut [u8],
480 quant_weights: &[f32],
481) -> f32 {
482 assert_eq!(x.len(), n);
483 assert_eq!(l.len(), n);
484 assert_eq!(quant_weights.len(), n);
485
486 let max = x.iter().copied().fold(0.0, f32::max);
487 if max == 0.0 {
488 l.iter_mut().for_each(|li| *li = 0);
489 return 0.0;
490 }
491
492 let mut iscale = nmax as f32 / max;
493 for (xi, li) in x.iter().zip(l.iter_mut()) {
494 *li = nearest_int(iscale * xi) as u8;
495 }
496
497 let scale = 1.0 / iscale;
498 let mut best_mse = x
499 .iter()
500 .zip(l.iter())
501 .zip(quant_weights.iter())
502 .map(|((&xi, &li), &w)| {
503 let diff = xi - scale * li as f32;
504 w * diff * diff
505 })
506 .sum::<f32>();
507
508 for is in -4..=4 {
509 if is == 0 {
510 continue;
511 }
512 let iscale_is = (0.1 * is as f32 + nmax as f32) / max;
513 let scale_is = 1.0 / iscale_is;
514
515 let mse = x
516 .iter()
517 .zip(quant_weights.iter())
518 .map(|(&xi, &w)| {
519 let mut li = nearest_int(iscale_is * xi) as u8;
520 li = li.min(nmax);
521 let diff = xi - scale_is * li as f32;
522 w * diff * diff
523 })
524 .sum::<f32>();
525
526 if mse < best_mse {
527 best_mse = mse;
528 iscale = iscale_is;
529 }
530 }
531
532 let mut sumlx = 0.0;
533 let mut suml2 = 0.0;
534 for ((xi, li), &w) in x.iter().zip(l.iter_mut()).zip(quant_weights.iter()) {
535 let mut li_new = (iscale * xi).round() as u8;
536 li_new = li_new.min(nmax);
537 *li = li_new;
538 sumlx += w * xi * li_new as f32;
539 suml2 += w * (li_new as f32).powi(2);
540 }
541
542 for _ in 0..5 {
543 let mut n_changed = 0;
544 for ((xi, li), &w) in x.iter().zip(l.iter_mut()).zip(quant_weights.iter()) {
545 let mut slx = sumlx - w * xi * *li as f32;
546 let mut sl2 = suml2 - w * (*li as f32).powi(2);
547 if slx > 0.0 && sl2 > 0.0 {
548 let new_li = (nearest_int(xi * sl2 / slx) as u8).min(nmax);
549 if new_li != *li {
550 slx += w * xi * new_li as f32;
551 sl2 += w * (new_li as f32).powi(2);
552 if slx.powi(2) * suml2 > sumlx.powi(2) * sl2 {
553 *li = new_li;
554 sumlx = slx;
555 suml2 = sl2;
556 n_changed += 1;
557 }
558 }
559 }
560 }
561 if n_changed == 0 {
562 break;
563 }
564 }
565
566 sumlx / suml2
567}