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