1const NORM_ADJUST: [[i32; 3]; 6] = [
16 [10, 16, 13],
17 [11, 18, 14],
18 [13, 20, 16],
19 [14, 23, 18],
20 [16, 25, 20],
21 [18, 29, 23],
22];
23
24const QUANT_MF: [[i32; 3]; 6] = [
27 [13107, 5243, 8066],
28 [11916, 4660, 7490],
29 [10082, 4194, 6554],
30 [9362, 3647, 5825],
31 [8192, 3355, 5243],
32 [7282, 2893, 4559],
33];
34
35#[inline]
40fn pos_group(i: usize, j: usize) -> usize {
41 match (i % 2, j % 2) {
42 (0, 0) => 0,
43 (1, 1) => 1,
44 _ => 2,
45 }
46}
47
48const POS_GROUP_FLAT: [usize; 16] = [0, 2, 0, 2, 2, 1, 2, 1, 0, 2, 0, 2, 2, 1, 2, 1];
52
53
54const fn flatten_level_scale() -> [[i32; 16]; 6] {
56 let mut out = [[0i32; 16]; 6];
57 let mut m = 0;
58 while m < 6 {
59 let mut idx = 0;
60 while idx < 16 {
61 out[m][idx] = 16 * NORM_ADJUST[m][POS_GROUP_FLAT[idx]];
62 idx += 1;
63 }
64 m += 1;
65 }
66 out
67}
68const LEVEL_SCALE_FLAT: [[i32; 16]; 6] = flatten_level_scale();
69
70#[inline]
72fn fwd_1d(x0: i32, x1: i32, x2: i32, x3: i32) -> (i32, i32, i32, i32) {
73 let t0 = x0 + x3;
74 let t1 = x1 + x2;
75 let t2 = x1 - x2;
76 let t3 = x0 - x3;
77 (t0 + t1, 2 * t3 + t2, t0 - t1, t3 - 2 * t2)
78}
79
80#[inline]
82fn inv_1d(d0: i32, d1: i32, d2: i32, d3: i32) -> (i32, i32, i32, i32) {
83 let e0 = d0 + d2;
84 let e1 = d0 - d2;
85 let e2 = (d1 >> 1) - d3;
86 let e3 = d1 + (d3 >> 1);
87 (e0 + e3, e1 + e2, e1 - e2, e0 - e3)
88}
89
90pub fn forward_core(block: &[i32; 16]) -> [i32; 16] {
93 let mut m = *block;
94 for r in 0..4 {
96 let (a, b, c, d) = fwd_1d(m[r * 4], m[r * 4 + 1], m[r * 4 + 2], m[r * 4 + 3]);
97 m[r * 4] = a;
98 m[r * 4 + 1] = b;
99 m[r * 4 + 2] = c;
100 m[r * 4 + 3] = d;
101 }
102 for c in 0..4 {
104 let (a, b, cc, d) = fwd_1d(m[c], m[4 + c], m[8 + c], m[12 + c]);
105 m[c] = a;
106 m[4 + c] = b;
107 m[8 + c] = cc;
108 m[12 + c] = d;
109 }
110 m
111}
112
113pub fn quantize(coeffs: &[i32; 16], qp: u8, dz_div: i64) -> [i32; 16] {
122 let mf_oh = &QUANT_MF_OH[qp as usize];
128 let ff = quant_dz_ff(qp, dz_div);
129 const POS: [usize; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7];
130 let mut out = [0i32; 16];
131 for idx in 0..16 {
132 let p = POS[idx];
133 let a = coeffs[idx].unsigned_abs() as i32;
134 let lvl = ((a + ff[p] as i32) * mf_oh[p] as i32) >> 16;
135 out[idx] = if coeffs[idx] < 0 { -lvl } else { lvl };
136 }
137 out
138}
139
140pub fn quant_dz_ff(qp: u8, dz_div: i64) -> [i16; 8] {
145 let m = (qp % 6) as usize;
146 let qbits = 15 + (qp / 6) as i64;
147 let f = (1i64 << qbits) / dz_div;
148 const GROUP8: [usize; 8] = [0, 2, 0, 2, 2, 1, 2, 1];
150 let mut ff = [0i16; 8];
151 for (i, slot) in ff.iter_mut().enumerate() {
152 let mfg = QUANT_MF[m][GROUP8[i]] as i64;
153 *slot = ((f + mfg / 2) / mfg) as i16;
154 }
155 ff
156}
157
158pub fn trellis_quant(coeffs: &[i32; 16], qp: u8, intra: bool, lambda: f64) -> [i32; 16] {
170 let m = (qp % 6) as usize;
171 let qbits = 15 + (qp / 6) as u32;
172 let scale = (1u64 << qbits) as f64;
173 let off: i64 = if intra { (1i64 << qbits) / 3 } else { (1i64 << qbits) / 6 };
174 let mut out = [0i32; 16];
175 for i in 0..4 {
176 for j in 0..4 {
177 let idx = i * 4 + j;
178 let w = coeffs[idx] as i64;
179 let mf = QUANT_MF[m][pos_group(i, j)] as i64;
180 let num = w.abs() * mf; let l_scalar = (num + off) >> qbits;
182 if l_scalar == 0 {
183 continue;
184 }
185 let lambda_q = lambda * (mf * mf) as f64 / (scale * scale) * 64.0;
188 let ideal = num as f64 / scale;
189 let mut best = l_scalar;
190 let mut best_j = f64::MAX;
191 for cand in [l_scalar - 1, l_scalar] {
192 let d = (ideal - cand as f64).powi(2);
193 let r = if cand == 0 {
194 0.0
195 } else {
196 2.0 + 2.0 * (64 - (cand as u64).leading_zeros()) as f64
198 };
199 let jj = d + lambda_q * r;
200 if jj < best_j {
201 best_j = jj;
202 best = cand;
203 }
204 }
205 out[idx] = if w < 0 { -best as i32 } else { best as i32 };
206 }
207 }
208 out
209}
210
211pub fn dequantize(levels: &[i32; 16], qp: u8) -> [i32; 16] {
214 let _g = crate::prof::scope(crate::prof::Stage::Dequant);
215 let m = (qp % 6) as usize;
216 let shift = (qp / 6) as i32;
217 let ls = &LEVEL_SCALE_FLAT[m];
218 let mut out = [0i32; 16];
219 if qp >= 24 {
220 let sh = shift - 4;
221 for idx in 0..16 {
222 out[idx] = (levels[idx] * ls[idx]) << sh;
223 }
224 } else {
225 let add = 1 << (3 - shift);
226 let sh = 4 - shift;
227 for idx in 0..16 {
228 out[idx] = (levels[idx] * ls[idx] + add) >> sh;
229 }
230 }
231 out
232}
233
234pub fn dequantize_weighted(levels: &[i32; 16], qp: u8, weight: &[i32; 16]) -> [i32; 16] {
238 let _g = crate::prof::scope(crate::prof::Stage::Dequant);
239 let m = (qp % 6) as usize;
240 let shift = (qp / 6) as i32;
241 let ls: [i32; 16] = std::array::from_fn(|idx| weight[idx] * NORM_ADJUST[m][POS_GROUP_FLAT[idx]]);
242 let mut out = [0i32; 16];
243 if qp >= 24 {
244 let sh = shift - 4;
245 for idx in 0..16 {
246 out[idx] = (levels[idx] * ls[idx]) << sh;
247 }
248 } else {
249 let add = 1 << (3 - shift);
250 let sh = 4 - shift;
251 for idx in 0..16 {
252 out[idx] = (levels[idx] * ls[idx] + add) >> sh;
253 }
254 }
255 out
256}
257
258pub fn inverse_core(coeffs: &[i32; 16]) -> [i32; 16] {
261 let mut m = *coeffs;
262 for r in 0..4 {
268 let (a, b, c, d) = inv_1d(m[r * 4], m[r * 4 + 1], m[r * 4 + 2], m[r * 4 + 3]);
269 m[r * 4] = a;
270 m[r * 4 + 1] = b;
271 m[r * 4 + 2] = c;
272 m[r * 4 + 3] = d;
273 }
274 for c in 0..4 {
275 let (a, b, cc, d) = inv_1d(m[c], m[4 + c], m[8 + c], m[12 + c]);
276 m[c] = a;
277 m[4 + c] = b;
278 m[8 + c] = cc;
279 m[12 + c] = d;
280 }
281 for v in m.iter_mut() {
282 *v = (*v + 32) >> 6;
283 }
284 m
285}
286
287pub fn forward_quant(residual: &[i32; 16], qp: u8, intra: bool) -> [i32; 16] {
290 quantize(&forward_core(residual), qp, if intra { 3 } else { 6 })
291}
292
293pub fn inverse_quant(levels: &[i32; 16], qp: u8) -> [i32; 16] {
295 inverse_core(&dequantize(levels, qp))
296}
297
298const NORM_ADJUST_8X8: [[i32; 6]; 6] = [
303 [20, 18, 32, 19, 25, 24],
304 [22, 19, 35, 21, 28, 26],
305 [26, 23, 42, 24, 33, 31],
306 [28, 25, 45, 26, 35, 33],
307 [32, 28, 51, 30, 40, 38],
308 [36, 32, 58, 34, 46, 43],
309];
310
311#[inline]
314const fn pos_group_8x8(i: usize, j: usize) -> usize {
315 let (i4, j4) = (i % 4, j % 4);
316 if i4 == 0 && j4 == 0 {
317 0
318 } else if i % 2 == 1 && j % 2 == 1 {
319 1
320 } else if i4 == 2 && j4 == 2 {
321 2
322 } else if (i4 == 0 && j % 2 == 1) || (i % 2 == 1 && j4 == 0) {
323 3
324 } else if (i4 == 0 && j4 == 2) || (i4 == 2 && j4 == 0) {
325 4
326 } else {
327 5
328 }
329}
330
331const POS_GROUP_8X8_FLAT: [usize; 64] = {
333 let mut out = [0usize; 64];
334 let mut i = 0;
335 while i < 8 {
336 let mut j = 0;
337 while j < 8 {
338 out[i * 8 + j] = pos_group_8x8(i, j);
339 j += 1;
340 }
341 i += 1;
342 }
343 out
344};
345
346#[inline]
348fn inv_1d_8x8(d: &[i32; 8]) -> [i32; 8] {
349 let a0 = d[0] + d[4];
350 let a4 = d[0] - d[4];
351 let a2 = (d[2] >> 1) - d[6];
352 let a6 = d[2] + (d[6] >> 1);
353 let b0 = a0 + a6;
354 let b2 = a4 + a2;
355 let b4 = a4 - a2;
356 let b6 = a0 - a6;
357 let a1 = -d[3] + d[5] - d[7] - (d[7] >> 1);
358 let a3 = d[1] + d[7] - d[3] - (d[3] >> 1);
359 let a5 = -d[1] + d[7] + d[5] + (d[5] >> 1);
360 let a7 = d[3] + d[5] + d[1] + (d[1] >> 1);
361 let b1 = a1 + (a7 >> 2);
362 let b7 = a7 - (a1 >> 2);
363 let b3 = a3 + (a5 >> 2);
364 let b5 = (a3 >> 2) - a5;
365 [b0 + b7, b2 + b5, b4 + b3, b6 + b1, b6 - b1, b4 - b3, b2 - b5, b0 - b7]
366}
367
368#[inline]
371fn fwd_1d_8x8(s: &[i32; 8]) -> [i32; 8] {
372 let a0 = s[0] + s[7];
373 let a1 = s[1] + s[6];
374 let a2 = s[2] + s[5];
375 let a3 = s[3] + s[4];
376 let a4 = s[0] - s[7];
377 let a5 = s[1] - s[6];
378 let a6 = s[2] - s[5];
379 let a7 = s[3] - s[4];
380 let b0 = a0 + a3;
381 let b1 = a1 + a2;
382 let b2 = a0 - a3;
383 let b3 = a1 - a2;
384 let y0 = b0 + b1;
385 let y2 = b2 + (b3 >> 1);
386 let y4 = b0 - b1;
387 let y6 = (b2 >> 1) - b3;
388 let b4 = a5 + a6 + ((a4 >> 1) + a4);
389 let b5 = a4 - a7 - ((a6 >> 1) + a6);
390 let b6 = a4 + a7 - ((a5 >> 1) + a5);
391 let b7 = a5 - a6 + ((a7 >> 1) + a7);
392 let y1 = b4 + (b7 >> 2);
393 let y3 = b5 + (b6 >> 2);
394 let y5 = b6 - (b5 >> 2);
395 let y7 = (b4 >> 2) - b7;
396 [y0, y1, y2, y3, y4, y5, y6, y7]
397}
398
399pub fn inverse_core_8x8(coeffs: &[i32; 64]) -> [i32; 64] {
402 let _g = crate::prof::scope(crate::prof::Stage::Reconstruct);
403 let mut m = *coeffs;
404 for r in 0..8 {
405 let row: [i32; 8] = std::array::from_fn(|k| m[r * 8 + k]);
406 let o = inv_1d_8x8(&row);
407 for k in 0..8 {
408 m[r * 8 + k] = o[k];
409 }
410 }
411 for c in 0..8 {
412 let col: [i32; 8] = std::array::from_fn(|k| m[k * 8 + c]);
413 let o = inv_1d_8x8(&col);
414 for k in 0..8 {
415 m[k * 8 + c] = o[k];
416 }
417 }
418 for v in m.iter_mut() {
419 *v = (*v + 32) >> 6;
420 }
421 m
422}
423
424pub fn forward_core_8x8(res: &[i32; 64]) -> [i32; 64] {
428 let mut m = *res;
429 for r in 0..8 {
430 let row: [i32; 8] = std::array::from_fn(|k| m[r * 8 + k]);
431 let o = fwd_1d_8x8(&row);
432 for k in 0..8 {
433 m[r * 8 + k] = o[k];
434 }
435 }
436 for c in 0..8 {
437 let col: [i32; 8] = std::array::from_fn(|k| m[k * 8 + c]);
438 let o = fwd_1d_8x8(&col);
439 for k in 0..8 {
440 m[k * 8 + c] = o[k];
441 }
442 }
443 m
444}
445
446pub fn dequantize_8x8(levels: &[i32; 64], qp: u8, weight: &[i32; 64]) -> [i32; 64] {
449 let _g = crate::prof::scope(crate::prof::Stage::Dequant);
450 let m = (qp % 6) as usize;
451 let shift = (qp / 6) as i32;
452 let mut out = [0i32; 64];
453 if qp >= 36 {
454 let sh = shift - 6;
455 for idx in 0..64 {
456 let ls = weight[idx] * NORM_ADJUST_8X8[m][POS_GROUP_8X8_FLAT[idx]];
457 out[idx] = (levels[idx] * ls) << sh;
458 }
459 } else {
460 let add = 1 << (5 - shift);
461 let sh = 6 - shift;
462 for idx in 0..64 {
463 let ls = weight[idx] * NORM_ADJUST_8X8[m][POS_GROUP_8X8_FLAT[idx]];
464 out[idx] = (levels[idx] * ls + add) >> sh;
465 }
466 }
467 out
468}
469
470pub fn inverse_quant_8x8(levels: &[i32; 64], qp: u8, weight: &[i32; 64]) -> [i32; 64] {
472 inverse_core_8x8(&dequantize_8x8(levels, qp, weight))
473}
474
475const QUANT_MF_8X8: [[i32; 6]; 6] = [
480 [13107, 14564, 8192, 13797, 10486, 10923],
481 [11916, 13797, 7490, 12483, 9362, 10083],
482 [10083, 11398, 6242, 10923, 7944, 8456],
483 [9362, 10486, 5825, 10083, 7490, 7944],
484 [8192, 9362, 5140, 8738, 6554, 6899],
485 [7282, 8192, 4520, 7710, 5699, 6096],
486];
487
488pub fn quantize_8x8(coeffs: &[i32; 64], qp: u8, weight: &[i32; 64], dz_div: i64) -> [i32; 64] {
493 let m = (qp % 6) as usize;
494 let qbits = 16 + (qp / 6) as i64;
495 let ff = (1i64 << qbits) / dz_div;
496 let mut out = [0i32; 64];
497 for idx in 0..64 {
498 let mf = QUANT_MF_8X8[m][POS_GROUP_8X8_FLAT[idx]] as i64 * 16 / weight[idx] as i64;
499 let a = coeffs[idx].unsigned_abs() as i64;
500 let lvl = ((a * mf + ff) >> qbits) as i32;
501 out[idx] = if coeffs[idx] < 0 { -lvl } else { lvl };
502 }
503 out
504}
505
506#[inline]
510fn hadamard_1d(a: i32, b: i32, c: i32, d: i32) -> (i32, i32, i32, i32) {
511 (a + b + c + d, a + b - c - d, a - b - c + d, a - b + c - d)
512}
513
514pub fn hadamard_4x4(block: &[i32; 16]) -> [i32; 16] {
517 let mut m = *block;
518 for r in 0..4 {
519 let (a, b, c, d) = hadamard_1d(m[r * 4], m[r * 4 + 1], m[r * 4 + 2], m[r * 4 + 3]);
520 m[r * 4] = a;
521 m[r * 4 + 1] = b;
522 m[r * 4 + 2] = c;
523 m[r * 4 + 3] = d;
524 }
525 for c in 0..4 {
526 let (a, b, cc, d) = hadamard_1d(m[c], m[4 + c], m[8 + c], m[12 + c]);
527 m[c] = a;
528 m[4 + c] = b;
529 m[8 + c] = cc;
530 m[12 + c] = d;
531 }
532 m
533}
534
535#[inline]
538fn had4_simd(
539 a: wide::i32x4,
540 b: wide::i32x4,
541 c: wide::i32x4,
542 d: wide::i32x4,
543) -> (wide::i32x4, wide::i32x4, wide::i32x4, wide::i32x4) {
544 (a + b + c + d, a + b - c - d, a - b - c + d, a - b + c - d)
545}
546
547fn satd_4x4_x4(b: [&[i32; 16]; 4]) -> i64 {
552 use wide::i32x4;
553 let mut v = [i32x4::from([0i32; 4]); 16];
555 for (p, slot) in v.iter_mut().enumerate() {
556 *slot = i32x4::from([b[0][p], b[1][p], b[2][p], b[3][p]]);
557 }
558 for r in 0..4 {
560 let i = r * 4;
561 let (a, c, d, e) = had4_simd(v[i], v[i + 1], v[i + 2], v[i + 3]);
562 (v[i], v[i + 1], v[i + 2], v[i + 3]) = (a, c, d, e);
563 }
564 for c in 0..4 {
566 let (a, b2, d, e) = had4_simd(v[c], v[c + 4], v[c + 8], v[c + 12]);
567 (v[c], v[c + 4], v[c + 8], v[c + 12]) = (a, b2, d, e);
568 }
569 let zero = i32x4::from([0i32; 4]);
571 let mut acc = zero;
572 for x in v {
573 acc += zero.max(x) - zero.min(x);
574 }
575 acc.to_array().iter().map(|&s| s as i64).sum()
576}
577
578pub fn satd_4x4_sum(blocks: &[[i32; 16]]) -> i64 {
581 let mut total = 0i64;
582 let mut chunks = blocks.chunks_exact(4);
583 for g in &mut chunks {
584 total += satd_4x4_x4([&g[0], &g[1], &g[2], &g[3]]);
585 }
586 for res in chunks.remainder() {
587 total += hadamard_4x4(res).iter().map(|&v| v.unsigned_abs() as i64).sum::<i64>();
588 }
589 total
590}
591
592#[inline]
595fn fwd_1d_simd(
596 x0: wide::i32x4,
597 x1: wide::i32x4,
598 x2: wide::i32x4,
599 x3: wide::i32x4,
600) -> (wide::i32x4, wide::i32x4, wide::i32x4, wide::i32x4) {
601 let t0 = x0 + x3;
602 let t1 = x1 + x2;
603 let t2 = x1 - x2;
604 let t3 = x0 - x3;
605 (t0 + t1, (t3 + t3) + t2, t0 - t1, t3 - (t2 + t2))
606}
607
608fn forward_core_x4(b: [&[i32; 16]; 4]) -> [[i32; 16]; 4] {
612 use wide::i32x4;
613 let mut v = [i32x4::from([0i32; 4]); 16];
614 for (p, slot) in v.iter_mut().enumerate() {
615 *slot = i32x4::from([b[0][p], b[1][p], b[2][p], b[3][p]]);
616 }
617 for r in 0..4 {
618 let i = r * 4;
619 let (a, c, d, e) = fwd_1d_simd(v[i], v[i + 1], v[i + 2], v[i + 3]);
620 (v[i], v[i + 1], v[i + 2], v[i + 3]) = (a, c, d, e);
621 }
622 for c in 0..4 {
623 let (a, b2, d, e) = fwd_1d_simd(v[c], v[c + 4], v[c + 8], v[c + 12]);
624 (v[c], v[c + 4], v[c + 8], v[c + 12]) = (a, b2, d, e);
625 }
626 let mut out = [[0i32; 16]; 4];
627 for (p, vp) in v.iter().enumerate() {
628 let a = vp.to_array();
629 for k in 0..4 {
630 out[k][p] = a[k];
631 }
632 }
633 out
634}
635
636#[inline]
640fn fwd_1d_simd8(
641 x0: wide::i32x8,
642 x1: wide::i32x8,
643 x2: wide::i32x8,
644 x3: wide::i32x8,
645) -> (wide::i32x8, wide::i32x8, wide::i32x8, wide::i32x8) {
646 let t0 = x0 + x3;
647 let t1 = x1 + x2;
648 let t2 = x1 - x2;
649 let t3 = x0 - x3;
650 (t0 + t1, (t3 + t3) + t2, t0 - t1, t3 - (t2 + t2))
651}
652
653fn forward_core_x8(b: [&[i32; 16]; 8]) -> [[i32; 16]; 8] {
656 use wide::i32x8;
657 let mut v = [i32x8::from([0i32; 8]); 16];
658 for (p, slot) in v.iter_mut().enumerate() {
659 *slot = i32x8::from([
660 b[0][p], b[1][p], b[2][p], b[3][p], b[4][p], b[5][p], b[6][p], b[7][p],
661 ]);
662 }
663 for r in 0..4 {
664 let i = r * 4;
665 let (a, c, d, e) = fwd_1d_simd8(v[i], v[i + 1], v[i + 2], v[i + 3]);
666 (v[i], v[i + 1], v[i + 2], v[i + 3]) = (a, c, d, e);
667 }
668 for c in 0..4 {
669 let (a, b2, d, e) = fwd_1d_simd8(v[c], v[c + 4], v[c + 8], v[c + 12]);
670 (v[c], v[c + 4], v[c + 8], v[c + 12]) = (a, b2, d, e);
671 }
672 let mut out = [[0i32; 16]; 8];
673 for (p, vp) in v.iter().enumerate() {
674 let a = vp.to_array();
675 for k in 0..8 {
676 out[k][p] = a[k];
677 }
678 }
679 out
680}
681
682pub fn forward_dct_blocks(res: &[[i32; 16]], out: &mut [[i32; 16]]) {
686 let mut i = 0;
687 let mut c8 = res.chunks_exact(8);
688 for g in &mut c8 {
689 let r = forward_core_x8([&g[0], &g[1], &g[2], &g[3], &g[4], &g[5], &g[6], &g[7]]);
690 out[i..i + 8].clone_from_slice(&r);
691 i += 8;
692 }
693 let mut c4 = c8.remainder().chunks_exact(4);
694 for g in &mut c4 {
695 let r = forward_core_x4([&g[0], &g[1], &g[2], &g[3]]);
696 out[i..i + 4].clone_from_slice(&r);
697 i += 4;
698 }
699 for r in c4.remainder() {
700 out[i] = forward_core(r);
701 i += 1;
702 }
703}
704
705#[inline]
709fn inv_1d_simd(
710 d0: wide::i32x4,
711 d1: wide::i32x4,
712 d2: wide::i32x4,
713 d3: wide::i32x4,
714) -> (wide::i32x4, wide::i32x4, wide::i32x4, wide::i32x4) {
715 let e0 = d0 + d2;
716 let e1 = d0 - d2;
717 let e2 = (d1 >> 1) - d3;
718 let e3 = d1 + (d3 >> 1);
719 (e0 + e3, e1 + e2, e1 - e2, e0 - e3)
720}
721
722fn inverse_core_x4(b: [&[i32; 16]; 4]) -> [[i32; 16]; 4] {
725 use wide::i32x4;
726 let mut v = [i32x4::from([0i32; 4]); 16];
727 for (p, slot) in v.iter_mut().enumerate() {
728 *slot = i32x4::from([b[0][p], b[1][p], b[2][p], b[3][p]]);
729 }
730 for r in 0..4 {
731 let i = r * 4;
732 let (a, c, d, e) = inv_1d_simd(v[i], v[i + 1], v[i + 2], v[i + 3]);
733 (v[i], v[i + 1], v[i + 2], v[i + 3]) = (a, c, d, e);
734 }
735 for c in 0..4 {
736 let (a, b2, d, e) = inv_1d_simd(v[c], v[c + 4], v[c + 8], v[c + 12]);
737 (v[c], v[c + 4], v[c + 8], v[c + 12]) = (a, b2, d, e);
738 }
739 let off = i32x4::from([32i32; 4]);
740 for vp in v.iter_mut() {
741 *vp = (*vp + off) >> 6;
742 }
743 let mut out = [[0i32; 16]; 4];
744 for (p, vp) in v.iter().enumerate() {
745 let a = vp.to_array();
746 for k in 0..4 {
747 out[k][p] = a[k];
748 }
749 }
750 out
751}
752
753#[inline]
755fn inv_1d_simd8(
756 d0: wide::i32x8,
757 d1: wide::i32x8,
758 d2: wide::i32x8,
759 d3: wide::i32x8,
760) -> (wide::i32x8, wide::i32x8, wide::i32x8, wide::i32x8) {
761 let e0 = d0 + d2;
762 let e1 = d0 - d2;
763 let e2 = (d1 >> 1) - d3;
764 let e3 = d1 + (d3 >> 1);
765 (e0 + e3, e1 + e2, e1 - e2, e0 - e3)
766}
767
768fn inverse_core_x8(b: [&[i32; 16]; 8]) -> [[i32; 16]; 8] {
771 use wide::i32x8;
772 let mut v = [i32x8::from([0i32; 8]); 16];
773 for (p, slot) in v.iter_mut().enumerate() {
774 *slot = i32x8::from([
775 b[0][p], b[1][p], b[2][p], b[3][p], b[4][p], b[5][p], b[6][p], b[7][p],
776 ]);
777 }
778 for r in 0..4 {
779 let i = r * 4;
780 let (a, c, d, e) = inv_1d_simd8(v[i], v[i + 1], v[i + 2], v[i + 3]);
781 (v[i], v[i + 1], v[i + 2], v[i + 3]) = (a, c, d, e);
782 }
783 for c in 0..4 {
784 let (a, b2, d, e) = inv_1d_simd8(v[c], v[c + 4], v[c + 8], v[c + 12]);
785 (v[c], v[c + 4], v[c + 8], v[c + 12]) = (a, b2, d, e);
786 }
787 let off = i32x8::from([32i32; 8]);
788 for vp in v.iter_mut() {
789 *vp = (*vp + off) >> 6;
790 }
791 let mut out = [[0i32; 16]; 8];
792 for (p, vp) in v.iter().enumerate() {
793 let a = vp.to_array();
794 for k in 0..8 {
795 out[k][p] = a[k];
796 }
797 }
798 out
799}
800
801pub fn inverse_dct_blocks(coeffs: &[[i32; 16]], out: &mut [[i32; 16]]) {
807 let mut i = 0;
808 let mut c8 = coeffs.chunks_exact(8);
809 for g in &mut c8 {
810 let r = inverse_core_x8([&g[0], &g[1], &g[2], &g[3], &g[4], &g[5], &g[6], &g[7]]);
811 out[i..i + 8].clone_from_slice(&r);
812 i += 8;
813 }
814 let mut c4 = c8.remainder().chunks_exact(4);
815 for g in &mut c4 {
816 let r = inverse_core_x4([&g[0], &g[1], &g[2], &g[3]]);
817 out[i..i + 4].clone_from_slice(&r);
818 i += 4;
819 }
820 for r in c4.remainder() {
821 out[i] = inverse_core(r);
822 i += 1;
823 }
824}
825
826
827pub fn forward_quant_luma_dc(dc: &[i32; 16], qp: u8, intra: bool) -> [i32; 16] {
830 let f = hadamard_4x4(dc);
831 let m = (qp % 6) as usize;
832 let qbits = 17 + (qp / 6) as u32;
836 let off: i64 = if intra { (1i64 << qbits) / 3 } else { (1i64 << qbits) / 6 };
837 let mf = QUANT_MF[m][0] as i64;
838 let mut out = [0i32; 16];
839 for (o, &fv) in out.iter_mut().zip(f.iter()) {
840 let level = ((fv.abs() as i64) * mf + off) >> qbits;
841 *o = if fv < 0 { -level as i32 } else { level as i32 };
842 }
843 out
844}
845
846pub fn inverse_quant_luma_dc(levels: &[i32; 16], qp: u8) -> [i32; 16] {
849 let _g = crate::prof::scope(crate::prof::Stage::Dequant);
850 let g = hadamard_4x4(levels);
851 let m = (qp % 6) as usize;
852 let shift = (qp / 6) as i32;
853 let level_scale = 16 * NORM_ADJUST[m][0];
854 let mut out = [0i32; 16];
855 for (o, &gv) in out.iter_mut().zip(g.iter()) {
856 *o = if qp >= 36 {
857 (gv * level_scale) << (shift - 6)
858 } else {
859 (gv * level_scale + (1 << (5 - shift))) >> (6 - shift)
860 };
861 }
862 out
863}
864
865pub fn inverse_quant_luma_dc_weighted(levels: &[i32; 16], qp: u8, w00: i32) -> [i32; 16] {
868 let g = hadamard_4x4(levels);
869 let m = (qp % 6) as usize;
870 let shift = (qp / 6) as i32;
871 let level_scale = w00 * NORM_ADJUST[m][0];
872 let mut out = [0i32; 16];
873 for (o, &gv) in out.iter_mut().zip(g.iter()) {
874 *o = if qp >= 36 {
875 (gv * level_scale) << (shift - 6)
876 } else {
877 (gv * level_scale + (1 << (5 - shift))) >> (6 - shift)
878 };
879 }
880 out
881}
882
883pub fn inverse_quant_chroma_dc_weighted(levels: &[i32; 4], qp: u8, w00: i32) -> [i32; 4] {
885 let g = hadamard_2x2(levels);
886 let m = (qp % 6) as usize;
887 let shift = (qp / 6) as i32;
888 let level_scale = w00 * NORM_ADJUST[m][0];
889 let mut out = [0i32; 4];
890 for (o, &gv) in out.iter_mut().zip(g.iter()) {
891 *o = ((gv * level_scale) << shift) >> 5;
892 }
893 out
894}
895
896pub fn hadamard_2x2(dc: &[i32; 4]) -> [i32; 4] {
898 let (a, b, c, d) = (dc[0], dc[1], dc[2], dc[3]);
899 [a + b + c + d, a - b + c - d, a + b - c - d, a - b - c + d]
900}
901
902pub fn forward_quant_chroma_dc(dc: &[i32; 4], qp: u8, intra: bool) -> [i32; 4] {
904 let f = hadamard_2x2(dc);
905 let m = (qp % 6) as usize;
906 let qbits = 15 + (qp / 6) as u32;
907 let off: i64 = if intra { (1i64 << qbits) / 3 } else { (1i64 << qbits) / 6 };
908 let mf = QUANT_MF[m][0] as i64;
909 let mut out = [0i32; 4];
910 for (o, &fv) in out.iter_mut().zip(f.iter()) {
911 let level = ((fv.abs() as i64) * mf + 2 * off) >> (qbits + 1);
912 *o = if fv < 0 { -level as i32 } else { level as i32 };
913 }
914 out
915}
916
917pub fn inverse_quant_chroma_dc(levels: &[i32; 4], qp: u8) -> [i32; 4] {
919 let _g = crate::prof::scope(crate::prof::Stage::Dequant);
920 let g = hadamard_2x2(levels);
921 let m = (qp % 6) as usize;
922 let shift = (qp / 6) as i32;
923 let level_scale = 16 * NORM_ADJUST[m][0];
924 let mut out = [0i32; 4];
925 for (o, &gv) in out.iter_mut().zip(g.iter()) {
926 *o = ((gv * level_scale) << shift) >> 5;
927 }
928 out
929}
930
931#[cfg(test)]
932mod tests {
933 use super::*;
934
935 #[test]
936 fn batched_forward_dct_matches_scalar() {
937 let mut state = 0x9e37_79b9u32;
938 let mut next = || {
939 state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
940 ((state >> 16) % 511) as i32 - 255
941 };
942 for n in 1..=18 {
943 let res: Vec<[i32; 16]> = (0..n).map(|_| std::array::from_fn(|_| next())).collect();
944 let mut out = vec![[0i32; 16]; n];
945 forward_dct_blocks(&res, &mut out);
946 for (r, o) in res.iter().zip(&out) {
947 assert_eq!(&forward_core(r), o, "n={n}");
948 }
949 }
950 }
951
952 #[test]
953 fn batched_inverse_dct_matches_scalar() {
954 let mut state = 0x0bad_f00du32;
958 let mut next = || {
959 state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
960 ((state >> 12) % 8191) as i32 - 4095
961 };
962 for n in 1..=18 {
963 let coeffs: Vec<[i32; 16]> = (0..n).map(|_| std::array::from_fn(|_| next())).collect();
964 let mut out = vec![[0i32; 16]; n];
965 inverse_dct_blocks(&coeffs, &mut out);
966 for (c, o) in coeffs.iter().zip(&out) {
967 assert_eq!(&inverse_core(c), o, "n={n}");
968 }
969 }
970 }
971
972 #[test]
973 fn simd_satd_matches_scalar() {
974 let scalar = |res: &[i32; 16]| -> i64 {
976 hadamard_4x4(res).iter().map(|&v| v.unsigned_abs() as i64).sum()
977 };
978 let mut state = 0x1234_5678u32;
980 let mut next = || {
981 state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
982 ((state >> 16) % 511) as i32 - 255
983 };
984 for n in 1..=20 {
985 let blocks: Vec<[i32; 16]> =
986 (0..n).map(|_| std::array::from_fn(|_| next())).collect();
987 let expect: i64 = blocks.iter().map(&scalar).sum();
988 assert_eq!(satd_4x4_sum(&blocks), expect, "n={n}");
989 }
990 }
991
992 #[test]
993 fn forward_inverse_core_are_consistent_scale() {
994 let block = [4i32; 16];
997 let w = forward_core(&block);
998 assert_eq!(w[0], 64, "DC coefficient");
999 for (k, &ac) in w.iter().enumerate().skip(1) {
1000 assert_eq!(ac, 0, "AC[{k}] should be zero for a flat block");
1001 }
1002 }
1003
1004 #[test]
1005 fn forward_core_8x8_flat_block_is_dc_only() {
1006 let block = [4i32; 64];
1009 let w = forward_core_8x8(&block);
1010 assert_eq!(w[0], 256, "8×8 DC coefficient");
1011 for (k, &ac) in w.iter().enumerate().skip(1) {
1012 assert_eq!(ac, 0, "8×8 AC[{k}] should be zero for a flat block");
1013 }
1014 }
1015
1016 #[test]
1017 fn inverse_core_8x8_dc_only_is_flat() {
1018 let mut coeffs = [0i32; 64];
1020 coeffs[0] = 256;
1021 let r = inverse_core_8x8(&coeffs);
1022 for (k, &v) in r.iter().enumerate() {
1023 assert_eq!(v, (256 + 32) >> 6, "8×8 inverse DC pixel {k}");
1024 }
1025 }
1026
1027 #[test]
1028 fn quant_dequant_8x8_round_trip_near_identity() {
1029 let weight = [16i32; 64];
1035 for &val in &[0i32, 4, -7, 31] {
1036 let block = [val; 64];
1037 let fwd = forward_core_8x8(&block);
1038 let deq = dequantize_8x8(&fwd, 24, &weight);
1041 let _ = deq; let recon = inverse_core_8x8(&fwd);
1043 assert_eq!(recon, block, "flat 8×8 must round-trip through the core");
1044 }
1045 }
1046
1047 #[test]
1048 fn quantize_8x8_round_trips_through_the_decoder_path() {
1049 let weight = [16i32; 64];
1053 let res: [i32; 64] = std::array::from_fn(|i| {
1055 let (x, y) = (i % 8, i / 8);
1056 (((x * 7 + y * 13) % 23) as i32 - 11) * 4 + ((x as i32 - y as i32) * 3)
1057 });
1058 for &qp in &[12u8, 22, 30, 40, 48] {
1059 let coeffs = forward_core_8x8(&res);
1060 let levels = quantize_8x8(&coeffs, qp, &weight, 2); let deq = dequantize_8x8(&levels, qp, &weight);
1063 for i in 0..64 {
1064 let step = (1i32 << (qp / 6)) * 64;
1066 assert!(
1067 (deq[i] - coeffs[i]).abs() <= step,
1068 "qp{qp} pos{i}: dequant {} vs coeff {} exceeds step {step}",
1069 deq[i],
1070 coeffs[i]
1071 );
1072 }
1073 let recon = inverse_core_8x8(&deq);
1075 let mae: i32 =
1076 (0..64).map(|i| (recon[i] - res[i]).abs()).sum::<i32>() / 64;
1077 let bound = 2 + (1i32 << (qp / 6)); assert!(mae <= bound, "qp{qp}: 8×8 recon MAE {mae} exceeds {bound}");
1079 }
1080 }
1081
1082 #[test]
1083 fn dequant_8x8_flat_matches_levelscale() {
1084 let mut levels = [0i32; 64];
1086 levels[0] = 3;
1087 let weight = [16i32; 64];
1088 let d = dequantize_8x8(&levels, 30, &weight);
1089 let ls = 16 * NORM_ADJUST_8X8[0][0];
1091 assert_eq!(d[0], (3 * ls + 1) >> 1);
1092 }
1093
1094 #[test]
1095 fn inverse_core_is_row_first() {
1096 let coeffs = [9, 2, -1, 2, -2, 2, -2, 1, -1, -2, 3, 5, -1, -1, -5, 3];
1102 let mut rows_then_cols = coeffs;
1103 for r in 0..4 {
1104 let (a, b, c, d) = inv_1d(
1105 rows_then_cols[r * 4],
1106 rows_then_cols[r * 4 + 1],
1107 rows_then_cols[r * 4 + 2],
1108 rows_then_cols[r * 4 + 3],
1109 );
1110 rows_then_cols[r * 4] = a;
1111 rows_then_cols[r * 4 + 1] = b;
1112 rows_then_cols[r * 4 + 2] = c;
1113 rows_then_cols[r * 4 + 3] = d;
1114 }
1115 for c in 0..4 {
1116 let (a, b, cc, d) = inv_1d(
1117 rows_then_cols[c],
1118 rows_then_cols[4 + c],
1119 rows_then_cols[8 + c],
1120 rows_then_cols[12 + c],
1121 );
1122 rows_then_cols[c] = a;
1123 rows_then_cols[4 + c] = b;
1124 rows_then_cols[8 + c] = cc;
1125 rows_then_cols[12 + c] = d;
1126 }
1127 let mut cols_then_rows = coeffs;
1128 for c in 0..4 {
1129 let (a, b, cc, d) = inv_1d(
1130 cols_then_rows[c],
1131 cols_then_rows[4 + c],
1132 cols_then_rows[8 + c],
1133 cols_then_rows[12 + c],
1134 );
1135 cols_then_rows[c] = a;
1136 cols_then_rows[4 + c] = b;
1137 cols_then_rows[8 + c] = cc;
1138 cols_then_rows[12 + c] = d;
1139 }
1140 for r in 0..4 {
1141 let (a, b, c, d) = inv_1d(
1142 cols_then_rows[r * 4],
1143 cols_then_rows[r * 4 + 1],
1144 cols_then_rows[r * 4 + 2],
1145 cols_then_rows[r * 4 + 3],
1146 );
1147 cols_then_rows[r * 4] = a;
1148 cols_then_rows[r * 4 + 1] = b;
1149 cols_then_rows[r * 4 + 2] = c;
1150 cols_then_rows[r * 4 + 3] = d;
1151 }
1152 assert_ne!(rows_then_cols, cols_then_rows);
1154 let expected: [i32; 16] =
1156 core::array::from_fn(|k| (rows_then_cols[k] + 32) >> 6);
1157 assert_eq!(inverse_core(&coeffs), expected);
1158 }
1159
1160 #[test]
1161 fn quant_dequant_roundtrip_is_near_identity() {
1162 let residual: [i32; 16] = [
1165 5, -3, 8, 0, 12, -7, 2, 1, -4, 6, 9, -2, 0, 3, -1, 7,
1166 ];
1167 for qp in [0u8, 6, 12, 18, 26, 30, 37, 45, 51] {
1168 let levels = forward_quant(&residual, qp, true);
1169 let recon = inverse_quant(&levels, qp);
1170 let tol = 2 + (1 << (qp / 6));
1172 for k in 0..16 {
1173 let diff = (recon[k] - residual[k]).abs();
1174 assert!(
1175 diff <= tol,
1176 "qp {qp}: residual[{k}]={} recon={} diff={diff} tol={tol}",
1177 residual[k],
1178 recon[k]
1179 );
1180 }
1181 }
1182 }
1183
1184 #[test]
1185 fn trellis_never_exceeds_scalar_magnitude() {
1186 let coeffs: [i32; 16] = [120, -40, 8, 1, -15, 6, -1, 0, 3, -2, 1, 0, 0, 1, 0, 0];
1189 let scalar = quantize(&coeffs, 26, 3);
1190 let t = trellis_quant(&coeffs, 26, true, 50.0);
1191 for k in 0..16 {
1192 assert!(t[k].unsigned_abs() <= scalar[k].unsigned_abs(), "[{k}]");
1193 assert!(t[k] == 0 || t[k].signum() == scalar[k].signum());
1194 }
1195 }
1196
1197 #[test]
1198 fn zero_residual_stays_zero() {
1199 let zero = [0i32; 16];
1200 let levels = forward_quant(&zero, 28, true);
1201 assert_eq!(levels, [0i32; 16]);
1202 assert_eq!(inverse_quant(&levels, 28), [0i32; 16]);
1203 }
1204
1205 #[test]
1206 fn luma_dc_end_to_end_flat_block() {
1207 for r in [3i32, 9, -5, 20] {
1211 for qp in [0u8, 12, 24, 30] {
1212 let w_dc = [16 * r; 16]; let z = forward_quant_luma_dc(&w_dc, qp, true);
1214 let dcy = inverse_quant_luma_dc(&z, qp);
1215 let tol = 1 + (1 << (qp / 6));
1216 for (b, &dc) in dcy.iter().enumerate() {
1217 let mut coeff = [0i32; 16];
1218 coeff[0] = dc;
1219 let res = inverse_core(&coeff);
1220 for &v in &res {
1221 assert!((v - r).abs() <= tol, "luma DC r={r} qp{qp} blk{b}: {v} vs {r}");
1222 }
1223 }
1224 }
1225 }
1226 }
1227
1228 #[test]
1229 fn chroma_dc_end_to_end_flat_block() {
1230 for r in [4i32, -6, 11] {
1232 for qp in [0u8, 18, 30] {
1233 let dc = [16 * r; 4];
1234 let z = forward_quant_chroma_dc(&dc, qp, true);
1235 let dcy = inverse_quant_chroma_dc(&z, qp);
1236 let tol = 1 + (1 << (qp / 6));
1237 for &d in &dcy {
1238 let mut coeff = [0i32; 16];
1239 coeff[0] = d;
1240 let res = inverse_core(&coeff);
1241 for &v in &res {
1242 assert!((v - r).abs() <= tol, "chroma DC r={r} qp{qp}: {v} vs {r}");
1243 }
1244 }
1245 }
1246 }
1247 }
1248
1249 #[test]
1250 fn hadamard_is_self_inverse_scaled() {
1251 let x: [i32; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
1253 let twice = hadamard_4x4(&hadamard_4x4(&x));
1254 for (k, (&a, &b)) in x.iter().zip(twice.iter()).enumerate() {
1255 assert_eq!(b, a * 16, "[{k}]");
1256 }
1257 }
1258
1259 #[test]
1260 fn low_qp_is_high_fidelity() {
1261 let residual: [i32; 16] = [1, 2, 3, 4, -1, -2, -3, -4, 0, 1, 0, -1, 2, -2, 1, 0];
1264 let levels = forward_quant(&residual, 0, true);
1265 let recon = inverse_quant(&levels, 0);
1266 for (k, (&r, &o)) in residual.iter().zip(recon.iter()).enumerate() {
1267 assert!((o - r).abs() <= 1, "qp0 residual[{k}]={r} recon={o}");
1268 }
1269 }
1270}
1271
1272pub const QUANT_MF_OH: [[i16; 8]; 52] = [
1274 [26214, 16132, 26214, 16132, 16132, 10486, 16132, 10486],
1275 [23832, 14980, 23832, 14980, 14980, 9320, 14980, 9320],
1276 [20164, 13108, 20164, 13108, 13108, 8388, 13108, 8388],
1277 [18724, 11650, 18724, 11650, 11650, 7294, 11650, 7294],
1278 [16384, 10486, 16384, 10486, 10486, 6710, 10486, 6710],
1279 [14564, 9118, 14564, 9118, 9118, 5786, 9118, 5786],
1280 [13107, 8066, 13107, 8066, 8066, 5243, 8066, 5243],
1281 [11916, 7490, 11916, 7490, 7490, 4660, 7490, 4660],
1282 [10082, 6554, 10082, 6554, 6554, 4194, 6554, 4194],
1283 [9362, 5825, 9362, 5825, 5825, 3647, 5825, 3647],
1284 [8192, 5243, 8192, 5243, 5243, 3355, 5243, 3355],
1285 [7282, 4559, 7282, 4559, 4559, 2893, 4559, 2893],
1286 [6554, 4033, 6554, 4033, 4033, 2622, 4033, 2622],
1287 [5958, 3745, 5958, 3745, 3745, 2330, 3745, 2330],
1288 [5041, 3277, 5041, 3277, 3277, 2097, 3277, 2097],
1289 [4681, 2913, 4681, 2913, 2913, 1824, 2913, 1824],
1290 [4096, 2622, 4096, 2622, 2622, 1678, 2622, 1678],
1291 [3641, 2280, 3641, 2280, 2280, 1447, 2280, 1447],
1292 [3277, 2017, 3277, 2017, 2017, 1311, 2017, 1311],
1293 [2979, 1873, 2979, 1873, 1873, 1165, 1873, 1165],
1294 [2521, 1639, 2521, 1639, 1639, 1049, 1639, 1049],
1295 [2341, 1456, 2341, 1456, 1456, 912, 1456, 912],
1296 [2048, 1311, 2048, 1311, 1311, 839, 1311, 839],
1297 [1821, 1140, 1821, 1140, 1140, 723, 1140, 723],
1298 [1638, 1008, 1638, 1008, 1008, 655, 1008, 655],
1299 [1490, 936, 1490, 936, 936, 583, 936, 583],
1300 [1260, 819, 1260, 819, 819, 524, 819, 524],
1301 [1170, 728, 1170, 728, 728, 456, 728, 456],
1302 [1024, 655, 1024, 655, 655, 419, 655, 419],
1303 [910, 570, 910, 570, 570, 362, 570, 362],
1304 [819, 504, 819, 504, 504, 328, 504, 328],
1305 [745, 468, 745, 468, 468, 291, 468, 291],
1306 [630, 410, 630, 410, 410, 262, 410, 262],
1307 [585, 364, 585, 364, 364, 228, 364, 228],
1308 [512, 328, 512, 328, 328, 210, 328, 210],
1309 [455, 285, 455, 285, 285, 181, 285, 181],
1310 [410, 252, 410, 252, 252, 164, 252, 164],
1311 [372, 234, 372, 234, 234, 146, 234, 146],
1312 [315, 205, 315, 205, 205, 131, 205, 131],
1313 [293, 182, 293, 182, 182, 114, 182, 114],
1314 [256, 164, 256, 164, 164, 105, 164, 105],
1315 [228, 142, 228, 142, 142, 90, 142, 90],
1316 [205, 126, 205, 126, 126, 82, 126, 82],
1317 [186, 117, 186, 117, 117, 73, 117, 73],
1318 [158, 102, 158, 102, 102, 66, 102, 66],
1319 [146, 91, 146, 91, 91, 57, 91, 57],
1320 [128, 82, 128, 82, 82, 52, 82, 52],
1321 [114, 71, 114, 71, 71, 45, 71, 45],
1322 [102, 63, 102, 63, 63, 41, 63, 41],
1323 [93, 59, 93, 59, 59, 36, 59, 36],
1324 [79, 51, 79, 51, 51, 33, 51, 33],
1325 [73, 46, 73, 46, 46, 28, 46, 28],
1326];
1327
1328pub const QUANT_FF_OH: [[i16; 8]; 58] = [
1329 [0, 1, 0, 1, 1, 1, 1, 1],
1330 [0, 1, 0, 1, 1, 1, 1, 1],
1331 [1, 1, 1, 1, 1, 1, 1, 1],
1332 [1, 1, 1, 1, 1, 1, 1, 1],
1333 [1, 1, 1, 1, 1, 2, 1, 2],
1334 [1, 1, 1, 1, 1, 2, 1, 2],
1335 [1, 1, 1, 1, 1, 2, 1, 2],
1336 [1, 1, 1, 1, 1, 2, 1, 2],
1337 [1, 2, 1, 2, 2, 3, 2, 3],
1338 [1, 2, 1, 2, 2, 3, 2, 3],
1339 [1, 2, 1, 2, 2, 3, 2, 3],
1340 [1, 2, 1, 2, 2, 4, 2, 4],
1341 [2, 3, 2, 3, 3, 4, 3, 4],
1342 [2, 3, 2, 3, 3, 5, 3, 5],
1343 [2, 3, 2, 3, 3, 5, 3, 5],
1344 [2, 4, 2, 4, 4, 6, 4, 6],
1345 [3, 4, 3, 4, 4, 7, 4, 7],
1346 [3, 5, 3, 5, 5, 8, 5, 8],
1347 [3, 5, 3, 5, 5, 8, 5, 8],
1348 [4, 6, 4, 6, 6, 9, 6, 9],
1349 [4, 7, 4, 7, 7, 10, 7, 10],
1350 [5, 8, 5, 8, 8, 12, 8, 12],
1351 [5, 8, 5, 8, 8, 13, 8, 13],
1352 [6, 10, 6, 10, 10, 15, 10, 15],
1353 [7, 11, 7, 11, 11, 17, 11, 17],
1354 [7, 12, 7, 12, 12, 19, 12, 19],
1355 [9, 13, 9, 13, 13, 21, 13, 21],
1356 [9, 15, 9, 15, 15, 24, 15, 24],
1357 [11, 17, 11, 17, 17, 26, 17, 26],
1358 [12, 19, 12, 19, 19, 30, 19, 30],
1359 [13, 22, 13, 22, 22, 33, 22, 33],
1360 [15, 23, 15, 23, 23, 38, 23, 38],
1361 [17, 27, 17, 27, 27, 42, 27, 42],
1362 [19, 30, 19, 30, 30, 48, 30, 48],
1363 [21, 33, 21, 33, 33, 52, 33, 52],
1364 [24, 38, 24, 38, 38, 60, 38, 60],
1365 [27, 43, 27, 43, 43, 67, 43, 67],
1366 [29, 47, 29, 47, 47, 75, 47, 75],
1367 [35, 53, 35, 53, 53, 83, 53, 83],
1368 [37, 60, 37, 60, 60, 96, 60, 96],
1369 [43, 67, 43, 67, 67, 104, 67, 104],
1370 [48, 77, 48, 77, 77, 121, 77, 121],
1371 [53, 87, 53, 87, 87, 133, 87, 133],
1372 [59, 93, 59, 93, 93, 150, 93, 150],
1373 [69, 107, 69, 107, 107, 167, 107, 167],
1374 [75, 120, 75, 120, 120, 192, 120, 192],
1375 [85, 133, 85, 133, 133, 208, 133, 208],
1376 [96, 153, 96, 153, 153, 242, 153, 242],
1377 [107, 173, 107, 173, 173, 267, 173, 267],
1378 [117, 187, 117, 187, 187, 300, 187, 300],
1379 [139, 213, 139, 213, 213, 333, 213, 333],
1380 [149, 240, 149, 240, 240, 383, 240, 383],
1381 [171, 267, 171, 267, 267, 417, 267, 417],
1382 [192, 307, 192, 307, 307, 483, 307, 483],
1383 [213, 347, 213, 347, 347, 533, 347, 533],
1384 [235, 373, 235, 373, 373, 600, 373, 600],
1385 [277, 427, 277, 427, 427, 667, 427, 667],
1386 [299, 480, 299, 480, 480, 767, 480, 767],
1387];