1use crate::bitio::{ByteReader, ByteWriter, DecodeError};
42use crate::codec::ErrorBound;
43use crate::coefcode::{band_class, KB, NCLASS, NE};
44use crate::wavelet::{forward_97, Pyramid, MAX_LEVELS, MAX_LEVELS_1D};
45
46pub const MAGIC: &[u8; 4] = b"TCG1";
48
49pub const QL: u32 = 24;
51
52fn qc(v: f64) -> i32 {
53 (v * (1u64 << QL) as f64).round() as i32
54}
55
56const ALPHA: f64 = -1.586_134_342_059_924;
57const BETA: f64 = -0.052_980_118_572_961;
58const GAMMA: f64 = 0.882_911_075_530_934;
59const DELTA: f64 = 0.443_506_852_043_971;
60const KAPPA: f64 = 1.149_604_398_860_241;
61
62pub fn lift_consts() -> [i32; 6] {
64 [
65 qc(1.0 / KAPPA),
66 qc(KAPPA),
67 qc(-DELTA),
68 qc(-GAMMA),
69 qc(-BETA),
70 qc(-ALPHA),
71 ]
72}
73
74#[inline]
76pub fn mulsh(a: i32, b: i32, s: u32) -> i32 {
77 ((a as i64 * b as i64 + (1i64 << (s - 1))) >> s) as i32
78}
79
80pub const MINIT: u32 = 0x8000_8000;
84
85#[inline]
86pub(crate) fn mp1(m: u32) -> u32 {
87 (((m & 0xFFFF) + (m >> 16)) >> 1).clamp(32, 65504)
88}
89
90#[inline]
91fn mupd(m: u32, bit: bool) -> u32 {
92 let (mut f, mut s) = (m & 0xFFFF, m >> 16);
93 if bit {
94 f += (65535 - f) >> 4;
95 s += (65535 - s) >> 7;
96 } else {
97 f -= f >> 4;
98 s -= s >> 7;
99 }
100 f | s << 16
101}
102
103const A_TH: [u32; 11] = [0, 1, 2, 3, 5, 7, 10, 14, 20, 30, 48];
104const NA: usize = 12;
105const P_TH: [u32; 3] = [0, 2, 6];
106const NPB: usize = 5;
107
108pub const SIG0: usize = 0;
110const NSIG: usize = NCLASS * 2 * NA * NPB;
111pub const MAG0: usize = SIG0 + NSIG;
113pub const LOW0: usize = MAG0 + NCLASS * NE * KB;
115pub const SGN0: usize = LOW0 + NE * 4;
117pub const ESC0: usize = SGN0 + NCLASS * 9;
119pub const NMODEL: usize = ESC0 + NCLASS * 32;
121pub const NOMODEL: usize = 96;
123
124#[inline]
125fn bucket(a: u32, th: &[u32]) -> usize {
126 th.iter().position(|&t| a <= t).unwrap_or(th.len())
127}
128
129pub trait Sink {
134 fn bit(&mut self, lane: usize, bit: bool, p1: u32) -> bool;
136 fn raw(&mut self, lane: usize, v: u32, n: u32) -> u32;
138 #[inline]
140 fn note(&mut self, _idx: usize, _bit: bool) {}
141}
142
143pub struct RecSink {
145 pub syms: Vec<Vec<(u32, u32)>>,
147}
148
149impl Sink for RecSink {
150 #[inline]
151 fn bit(&mut self, lane: usize, bit: bool, p1: u32) -> bool {
152 let f0 = 65536 - p1;
153 self.syms[lane].push(if bit { (f0, p1) } else { (0, f0) });
154 bit
155 }
156 #[inline]
157 fn raw(&mut self, lane: usize, v: u32, n: u32) -> u32 {
158 let v = v & ((1u32 << n) - 1);
159 self.syms[lane].push((v << (16 - n), 1 << (16 - n)));
160 v
161 }
162}
163
164pub fn rans_encode(syms: &[(u32, u32)]) -> Vec<u16> {
166 if syms.is_empty() {
167 return Vec::new();
168 }
169 let mut x: u32 = 1 << 16;
170 let mut out: Vec<u16> = Vec::with_capacity(syms.len() / 8 + 4);
171 for &(cum, f) in syms.iter().rev() {
172 let xmax = f << 16;
173 if x >= xmax {
174 out.push(x as u16);
175 x >>= 16;
176 }
177 x = ((x / f) << 16) + (x % f) + cum;
178 }
179 out.push((x >> 16) as u16);
180 out.push(x as u16);
181 out.reverse();
183 out
184}
185
186#[derive(Clone, Debug)]
188pub struct RansDec<'a> {
189 w: &'a [u16],
190 pos: usize,
191 x: u32,
192}
193
194impl<'a> RansDec<'a> {
195 pub fn new(w: &'a [u16]) -> Self {
197 let x = if w.len() >= 2 {
198 w[0] as u32 | (w[1] as u32) << 16
199 } else {
200 1 << 16
201 };
202 Self { w, pos: 2, x }
203 }
204 #[inline]
205 fn step(&mut self, cum: u32, f: u32) {
206 self.x = f
207 .wrapping_mul(self.x >> 16)
208 .wrapping_add((self.x & 0xFFFF).wrapping_sub(cum));
209 if self.x < 1 << 16 {
210 let v = self.w.get(self.pos).copied().unwrap_or(0) as u32;
211 self.pos += 1;
212 self.x = (self.x << 16) | v;
213 }
214 }
215 #[inline]
217 pub fn bit(&mut self, p1: u32) -> bool {
218 let f0 = 65536 - p1;
219 let b = (self.x & 0xFFFF) >= f0;
220 if b {
221 self.step(f0, p1)
222 } else {
223 self.step(0, f0)
224 }
225 b
226 }
227 #[inline]
229 pub fn raw(&mut self, n: u32) -> u32 {
230 let v = (self.x & 0xFFFF) >> (16 - n);
231 self.step(v << (16 - n), 1 << (16 - n));
232 v
233 }
234 pub fn overrun(&self) -> bool {
236 self.w.len() >= 2 && self.pos > self.w.len()
237 }
238}
239
240pub struct DecSink<'a> {
242 pub lanes: Vec<RansDec<'a>>,
244}
245
246impl Sink for DecSink<'_> {
247 #[inline]
248 fn bit(&mut self, lane: usize, _: bool, p1: u32) -> bool {
249 self.lanes[lane].bit(p1)
250 }
251 #[inline]
252 fn raw(&mut self, lane: usize, _: u32, n: u32) -> u32 {
253 self.lanes[lane].raw(n)
254 }
255}
256
257#[inline]
258pub(crate) fn bitm<S: Sink, const A: bool>(
259 s: &mut S,
260 lane: usize,
261 m: &mut [u32],
262 idx: usize,
263 bit: bool,
264) -> bool {
265 let b = s.bit(lane, bit, mp1(m[idx]));
266 if A {
267 m[idx] = mupd(m[idx], b);
268 }
269 s.note(idx, b);
270 b
271}
272
273#[inline]
274pub(crate) fn raw_n<S: Sink>(s: &mut S, lane: usize, v: u32, mut n: u32) -> u32 {
275 let mut out = 0u32;
276 while n > 16 {
277 out = (out << 16) | s.raw(lane, v >> (n - 16), 16);
278 n -= 16;
279 }
280 if n > 0 {
281 out = (out << n) | s.raw(lane, v, n);
282 }
283 out
284}
285
286#[inline]
288pub(crate) fn gamma<S: Sink, const A: bool>(
289 s: &mut S,
290 lane: usize,
291 m: &mut [u32],
292 base: usize,
293 v: u32,
294) -> u32 {
295 let w = v.wrapping_add(1);
296 let nbe = 31 - w.max(1).leading_zeros();
297 let mut nb = 0u32;
298 while nb < 31 && bitm::<S, A>(s, lane, m, base + nb as usize, nb < nbe) {
299 nb += 1;
300 }
301 let lo = raw_n(s, lane, w, nb);
302 ((1u32 << nb) | lo).wrapping_sub(1)
303}
304
305fn exp_det(x: f64) -> f64 {
309 let ln2 = core::f64::consts::LN_2;
310 let k = (x / ln2).round();
311 let r = x - k * ln2;
312 let (mut t, mut s) = (1.0f64, 1.0f64);
313 for i in 1..25 {
314 t = t * r / i as f64;
315 s += t;
316 }
317 s * f64::from_bits(((k as i64 + 1023) as u64) << 52)
318}
319
320pub fn prior_table() -> &'static [u32; 64] {
322 use std::sync::OnceLock;
323 static T: OnceLock<[u32; 64]> = OnceLock::new();
324 T.get_or_init(|| {
325 let mut t = [0u32; 64];
326 for (k, v) in t.iter_mut().enumerate() {
327 let l = (k as f64 - 31.5) * 0.28;
328 *v = (65536.0 / (1.0 + exp_det(-l))).round().clamp(32.0, 65504.0) as u32;
329 }
330 t
331 })
332}
333
334pub(crate) struct CountSink {
336 pub(crate) n: Vec<[u32; 2]>,
337}
338
339impl Sink for CountSink {
340 #[inline]
341 fn bit(&mut self, _: usize, bit: bool, _: u32) -> bool {
342 bit
343 }
344 #[inline]
345 fn raw(&mut self, _: usize, v: u32, n: u32) -> u32 {
346 v & ((1u32 << n) - 1)
347 }
348 #[inline]
349 fn note(&mut self, idx: usize, bit: bool) {
350 self.n[idx][bit as usize] += 1;
351 }
352}
353
354pub(crate) fn choose_priors(n: &[[u32; 2]], adaptive: bool) -> Vec<Option<u8>> {
356 let th: u32 = std::env::var("TC_PRIOR_MIN")
357 .ok()
358 .and_then(|v| v.parse().ok())
359 .unwrap_or(if adaptive { 16 } else { 4 });
360 let t = prior_table();
361 n.iter()
362 .map(|&[n0, n1]| {
363 if n0 + n1 < th {
364 return None;
365 }
366 let cost = |p: u32| {
367 let p = p as f64 / 65536.0;
368 -(n1 as f64) * p.log2() - (n0 as f64) * (1.0 - p).log2()
369 };
370 (0..64u8).min_by(|&a, &b| cost(t[a as usize]).total_cmp(&cost(t[b as usize])))
371 })
372 .collect()
373}
374
375pub(crate) fn write_priors(w: &mut ByteWriter, pr: &[Option<u8>]) {
376 use crate::abac::{BitModel, Encoder, UintModel};
377 let mut e = Encoder::new();
378 let mut pm = [BitModel::default(); 2];
379 let mut um = UintModel::default();
380 let (mut prev, mut last) = (false, 32i64);
381 for p in pr {
382 e.encode(p.is_some(), &mut pm[prev as usize]);
383 prev = p.is_some();
384 if let Some(k) = p {
385 um.encode(&mut e, crate::bitio::zigzag(*k as i64 - last));
386 last = *k as i64;
387 }
388 }
389 w.block(&e.finish());
390}
391
392pub(crate) fn read_priors(r: &mut ByteReader) -> Result<Vec<u32>, DecodeError> {
393 use crate::abac::{BitModel, Decoder, UintModel};
394 let buf = r.block()?;
395 let mut d = Decoder::new(buf);
396 let mut pm = [BitModel::default(); 2];
397 let mut um = UintModel::default();
398 let (mut prev, mut last) = (false, 32i64);
399 let t = prior_table();
400 let mut init = vec![MINIT; NMODEL];
401 for v in init.iter_mut() {
402 prev = d.decode(&mut pm[prev as usize]);
403 if prev {
404 last += crate::bitio::unzigzag(um.decode(&mut d));
405 let k = last.clamp(0, 63) as usize;
406 *v = t[k] | t[k] << 16;
407 }
408 }
409 if d.overrun() {
410 return Err(DecodeError::Truncated);
411 }
412 Ok(init)
413}
414
415pub(crate) fn init_of(pr: &[Option<u8>]) -> Vec<u32> {
416 let t = prior_table();
417 pr.iter()
418 .map(|p| p.map_or(MINIT, |k| t[k as usize] | t[k as usize] << 16))
419 .collect()
420}
421
422#[derive(Clone, Debug)]
426pub struct BandInfo {
427 pub start: [usize; 3],
429 pub end: [usize; 3],
431 pub class: usize,
433 pub parent: Option<usize>,
435 pub pshift: [u32; 3],
437 pub npass: usize,
439 pub pkey: [usize; 8],
441 pub m: i32,
443 pub sh: u32,
445 pub w: f64,
447 pub org: [usize; 3],
450 pub raster: bool,
453 pub ax: bool,
457 pub nl: usize,
459}
460
461#[derive(Clone, Debug)]
463pub struct Shape {
464 pub dims: [usize; 3],
466 pub p: Pyramid,
468 pub bands: Vec<BandInfo>,
470}
471
472pub(crate) fn max_levels(dims: [usize; 3]) -> usize {
473 if dims.iter().filter(|&&d| d > 1).count() <= 1 {
474 MAX_LEVELS_1D
475 } else {
476 MAX_LEVELS
477 }
478}
479
480pub fn npass_of(start: [usize; 3], end: [usize; 3]) -> usize {
482 let (ez, ey) = (end[0] - start[0], end[1] - start[1]);
483 if ez > 1 && ey > 1 {
484 7
485 } else if ez > 1 || ey > 1 {
486 4
487 } else {
488 1
489 }
490}
491
492#[inline]
494pub fn pass_of(npass: usize, two_axes: bool, zy_is_y: bool, zr: usize, yr: usize) -> usize {
495 let _ = two_axes;
496 match npass {
497 7 => {
498 if (yr | zr) & 1 == 0 {
499 [0, 2, 3, 1][(yr >> 1 & 1) | (zr >> 1 & 1) << 1]
500 } else {
501 [0, 5, 6, 4][(yr & 1) | (zr & 1) << 1]
502 }
503 }
504 4 => {
505 let t = if zy_is_y { yr } else { zr };
506 if t & 1 == 1 {
507 3
508 } else if t & 3 == 2 {
509 2
510 } else if t & 7 == 4 {
511 1
512 } else {
513 0
514 }
515 }
516 _ => 0,
517 }
518}
519
520#[inline]
521fn band_pass(b: &BandInfo, zr: usize, yr: usize) -> usize {
522 let ey = b.end[1] - b.start[1];
523 pass_of(b.npass, false, ey > 1, zr, yr)
524}
525
526fn key_id(level: usize, mask: u8, pass: usize, nlev: usize) -> usize {
528 let l = if mask == 0 { 15 } else { level.min(14) };
529 let _ = nlev;
530 (l * 8 + mask as usize) * 8 + pass
531}
532
533pub const NKEY: usize = 16 * 8 * 8;
535
536impl Shape {
537 pub(crate) fn new(dims: [usize; 3]) -> Self {
538 let p = Pyramid::new(dims, max_levels(dims));
539 let bands = (0..p.bands.len())
540 .map(|bi| {
541 let b = &p.bands[bi];
542 let parent = p.parent_band(bi);
543 let mut pshift = [0; 3];
544 if let Some(pi) = parent {
545 let pl = p.bands[pi].level;
546 for a in 0..3 {
547 pshift[a] = p.split[pl][a] as u32;
548 }
549 }
550 let npass = npass_of(b.start, b.end);
551 let mut pkey = [0; 8];
552 for (ps, k) in pkey.iter_mut().enumerate().take(npass) {
553 *k = key_id(b.level, b.mask, ps, p.nlev());
554 }
555 BandInfo {
556 start: b.start,
557 end: b.end,
558 class: band_class(b) as usize,
559 parent,
560 pshift,
561 npass,
562 pkey,
563 m: 0,
564 sh: 1,
565 w: p.band_weight(b),
566 org: b.start,
567 raster: false,
568 ax: false,
569 nl: 0,
570 }
571 })
572 .collect();
573 Self { dims, p, bands }
574 }
575
576 pub(crate) fn set_steps(&mut self, delta_g: f64) {
577 for b in self.bands.iter_mut() {
578 let (m, sh) = step_repr(delta_g / b.w);
579 b.m = m;
580 b.sh = sh;
581 }
582 }
583
584 pub(crate) fn len(&self) -> usize {
585 self.dims.iter().product()
586 }
587}
588
589pub(crate) fn step_repr(step: f64) -> (i32, u32) {
591 let lg = step.log2().floor() as i32;
592 let sh = (29 - lg).clamp(1, 52);
593 let m = (step * 2f64.powi(sh))
594 .round()
595 .clamp(1.0, (1u64 << 31) as f64 - 1.0) as i32;
596 (m, sh as u32)
597}
598
599const ROWNB: [(i32, i32, u8); 20] = [
603 (0, -1, 0),
604 (0, 1, 0),
605 (-1, 0, 0),
606 (1, 0, 0),
607 (-1, -1, 1),
608 (-1, 1, 1),
609 (1, -1, 1),
610 (1, 1, 1),
611 (0, -2, 2),
612 (0, 2, 2),
613 (-2, 0, 2),
614 (2, 0, 2),
615 (-2, -2, 2),
616 (-2, 2, 2),
617 (2, -2, 2),
618 (2, 2, 2),
619 (0, -4, 2),
620 (0, 4, 2),
621 (-4, 0, 2),
622 (4, 0, 2),
623];
624
625pub const NTAP: usize = 6;
627const TCLAMP: i32 = 1 << 13;
628
629#[derive(Clone, Copy, Default)]
631pub(crate) struct RowCtx {
632 pub(crate) base: [usize; 20],
633 pub(crate) cat: [u8; 20],
634 pub(crate) ax: [u8; 20],
636 pub(crate) n: usize,
637}
638
639pub(crate) fn row_ctx(sh: &Shape, b: &BandInfo, p: usize, z: usize, y: usize) -> RowCtx {
640 let [_, ny, nx] = sh.dims;
641 let mut rc = RowCtx::default();
642 for &(dz, dy, cat) in &ROWNB {
643 let (z2, y2) = (z as i32 + dz, y as i32 + dy);
644 if z2 < b.start[0] as i32
645 || z2 >= b.end[0] as i32
646 || y2 < b.start[1] as i32
647 || y2 >= b.end[1] as i32
648 {
649 continue;
650 }
651 let (z2, y2) = (z2 as usize, y2 as usize);
652 if b.raster {
653 if (z2, y2) >= (z, y) {
654 continue;
655 }
656 } else if band_pass(b, z2 - b.start[0], y2 - b.start[1]) >= p {
657 continue;
658 }
659 rc.base[rc.n] = (z2 * ny + y2) * nx;
660 rc.cat[rc.n] = cat;
661 rc.ax[rc.n] = if dy == 0 {
662 0
663 } else if dz == 0 {
664 1
665 } else {
666 2
667 };
668 rc.n += 1;
669 }
670 rc
671}
672
673#[derive(Clone, Copy, Debug, Default)]
675pub struct Feats {
676 pub taps: [i32; NTAP],
678 pub sig: usize,
680 pub e: usize,
682 pub sctx: usize,
684 pub raw: [i32; 18],
689}
690
691#[inline]
692pub(crate) fn cap(v: i32) -> u32 {
693 v.unsigned_abs().min(65535)
694}
695
696#[inline]
697#[allow(clippy::too_many_arguments)]
698pub(crate) fn feats(
699 sh: &Shape,
700 b: &BandInfo,
701 rc: &RowCtx,
702 q: &[i32],
703 rs: Option<&[i32]>,
704 z: usize,
705 y: usize,
706 x: usize,
707 w: &[i32; NTAP],
708) -> (Feats, i32) {
709 let m = rs.unwrap_or(q);
711 let [_, ny, nx] = sh.dims;
712 let idx = (z * ny + y) * nx + x;
713 let x0 = b.start[2];
714 let wv = if x > x0 { q[idx - 1] } else { 0 };
715 let wwv = if x > x0 + 1 { q[idx - 2] } else { 0 };
716 let wm = if x > x0 { m[idx - 1] } else { 0 };
717 let wwm = if x > x0 + 1 { m[idx - 2] } else { 0 };
718 let (mut sf, mut sd, mut sr) = (0i32, 0i32, 0i32);
719 let (mut af, mut ad, mut ar) = (0u32, 0u32, 0u32);
720 let (mut nf, mut nd, mut nr) = (0u32, 0u32, 0u32);
721 let mut sa = [0i32; 3];
722 for j in 0..rc.n {
723 let v = q[rc.base[j] + x];
724 sa[rc.ax[j] as usize] = sa[rc.ax[j] as usize].wrapping_add(v);
725 let vm = m[rc.base[j] + x];
726 match rc.cat[j] {
727 0 => {
728 sf = sf.wrapping_add(v);
729 af += cap(vm);
730 if b.raster {
731 if x > x0 {
733 ad += cap(m[rc.base[j] + x - 1]);
734 nd += 1;
735 }
736 if x + 1 < b.end[2] {
737 ad += cap(m[rc.base[j] + x + 1]);
738 nd += 1;
739 }
740 }
741 nf += 1;
742 }
743 1 => {
744 sd = sd.wrapping_add(v);
745 ad += cap(vm);
746 nd += 1;
747 }
748 _ => {
749 sr = sr.wrapping_add(v);
750 ar += cap(vm);
751 nr += 1;
752 }
753 }
754 }
755 let (mut pv, mut pm, mut pnb, mut has_p) = (0i32, 0i32, 0u32, false);
756 if let Some(pi) = b.parent {
757 let pb = &sh.bands[pi];
758 let mut pp = [0usize; 3];
759 let pos = [z, y, x];
760 for a in 0..3 {
761 pp[a] = (pb.start[a] + ((pos[a] - b.org[a]) >> b.pshift[a])).min(pb.end[a] - 1);
762 }
763 let at = |p: [usize; 3]| m[(p[0] * ny + p[1]) * nx + p[2]];
764 pv = q[(pp[0] * ny + pp[1]) * nx + pp[2]];
765 pm = at(pp);
766 has_p = true;
767 for a in 0..3 {
768 if pp[a] > pb.start[a] {
769 let mut t = pp;
770 t[a] -= 1;
771 pnb += cap(at(t));
772 }
773 if pp[a] + 1 < pb.end[a] {
774 let mut t = pp;
775 t[a] += 1;
776 pnb += cap(at(t));
777 }
778 }
779 }
780 let cl = |v: i32| v.clamp(-TCLAMP, TCLAMP);
781 if b.ax {
782 (sf, sd, sr) = (sa[0], sa[1], sa[2]);
783 }
784 let taps = [cl(wv), cl(wwv), cl(sf), cl(sd), cl(sr), cl(pv)];
785 let mut acc = 0i32;
786 for i in 0..NTAP {
787 acc = acc.wrapping_add(w[i].wrapping_mul(taps[i]));
788 }
789 let pred = acc.wrapping_add(2048) >> 12;
790 let s = 2 * cap(wm) + cap(wwm) + 2 * af + ad + ar + 2 * cap(pm) + 2 * cap(pred);
791 let ws = 3 + 2 * nf + nd + nr + 2 * has_p as u32 + 2;
792 let a = 12 * s / ws;
793 let ab = bucket(a, &A_TH);
794 let pb = if has_p {
795 1 + bucket(4 * cap(pm).min(15) + pnb.min(60), &P_TH)
796 } else {
797 0
798 };
799 let g = (nf + nd + nr > 0) as usize;
800 let c = b.class;
801 let e = ((1 + 2 * s / ws).ilog2() as usize).min(NE - 1);
802 let sgn = |v: i32| (v.signum() + 1) as usize;
803 let f = Feats {
804 taps,
805 sig: ((c * 2 + g) * NA + ab) * NPB + pb,
806 e,
807 sctx: c * 9 + sgn(wm) * 3 + sgn(sf.wrapping_add(sd)),
808 raw: [
809 wv,
810 wwv,
811 sf,
812 sd,
813 sr,
814 pv,
815 pred,
816 cap(wm) as i32,
817 cap(wwm) as i32,
818 af as i32,
819 ad as i32,
820 ar as i32,
821 cap(pm) as i32,
822 pnb as i32,
823 nf as i32,
824 nd as i32,
825 nr as i32,
826 has_p as i32,
827 ],
828 };
829 (f, pred)
830}
831
832#[inline]
834pub(crate) fn code_res<S: Sink, const A: bool>(
835 s: &mut S,
836 lane: usize,
837 m: &mut [u32],
838 c: usize,
839 f: &Feats,
840 r: i32,
841) -> i32 {
842 let mag = r.unsigned_abs();
843 if !bitm::<S, A>(s, lane, m, SIG0 + f.sig, mag > 0) {
844 return 0;
845 }
846 let e = f.e;
847 let k = e.saturating_sub(2) as u32;
848 let rr = mag.wrapping_sub(1);
849 let hi = rr >> k;
850 let mut h = 0usize;
851 while h < KB {
852 if !bitm::<S, A>(s, lane, m, MAG0 + (c * NE + e) * KB + h, hi > h as u32) {
853 break;
854 }
855 h += 1;
856 }
857 let mut hv = h as u32;
858 if h == KB {
859 hv = hv.wrapping_add(gamma::<S, A>(
860 s,
861 lane,
862 m,
863 ESC0 + c * 32,
864 hi.wrapping_sub(KB as u32),
865 ));
866 }
867 let mut lo = 0u32;
868 let mut j = k;
869 while j > 0 {
870 let pos = k - j;
871 if pos < 2 {
872 let idx = LOW0 + (e * 2 + pos as usize) * 2 + (pos == 1 && lo & 1 == 1) as usize;
873 let bit = bitm::<S, A>(s, lane, m, idx, (rr >> (j - 1)) & 1 == 1);
874 lo = (lo << 1) | bit as u32;
875 j -= 1;
876 } else {
877 let got = raw_n(s, lane, rr & ((1u32 << j) - 1), j);
878 lo = (lo << j) | got;
879 j = 0;
880 }
881 }
882 let mv = ((hv << k) | lo).wrapping_add(1);
883 let neg = bitm::<S, A>(s, lane, m, SGN0 + f.sctx, r < 0);
884 if neg {
885 (mv as i32).wrapping_neg()
886 } else {
887 mv as i32
888 }
889}
890
891pub fn pass_lattice(npass: usize, zy_is_y: bool, p: usize) -> (usize, usize, usize, usize) {
894 match npass {
895 7 => [
896 (0, 4, 0, 4),
897 (2, 4, 2, 4),
898 (0, 4, 2, 4),
899 (2, 4, 0, 4),
900 (1, 2, 1, 2),
901 (0, 2, 1, 2),
902 (1, 2, 0, 2),
903 ][p],
904 4 => {
905 let (r, st) = [(0, 8), (4, 8), (2, 4), (1, 2)][p];
906 if zy_is_y {
907 (0, 1, r, st)
908 } else {
909 (r, st, 0, 1)
910 }
911 }
912 _ => (0, 1, 0, 1),
913 }
914}
915
916pub(crate) fn for_lines(b: &BandInfo, lanes: usize, mut f: impl FnMut(usize, usize, usize, usize)) {
919 if b.raster {
920 for z in b.start[0]..b.end[0] {
921 for y in b.start[1]..b.end[1] {
922 f(0, 0, z, y);
923 }
924 }
925 return;
926 }
927 let lanes = if b.nl > 0 { b.nl.min(lanes) } else { lanes };
928 let (ez, ey) = (b.end[0] - b.start[0], b.end[1] - b.start[1]);
929 for p in 0..b.npass {
930 let (rz, sz, ry, sy) = pass_lattice(b.npass, ey > 1, p);
931 if rz >= ez || ry >= ey {
932 continue;
933 }
934 let cy = (ey - ry).div_ceil(sy);
935 let n = (ez - rz).div_ceil(sz) * cy;
936 for j in 0..n {
937 f(
938 p,
939 j % lanes,
940 b.start[0] + rz + (j / cy) * sz,
941 b.start[1] + ry + (j % cy) * sy,
942 );
943 }
944 }
945}
946
947pub fn code_brick<S: Sink>(
950 sh: &Shape,
951 q: &mut [i32],
952 preds: &[[i32; NTAP]],
953 init: &[u32],
954 lanes: usize,
955 adapt: bool,
956 s: &mut S,
957) {
958 if adapt {
959 code_brick_impl::<S, true>(sh, q, preds, init, lanes, s)
960 } else {
961 code_brick_impl::<S, false>(sh, q, preds, init, lanes, s)
962 }
963}
964
965fn code_brick_impl<S: Sink, const A: bool>(
966 sh: &Shape,
967 q: &mut [i32],
968 preds: &[[i32; NTAP]],
969 init: &[u32],
970 lanes: usize,
971 s: &mut S,
972) {
973 let [_, ny, nx] = sh.dims;
974 let mut models: Vec<u32> = (0..lanes).flat_map(|_| init.iter().copied()).collect();
975 for b in &sh.bands {
976 for_lines(b, lanes, |p, lane, z, y| {
977 let rc = row_ctx(sh, b, p, z, y);
978 let w = &preds[b.pkey[p]];
979 let m = &mut models[lane * NMODEL..(lane + 1) * NMODEL];
980 for x in b.start[2]..b.end[2] {
981 let (f, pred) = feats(sh, b, &rc, q, None, z, y, x, w);
982 let i = (z * ny + y) * nx + x;
983 let r = code_res::<S, A>(s, lane, m, b.class, &f, q[i].wrapping_sub(pred));
984 q[i] = r.wrapping_add(pred);
985 }
986 });
987 }
988}
989
990pub(crate) fn inv97_line(x: &mut [i32], tmp: &mut Vec<i32>, k: &[i32; 6]) {
993 let n = x.len();
994 if n < 2 {
995 return;
996 }
997 let ns = n.div_ceil(2);
998 tmp.clear();
999 tmp.extend_from_slice(x);
1000 let (s, d) = tmp.split_at_mut(ns);
1001 let nd = d.len();
1002 for v in s.iter_mut() {
1003 *v = mulsh(*v, k[0], QL);
1004 }
1005 for v in d.iter_mut() {
1006 *v = mulsh(*v, k[1], QL);
1007 }
1008 let lift_s = |s: &mut [i32], d: &[i32], c: i32| {
1009 for i in 0..ns {
1010 let l = if i == 0 { d[0] } else { d[i - 1] };
1011 let r = if i < nd { d[i] } else { d[nd - 1] };
1012 s[i] = s[i].wrapping_add(mulsh(l.wrapping_add(r), c, QL));
1013 }
1014 };
1015 let lift_d = |s: &[i32], d: &mut [i32], c: i32| {
1016 for i in 0..nd {
1017 let r = if i + 1 < ns { s[i + 1] } else { s[ns - 1] };
1018 d[i] = d[i].wrapping_add(mulsh(s[i].wrapping_add(r), c, QL));
1019 }
1020 };
1021 lift_s(s, d, k[2]);
1022 lift_d(s, d, k[3]);
1023 lift_s(s, d, k[4]);
1024 lift_d(s, d, k[5]);
1025 for i in 0..ns {
1026 x[2 * i] = s[i];
1027 }
1028 for i in 0..nd {
1029 x[2 * i + 1] = d[i];
1030 }
1031}
1032
1033pub fn inverse_int(p: &Pyramid, x: &mut [i32]) {
1035 let k = lift_consts();
1036 let mut line = Vec::new();
1037 let mut tmp = Vec::new();
1038 let st = [p.dims[1] * p.dims[2], p.dims[2], 1];
1039 for l in (0..p.nlev()).rev() {
1040 for a in [2usize, 1, 0] {
1041 if !p.split[l][a] {
1042 continue;
1043 }
1044 let ext = p.lens[l];
1045 let o: Vec<usize> = (0..3).filter(|&b| b != a).collect();
1046 for i in 0..ext[o[0]] {
1047 for j in 0..ext[o[1]] {
1048 let off = i * st[o[0]] + j * st[o[1]];
1049 line.clear();
1050 line.extend((0..ext[a]).map(|t| x[off + t * st[a]]));
1051 inv97_line(&mut line, &mut tmp, &k);
1052 for (t, &v) in line.iter().enumerate() {
1053 x[off + t * st[a]] = v;
1054 }
1055 }
1056 }
1057 }
1058 }
1059}
1060
1061#[inline]
1063pub fn dequant(v: i32, b: &BandInfo, dl: &[u8; NDL]) -> i32 {
1064 if v == 0 {
1065 return 0;
1066 }
1067 let a = v.unsigned_abs().min(i32::MAX as u32) as i32;
1068 let d = dl[b.class * 3 + (v.unsigned_abs().min(3) as usize) - 1] as i32;
1069 let c = mulsh(a, b.m, b.sh).wrapping_sub(mulsh(d, b.m, b.sh + 9));
1070 if v < 0 {
1071 c.wrapping_neg()
1072 } else {
1073 c
1074 }
1075}
1076
1077pub const NDL: usize = NCLASS * 3;
1079
1080pub const VMAX: i32 = (1 << 24) - 1;
1082
1083#[inline]
1085pub fn to_f32_bits(v: i32, scale: f32) -> u32 {
1086 ((v.clamp(-VMAX, VMAX) as f32) * scale).to_bits()
1087}
1088
1089#[derive(Clone, Debug)]
1093pub struct GpuConfig {
1094 pub bound: ErrorBound,
1096 pub brick: usize,
1098 pub lanes: usize,
1100 pub rho: f64,
1102 pub adaptive: bool,
1106}
1107
1108impl GpuConfig {
1109 pub fn new(bound: ErrorBound) -> Self {
1111 Self {
1112 bound,
1113 brick: 64,
1114 lanes: 32,
1115 rho: 0.45,
1116 adaptive: false,
1117 }
1118 }
1119}
1120
1121#[derive(Clone, Debug, Default)]
1123pub struct GpuStats {
1124 pub bytes: usize,
1126 pub bits_per_value: f64,
1128 pub header_bytes: usize,
1130 pub index_bytes: usize,
1132 pub outlier_bytes: usize,
1134 pub n_outliers: usize,
1136 pub n_escapes: usize,
1138 pub rmse: f64,
1140 pub max_abs: f64,
1142 pub delta: f64,
1144}
1145
1146#[derive(Clone, Debug)]
1148pub struct BrickRef {
1149 pub origin: [usize; 3],
1151 pub shape: usize,
1153 pub off: usize,
1155 pub lane_word: Vec<usize>,
1158 pub esc: Vec<(usize, u32)>,
1160}
1161
1162#[derive(Clone, Debug)]
1164pub struct Parsed {
1165 pub dims: Vec<usize>,
1167 pub d3: [usize; 3],
1169 pub bdims: [usize; 3],
1171 pub lanes: usize,
1173 pub adaptive: bool,
1175 pub e: i32,
1177 pub mean_fix: i32,
1179 pub delta_g: f64,
1181 pub dl: [u8; NDL],
1183 pub corr: i32,
1185 pub preds: Vec<[i32; NTAP]>,
1187 pub init: Vec<u32>,
1189 pub shapes: Vec<Shape>,
1191 pub bricks: Vec<BrickRef>,
1193}
1194
1195impl Parsed {
1196 pub fn scale(&self) -> f32 {
1198 f32::from_bits(((self.e + 127) as u32) << 23)
1199 }
1200}
1201
1202fn brick_grid(d3: [usize; 3], bd: [usize; 3]) -> Vec<([usize; 3], [usize; 3])> {
1203 let mut v = Vec::new();
1204 for z in (0..d3[0]).step_by(bd[0]) {
1205 for y in (0..d3[1]).step_by(bd[1]) {
1206 for x in (0..d3[2]).step_by(bd[2]) {
1207 let o = [z, y, x];
1208 v.push((o, [0, 1, 2].map(|a| bd[a].min(d3[a] - o[a]))));
1209 }
1210 }
1211 }
1212 v
1213}
1214
1215fn brick_dims(d3: [usize; 3], b: usize) -> [usize; 3] {
1216 let nd = d3.iter().filter(|&&d| d > 1).count();
1217 match nd {
1218 3 => [b.min(d3[0]), b.min(d3[1]), b.min(d3[2])],
1219 2 => [1, b.min(d3[1]), b.min(d3[2])],
1220 _ => [1, 1, (b * b).min(d3[2])],
1221 }
1222}
1223
1224fn shapes_for(grid: &[([usize; 3], [usize; 3])]) -> (Vec<Shape>, Vec<usize>) {
1226 let mut shapes: Vec<Shape> = Vec::new();
1227 let ids = grid
1228 .iter()
1229 .map(|(_, s)| {
1230 if let Some(i) = shapes.iter().position(|sh| sh.dims == *s) {
1231 i
1232 } else {
1233 shapes.push(Shape::new(*s));
1234 shapes.len() - 1
1235 }
1236 })
1237 .collect();
1238 (shapes, ids)
1239}
1240
1241fn used_keys(shapes: &[Shape]) -> Vec<usize> {
1243 let mut k: Vec<usize> = shapes
1244 .iter()
1245 .flat_map(|s| s.bands.iter().flat_map(|b| b.pkey[..b.npass].to_vec()))
1246 .collect();
1247 k.sort_unstable();
1248 k.dedup();
1249 k
1250}
1251
1252pub fn parse(bytes: &[u8]) -> Result<Parsed, DecodeError> {
1254 let mut r = ByteReader::new(bytes);
1255 if r.take(4)? != MAGIC {
1256 return Err(DecodeError::Invalid("not a tc-gpu stream"));
1257 }
1258 let nd = r.varint()? as usize;
1259 if nd == 0 || nd > 3 {
1260 return Err(DecodeError::Invalid("rank"));
1261 }
1262 let dims: Vec<usize> = (0..nd)
1263 .map(|_| r.varint().map(|v| v as usize))
1264 .collect::<Result<_, _>>()?;
1265 let d3 = crate::wavelet::as3(&dims);
1266 let mut bdims = [0usize; 3];
1267 for v in bdims.iter_mut() {
1268 *v = r.varint()? as usize;
1269 if *v == 0 {
1270 return Err(DecodeError::Invalid("brick"));
1271 }
1272 }
1273 let lanes = r.varint()? as usize;
1274 if lanes == 0 || lanes > 1024 {
1275 return Err(DecodeError::Invalid("lanes"));
1276 }
1277 let adaptive = r.u8()? != 0;
1278 let e = r.svarint()? as i32;
1279 let mean_fix = r.svarint()? as i32;
1280 let delta_g = r.f64()?;
1281 let mut dl = [0u8; NDL];
1282 dl.copy_from_slice(r.take(NDL)?);
1283 let corr = r.varint()? as i32;
1284 let grid = brick_grid(d3, bdims);
1285 let (mut shapes, ids) = shapes_for(&grid);
1286 for s in shapes.iter_mut() {
1287 s.set_steps(delta_g);
1288 }
1289 let mut preds = vec![[0i32; NTAP]; NKEY];
1290 for k in used_keys(&shapes) {
1291 if r.u8()? != 0 {
1292 for t in preds[k].iter_mut() {
1293 *t = r.svarint()? as i32;
1294 }
1295 }
1296 }
1297 let init = read_priors(&mut r)?;
1298 let sizes: Vec<usize> = (0..grid.len())
1299 .map(|_| r.varint().map(|v| v as usize))
1300 .collect::<Result<_, _>>()?;
1301 let mut off = r.position().next_multiple_of(2);
1302 let mut bricks = Vec::with_capacity(grid.len());
1303 for (bi, (o, _)) in grid.iter().enumerate() {
1304 let end = off + sizes[bi];
1305 if end > bytes.len() {
1306 return Err(DecodeError::Truncated);
1307 }
1308 let mut br = ByteReader::new(&bytes[off..end]);
1309 let nw: Vec<usize> = (0..=lanes)
1310 .map(|_| br.varint().map(|v| v as usize))
1311 .collect::<Result<_, _>>()?;
1312 let ne = br.varint()? as usize;
1313 let mut esc = Vec::with_capacity(ne);
1314 let mut last = 0usize;
1315 for i in 0..ne {
1316 let g = br.varint()? as usize;
1317 let idx = if i == 0 { g } else { last + g };
1318 last = idx;
1319 let b = br.take(4)?;
1320 esc.push((idx, u32::from_le_bytes([b[0], b[1], b[2], b[3]])));
1321 }
1322 let mut w = (off + br.position().next_multiple_of(2)) / 2;
1323 let mut lane_word = Vec::with_capacity(lanes + 2);
1324 for &n in &nw {
1325 lane_word.push(w);
1326 w += n;
1327 }
1328 lane_word.push(w);
1329 if w * 2 > end {
1330 return Err(DecodeError::Truncated);
1331 }
1332 bricks.push(BrickRef {
1333 origin: *o,
1334 shape: ids[bi],
1335 off,
1336 lane_word,
1337 esc,
1338 });
1339 off = end;
1340 }
1341 Ok(Parsed {
1342 dims,
1343 d3,
1344 bdims,
1345 lanes,
1346 adaptive,
1347 e,
1348 mean_fix,
1349 delta_g,
1350 dl,
1351 corr,
1352 preds,
1353 init,
1354 shapes,
1355 bricks,
1356 })
1357}
1358
1359fn words(bytes: &[u8], a: usize, b: usize) -> Vec<u16> {
1360 (a..b)
1361 .map(|i| u16::from_le_bytes([bytes[2 * i], bytes[2 * i + 1]]))
1362 .collect()
1363}
1364
1365pub fn decode_brick_fix(ps: &Parsed, bytes: &[u8], bi: usize) -> Result<Vec<i32>, DecodeError> {
1368 let br = &ps.bricks[bi];
1369 let sh = &ps.shapes[br.shape];
1370 let lw: Vec<Vec<u16>> = (0..=ps.lanes)
1371 .map(|l| words(bytes, br.lane_word[l], br.lane_word[l + 1]))
1372 .collect();
1373 let mut sink = DecSink {
1374 lanes: lw.iter().map(|w| RansDec::new(w)).collect(),
1375 };
1376 let mut q = vec![0i32; sh.len()];
1377 code_brick(
1378 sh,
1379 &mut q,
1380 &ps.preds,
1381 &ps.init,
1382 ps.lanes,
1383 ps.adaptive,
1384 &mut sink,
1385 );
1386 let mut c = dequant_brick(sh, &q, &ps.dl);
1387 inverse_int(&sh.p, &mut c);
1388 let ol = ps.lanes;
1390 let mut om = vec![MINIT; NOMODEL];
1391 let n = gamma::<_, true>(&mut sink, ol, &mut om, 0, 0) as usize;
1392 let mut last: i64 = -1;
1393 for _ in 0..n {
1394 let g = gamma::<_, true>(&mut sink, ol, &mut om, 32, 0) as i64;
1395 let idx = (last + 1 + g) as usize;
1396 last = idx as i64;
1397 let neg = sink.raw(ol, 0, 1) == 1;
1398 let k = gamma::<_, true>(&mut sink, ol, &mut om, 64, 0).wrapping_add(1) as i32;
1399 let k = if neg { -k } else { k };
1400 if idx < c.len() {
1401 c[idx] = c[idx].wrapping_add(k.wrapping_mul(ps.corr));
1402 }
1403 }
1404 if sink.lanes.iter().any(|l| l.overrun()) {
1405 return Err(DecodeError::Truncated);
1406 }
1407 Ok(c)
1408}
1409
1410pub(crate) fn dequant_brick(sh: &Shape, q: &[i32], dl: &[u8; NDL]) -> Vec<i32> {
1411 let [_, ny, nx] = sh.dims;
1412 let mut c = vec![0i32; q.len()];
1413 for b in &sh.bands {
1414 for z in b.start[0]..b.end[0] {
1415 for y in b.start[1]..b.end[1] {
1416 for x in b.start[2]..b.end[2] {
1417 let i = (z * ny + y) * nx + x;
1418 c[i] = dequant(q[i], b, dl);
1419 }
1420 }
1421 }
1422 }
1423 c
1424}
1425
1426fn emit_brick(ps: &Parsed, bi: usize, c: &[i32], lo: [usize; 3], hi: [usize; 3], out: &mut [u32]) {
1429 let br = &ps.bricks[bi];
1430 let sh = &ps.shapes[br.shape];
1431 let scale = ps.scale();
1432 let bx = [0, 1, 2].map(|a| hi[a] - lo[a]);
1433 let mut esc = br.esc.iter().peekable();
1434 let [bz, by, bxx] = sh.dims;
1435 for z in 0..bz {
1436 for y in 0..by {
1437 for x in 0..bxx {
1438 let i = (z * by + y) * bxx + x;
1439 let mut bits = to_f32_bits(c[i].wrapping_add(ps.mean_fix), scale);
1440 while let Some(&&(ei, eb)) = esc.peek() {
1441 if ei < i {
1442 esc.next();
1443 } else {
1444 if ei == i {
1445 bits = eb;
1446 }
1447 break;
1448 }
1449 }
1450 let g = [br.origin[0] + z, br.origin[1] + y, br.origin[2] + x];
1451 if (0..3).all(|a| g[a] >= lo[a] && g[a] < hi[a]) {
1452 out[((g[0] - lo[0]) * bx[1] + (g[1] - lo[1])) * bx[2] + (g[2] - lo[2])] = bits;
1453 }
1454 }
1455 }
1456 }
1457}
1458
1459fn intersects(ps: &Parsed, bi: usize, lo: [usize; 3], hi: [usize; 3]) -> bool {
1460 let br = &ps.bricks[bi];
1461 let d = ps.shapes[br.shape].dims;
1462 (0..3).all(|a| br.origin[a] < hi[a] && br.origin[a] + d[a] > lo[a])
1463}
1464
1465pub fn decode_box_bits(
1468 bytes: &[u8],
1469 lo: [usize; 3],
1470 hi: [usize; 3],
1471 threads: usize,
1472) -> Result<Vec<u32>, DecodeError> {
1473 let ps = parse(bytes)?;
1474 decode_box_parsed(&ps, bytes, lo, hi, threads)
1475}
1476
1477pub fn decode_box_parsed(
1479 ps: &Parsed,
1480 bytes: &[u8],
1481 lo: [usize; 3],
1482 hi: [usize; 3],
1483 threads: usize,
1484) -> Result<Vec<u32>, DecodeError> {
1485 for a in 0..3 {
1486 if lo[a] >= hi[a] || hi[a] > ps.d3[a] {
1487 return Err(DecodeError::Invalid("box"));
1488 }
1489 }
1490 let n: usize = (0..3).map(|a| hi[a] - lo[a]).product();
1491 let todo: Vec<usize> = (0..ps.bricks.len())
1492 .filter(|&b| intersects(ps, b, lo, hi))
1493 .collect();
1494 let mut out = vec![0u32; n];
1495 if threads <= 1 || todo.len() <= 1 {
1496 for &bi in &todo {
1497 let c = decode_brick_fix(ps, bytes, bi)?;
1498 emit_brick(ps, bi, &c, lo, hi, &mut out);
1499 }
1500 return Ok(out);
1501 }
1502 use std::sync::atomic::{AtomicUsize, Ordering};
1503 use std::sync::Mutex;
1504 let next = AtomicUsize::new(0);
1505 let err = Mutex::new(None);
1506 let outp = SendPtr(out.as_mut_ptr());
1507 std::thread::scope(|s| {
1508 for _ in 0..threads.min(todo.len()) {
1509 let (next, err, todo) = (&next, &err, &todo);
1510 let outp = &outp;
1511 s.spawn(move || loop {
1512 let t = next.fetch_add(1, Ordering::Relaxed);
1513 if t >= todo.len() {
1514 break;
1515 }
1516 let bi = todo[t];
1517 match decode_brick_fix(ps, bytes, bi) {
1518 Ok(c) => {
1519 let o = unsafe { std::slice::from_raw_parts_mut(outp.0, n) };
1521 emit_brick(ps, bi, &c, lo, hi, o);
1522 }
1523 Err(e) => *err.lock().unwrap() = Some(e),
1524 }
1525 });
1526 }
1527 });
1528 if let Some(e) = err.into_inner().unwrap() {
1529 return Err(e);
1530 }
1531 Ok(out)
1532}
1533
1534struct SendPtr(*mut u32);
1535unsafe impl Sync for SendPtr {}
1536unsafe impl Send for SendPtr {}
1537
1538pub fn decode_f32(bytes: &[u8], threads: usize) -> Result<(Vec<usize>, Vec<f32>), DecodeError> {
1540 let ps = parse(bytes)?;
1541 let bits = decode_box_parsed(&ps, bytes, [0; 3], ps.d3, threads)?;
1542 Ok((
1543 ps.dims.clone(),
1544 bits.into_iter().map(f32::from_bits).collect(),
1545 ))
1546}
1547
1548pub(crate) struct EncBrick {
1551 pub(crate) shape: usize,
1552 pub(crate) origin: [usize; 3],
1553 pub(crate) c: Vec<f64>,
1555}
1556
1557pub(crate) struct Enc<'a> {
1558 pub(crate) x: &'a [f32],
1559 pub(crate) d3: [usize; 3],
1560 pub(crate) bdims: [usize; 3],
1561 pub(crate) shapes: Vec<Shape>,
1562 pub(crate) bricks: Vec<EncBrick>,
1563 pub(crate) e: i32,
1564 pub(crate) mean_fix: i32,
1565 pub(crate) threads: usize,
1566}
1567
1568pub(crate) fn par_map<T: Send + Sync, R: Send>(
1569 items: &[T],
1570 threads: usize,
1571 f: impl Fn(&T) -> R + Sync,
1572) -> Vec<R> {
1573 if threads <= 1 || items.len() <= 1 {
1574 return items.iter().map(f).collect();
1575 }
1576 use std::sync::atomic::{AtomicUsize, Ordering};
1577 use std::sync::Mutex;
1578 let next = AtomicUsize::new(0);
1579 let res: Mutex<Vec<Option<R>>> = Mutex::new((0..items.len()).map(|_| None).collect());
1580 std::thread::scope(|s| {
1581 for _ in 0..threads.min(items.len()) {
1582 s.spawn(|| loop {
1583 let i = next.fetch_add(1, Ordering::Relaxed);
1584 if i >= items.len() {
1585 break;
1586 }
1587 let r = f(&items[i]);
1588 res.lock().unwrap()[i] = Some(r);
1589 });
1590 }
1591 });
1592 res.into_inner()
1593 .unwrap()
1594 .into_iter()
1595 .map(|r| r.unwrap())
1596 .collect()
1597}
1598
1599impl<'a> Enc<'a> {
1600 pub(crate) fn new(x: &'a [f32], dims: &[usize], brick: usize, threads: usize) -> Self {
1601 let d3 = crate::wavelet::as3(dims);
1602 let bdims = brick_dims(d3, brick);
1603 let grid = brick_grid(d3, bdims);
1604 let (shapes, ids) = shapes_for(&grid);
1605 let n = x.len() as f64;
1606 let mean = x.iter().map(|&v| v as f64).sum::<f64>() / n;
1607 let amax = x.iter().fold(0.0f64, |m, &v| m.max((v as f64).abs()));
1608 let dmax = x
1609 .iter()
1610 .fold(0.0f64, |m, &v| m.max((v as f64 - mean).abs()));
1611 let need = |v: f64, lim: f64| {
1612 if v > 0.0 {
1613 (v / lim).log2().ceil() as i32
1614 } else {
1615 -126
1616 }
1617 };
1618 let e = need(amax, (1u32 << 23) as f64)
1619 .max(need(dmax, (1u32 << 20) as f64))
1620 .clamp(-126, 100);
1621 let sc = 2f64.powi(-e);
1622 let mean_fix = (mean * sc).round() as i32;
1623 type Item = (usize, ([usize; 3], [usize; 3]));
1624 let items: Vec<Item> = ids.iter().copied().zip(grid.iter().copied()).collect();
1625 let bricks = par_map(&items, threads, |&(sid, (o, bd))| {
1626 let sh = &shapes[sid];
1627 let mut c = vec![0.0f64; bd.iter().product()];
1628 for z in 0..bd[0] {
1629 for y in 0..bd[1] {
1630 for xx in 0..bd[2] {
1631 let g = ((o[0] + z) * d3[1] + o[1] + y) * d3[2] + o[2] + xx;
1632 c[(z * bd[1] + y) * bd[2] + xx] = x[g] as f64 * sc - mean_fix as f64;
1633 }
1634 }
1635 }
1636 forward_97(&sh.p, &mut c);
1637 EncBrick {
1638 shape: sid,
1639 origin: o,
1640 c,
1641 }
1642 });
1643 Self {
1644 x,
1645 d3,
1646 bdims,
1647 shapes,
1648 bricks,
1649 e,
1650 mean_fix,
1651 threads,
1652 }
1653 }
1654
1655 pub(crate) fn scale(&self) -> f32 {
1656 f32::from_bits(((self.e + 127) as u32) << 23)
1657 }
1658
1659 pub(crate) fn quantize(&self, dg: f64, rho: f64) -> (Vec<Vec<i32>>, [u8; NDL]) {
1661 let parts = par_map(&self.bricks, self.threads, |b| {
1662 let sh = &self.shapes[b.shape];
1663 let [_, ny, nx] = sh.dims;
1664 let mut q = vec![0i32; b.c.len()];
1665 let mut sum = [0.0f64; NDL];
1666 let mut cnt = [0u64; NDL];
1667 for bd in &sh.bands {
1668 let inv = bd.w / dg;
1669 for z in bd.start[0]..bd.end[0] {
1670 for y in bd.start[1]..bd.end[1] {
1671 for x in bd.start[2]..bd.end[2] {
1672 let i = (z * ny + y) * nx + x;
1673 let a = b.c[i].abs() * inv;
1674 let m = (a + rho).floor();
1675 if m >= 1.0 {
1676 let m = m.min(1.0e9);
1677 let j = bd.class * 3 + (m as usize).min(3) - 1;
1678 sum[j] += m - a;
1679 cnt[j] += 1;
1680 q[i] = if b.c[i] < 0.0 { -(m as i32) } else { m as i32 };
1681 }
1682 }
1683 }
1684 }
1685 }
1686 (q, sum, cnt)
1687 });
1688 let mut sum = [0.0f64; NDL];
1689 let mut cnt = [0u64; NDL];
1690 for (_, s, c) in &parts {
1691 for j in 0..NDL {
1692 sum[j] += s[j];
1693 cnt[j] += c[j];
1694 }
1695 }
1696 let mut d = [0u8; NDL];
1697 for j in 0..NDL {
1698 if cnt[j] > 0 {
1699 d[j] = ((sum[j] / cnt[j] as f64).clamp(0.0, 0.498) * 512.0).round() as u8;
1700 }
1701 }
1702 (parts.into_iter().map(|p| p.0).collect(), d)
1703 }
1704
1705 pub(crate) fn reconstruct(
1707 &self,
1708 shapes: &[Shape],
1709 qs: &[Vec<i32>],
1710 dl: &[u8; NDL],
1711 ) -> Vec<Vec<i32>> {
1712 let idx: Vec<usize> = (0..self.bricks.len()).collect();
1713 par_map(&idx, self.threads, |&bi| {
1714 let sh = &shapes[self.bricks[bi].shape];
1715 let mut c = dequant_brick(sh, &qs[bi], dl);
1716 inverse_int(&sh.p, &mut c);
1717 c
1718 })
1719 }
1720
1721 pub(crate) fn global_index(&self, bi: usize, i: usize) -> usize {
1722 let b = &self.bricks[bi];
1723 let d = self.shapes[b.shape].dims;
1724 let (z, y, x) = (i / (d[1] * d[2]), (i / d[2]) % d[1], i % d[2]);
1725 ((b.origin[0] + z) * self.d3[1] + b.origin[1] + y) * self.d3[2] + b.origin[2] + x
1726 }
1727
1728 pub(crate) fn errors(&self, cs: &[Vec<i32>]) -> (f64, f64) {
1730 let scale = self.scale();
1731 let idx: Vec<usize> = (0..cs.len()).collect();
1732 let parts = par_map(&idx, self.threads, |&bi| {
1733 let mut se = 0.0;
1734 let mut mx = 0.0f64;
1735 for (i, &v) in cs[bi].iter().enumerate() {
1736 let y = f32::from_bits(to_f32_bits(v.wrapping_add(self.mean_fix), scale)) as f64;
1737 let e = self.x[self.global_index(bi, i)] as f64 - y;
1738 se += e * e;
1739 mx = mx.max(e.abs());
1740 }
1741 (se, mx)
1742 });
1743 parts
1744 .iter()
1745 .fold((0.0, 0.0), |(a, b), &(s, m)| (a + s, b.max(m)))
1746 }
1747
1748 pub(crate) fn shapes_at(&self, dg: f64) -> Vec<Shape> {
1749 let mut s = self.shapes.clone();
1750 for sh in s.iter_mut() {
1751 sh.set_steps(dg);
1752 }
1753 s
1754 }
1755
1756 pub(crate) fn trial_rmse(&self, dg: f64, rho: f64) -> f64 {
1757 let shapes = self.shapes_at(dg);
1758 let (q, d) = self.quantize(dg, rho);
1759 let cs = self.reconstruct(&shapes, &q, &d);
1760 (self.errors(&cs).0 / self.x.len() as f64).sqrt()
1761 }
1762}
1763
1764fn fit_preds(
1766 shapes: &[Shape],
1767 bricks: &[EncBrick],
1768 qs: &[Vec<i32>],
1769 lanes: usize,
1770) -> Vec<Option<[i32; NTAP]>> {
1771 let mut g = vec![[[0.0f64; NTAP]; NTAP]; NKEY];
1772 let mut h = vec![[0.0f64; NTAP]; NKEY];
1773 let mut n = vec![0usize; NKEY];
1774 let zero = [0i32; NTAP];
1775 let mut obs: Vec<Vec<([i32; NTAP], i32)>> = vec![Vec::new(); NKEY];
1776 for (bi, b) in bricks.iter().enumerate() {
1777 let sh = &shapes[b.shape];
1778 let q = &qs[bi];
1779 let [_, ny, nx] = sh.dims;
1780 for bd in &sh.bands {
1781 for_lines(bd, lanes, |p, _, z, y| {
1782 let rc = row_ctx(sh, bd, p, z, y);
1783 let k = bd.pkey[p];
1784 for x in bd.start[2]..bd.end[2] {
1785 let (f, _) = feats(sh, bd, &rc, q, None, z, y, x, &zero);
1786 let v = q[(z * ny + y) * nx + x];
1787 if v == 0 && f.taps.iter().all(|&t| t == 0) {
1788 continue;
1789 }
1790 n[k] += 1;
1791 for i in 0..NTAP {
1792 h[k][i] += f.taps[i] as f64 * v as f64;
1793 for j in 0..NTAP {
1794 g[k][i][j] += f.taps[i] as f64 * f.taps[j] as f64;
1795 }
1796 }
1797 if obs[k].len() < 200_000 {
1798 obs[k].push((f.taps, v));
1799 }
1800 }
1801 });
1802 }
1803 }
1804 (0..NKEY)
1805 .map(|k| {
1806 if n[k] < 64 {
1807 return None;
1808 }
1809 let mut a = g[k];
1810 let mut r = h[k];
1811 for i in 0..NTAP {
1812 a[i][i] += 1e-3 * (g[k][i][i] + 1.0);
1813 }
1814 for c in 0..NTAP {
1815 let piv = a[c][c];
1816 if piv.abs() < 1e-12 {
1817 continue;
1818 }
1819 for rr in 0..NTAP {
1820 if rr != c {
1821 let f = a[rr][c] / piv;
1822 for kk in 0..NTAP {
1823 a[rr][kk] -= f * a[c][kk];
1824 }
1825 r[rr] -= f * r[c];
1826 }
1827 }
1828 }
1829 let mut w = [0i32; NTAP];
1830 for i in 0..NTAP {
1831 let wi = if a[i][i].abs() > 1e-12 {
1832 r[i] / a[i][i]
1833 } else {
1834 0.0
1835 };
1836 w[i] = (wi * 4096.0).round().clamp(-32767.0, 32767.0) as i32;
1837 }
1838 let (mut c0, mut c1) = (0.0f64, 0.0f64);
1839 for &(t, v) in &obs[k] {
1840 let mut acc = 0i32;
1841 for i in 0..NTAP {
1842 acc = acc.wrapping_add(w[i].wrapping_mul(t[i]));
1843 }
1844 let pr = acc.wrapping_add(2048) >> 12;
1845 c0 += (1.0 + v.unsigned_abs() as f64).log2();
1846 c1 += (1.0 + v.wrapping_sub(pr).unsigned_abs() as f64).log2();
1847 }
1848 if c1 < 0.98 * c0 && c0 - c1 > 64.0 {
1849 Some(w)
1850 } else {
1851 None
1852 }
1853 })
1854 .collect()
1855}
1856
1857pub fn encode_f32(x: &[f32], dims: &[usize], cfg: &GpuConfig) -> (Vec<u8>, GpuStats) {
1859 encode_f32_mt(x, dims, cfg, 1)
1860}
1861
1862pub fn encode_f32_mt(
1865 x: &[f32],
1866 dims: &[usize],
1867 cfg: &GpuConfig,
1868 threads: usize,
1869) -> (Vec<u8>, GpuStats) {
1870 assert!(cfg.lanes >= 1 && cfg.lanes <= 1024 && cfg.brick >= 1);
1871 rate_control(
1872 x,
1873 dims,
1874 cfg.brick,
1875 cfg.bound,
1876 cfg.rho,
1877 threads,
1878 |enc, dg, mx| encode_at(enc, dims, cfg, dg, mx),
1879 )
1880}
1881
1882pub(crate) fn rate_control(
1886 x: &[f32],
1887 dims: &[usize],
1888 brick: usize,
1889 bound: ErrorBound,
1890 rho: f64,
1891 threads: usize,
1892 encode_at: impl Fn(&Enc, f64, Option<f64>) -> (Vec<u8>, GpuStats),
1893) -> (Vec<u8>, GpuStats) {
1894 assert_eq!(dims.iter().product::<usize>(), x.len());
1895 let enc = Enc::new(x, dims, brick, threads);
1896 let (lo, hi) = x
1897 .iter()
1898 .fold((f64::INFINITY, f64::NEG_INFINITY), |(a, b), &v| {
1899 (a.min(v as f64), b.max(v as f64))
1900 });
1901 let range = hi - lo;
1902 let g = 2f64.powi(enc.e);
1903 match bound {
1904 ErrorBound::MaxAbs(b) => {
1905 let mut best: Option<(Vec<u8>, GpuStats)> = None;
1906 for f in [1.0, 1.4, 1.8, 2.2, 2.7, 3.3, 4.0, 5.0] {
1907 let r = encode_at(&enc, (f * b / g).max(1.0), Some(b));
1908 if best.as_ref().is_none_or(|(bb, _)| r.0.len() < bb.len()) {
1909 best = Some(r);
1910 }
1911 }
1912 best.unwrap()
1913 }
1914 ErrorBound::Psnr(_) | ErrorBound::Rmse(_) => {
1915 let t = match bound {
1916 ErrorBound::Rmse(r) => r,
1917 ErrorBound::Psnr(db) => range * 10f64.powf(-db / 20.0),
1918 _ => unreachable!(),
1919 }
1920 .max(f64::MIN_POSITIVE);
1921 let tg = t / g;
1922 let (mut lo, mut hi) = (tg * 0.5, tg * 8.0);
1923 let mut guard = 0;
1924 while enc.trial_rmse(lo.max(1.0), rho) > t && guard < 40 && lo > 1.0 {
1925 hi = lo;
1926 lo *= 0.5;
1927 guard += 1;
1928 }
1929 while enc.trial_rmse(hi, rho) <= t && guard < 80 {
1930 lo = hi;
1931 hi *= 2.0;
1932 guard += 1;
1933 }
1934 lo = lo.max(1.0);
1935 for _ in 0..14 {
1936 let mid = (lo * hi).sqrt();
1937 if enc.trial_rmse(mid, rho) <= t {
1938 lo = mid;
1939 } else {
1940 hi = mid;
1941 }
1942 }
1943 encode_at(&enc, lo, None)
1944 }
1945 }
1946}
1947
1948pub(crate) fn encode_at(
1949 enc: &Enc,
1950 dims: &[usize],
1951 cfg: &GpuConfig,
1952 dg: f64,
1953 maxabs: Option<f64>,
1954) -> (Vec<u8>, GpuStats) {
1955 let shapes = enc.shapes_at(dg);
1956 let (qs, dl) = enc.quantize(dg, cfg.rho);
1957 let fitted = if std::env::var("TC_NOPRED").is_ok() {
1958 vec![None; NKEY]
1959 } else {
1960 fit_preds(&shapes, &enc.bricks, &qs, cfg.lanes)
1961 };
1962 let preds: Vec<[i32; NTAP]> = fitted.iter().map(|p| p.unwrap_or([0; NTAP])).collect();
1963 let mut cs = enc.reconstruct(&shapes, &qs, &dl);
1964 let scale = enc.scale();
1965 let g = 2f64.powi(enc.e);
1966 let corr = maxabs
1968 .map(|b| ((2.0 * b / g).floor() as i64).clamp(0, 1 << 30) as i32)
1969 .unwrap_or(0);
1970 let nb = enc.bricks.len();
1971 let mut outl: Vec<Vec<(usize, i32)>> = vec![Vec::new(); nb];
1972 let mut escs: Vec<Vec<(usize, u32)>> = vec![Vec::new(); nb];
1973 if let Some(b) = maxabs {
1974 for bi in 0..nb {
1975 for i in 0..cs[bi].len() {
1976 let xv = enc.x[enc.global_index(bi, i)];
1977 let y =
1978 f32::from_bits(to_f32_bits(cs[bi][i].wrapping_add(enc.mean_fix), scale)) as f64;
1979 let r = xv as f64 - y;
1980 if r.abs() > b && corr > 0 {
1981 let k = (r / g / corr as f64)
1982 .round()
1983 .clamp(-(1 << 20) as f64, (1 << 20) as f64)
1984 as i32;
1985 if k != 0 {
1986 cs[bi][i] = cs[bi][i].wrapping_add(k.wrapping_mul(corr));
1987 outl[bi].push((i, k));
1988 }
1989 }
1990 let y =
1991 f32::from_bits(to_f32_bits(cs[bi][i].wrapping_add(enc.mean_fix), scale)) as f64;
1992 if (xv as f64 - y).abs() > b {
1993 escs[bi].push((i, xv.to_bits()));
1994 }
1995 }
1996 }
1997 }
1998 let idx: Vec<usize> = (0..nb).collect();
2000 let counts = par_map(&idx, enc.threads, |&bi| {
2001 let sh = &shapes[enc.bricks[bi].shape];
2002 let mut cs = CountSink {
2003 n: vec![[0; 2]; NMODEL],
2004 };
2005 let mut q = qs[bi].clone();
2006 code_brick(
2007 sh,
2008 &mut q,
2009 &preds,
2010 &vec![MINIT; NMODEL],
2011 cfg.lanes,
2012 cfg.adaptive,
2013 &mut cs,
2014 );
2015 cs.n
2016 });
2017 let mut n = vec![[0u32; 2]; NMODEL];
2018 for c in &counts {
2019 for (a, b) in n.iter_mut().zip(c) {
2020 a[0] += b[0];
2021 a[1] += b[1];
2022 }
2023 }
2024 let priors = if std::env::var("TC_NOPRIOR").is_ok() {
2025 vec![None; NMODEL]
2026 } else {
2027 choose_priors(&n, cfg.adaptive)
2028 };
2029 let init = init_of(&priors);
2030 let payloads: Vec<(Vec<u8>, usize, usize)> = par_map(&idx, enc.threads, |&bi| {
2032 let sh = &shapes[enc.bricks[bi].shape];
2033 let mut sink = RecSink {
2034 syms: vec![Vec::new(); cfg.lanes + 1],
2035 };
2036 let mut q = qs[bi].clone();
2037 code_brick(
2038 sh,
2039 &mut q,
2040 &preds,
2041 &init,
2042 cfg.lanes,
2043 cfg.adaptive,
2044 &mut sink,
2045 );
2046 let ol = cfg.lanes;
2047 let mut om = vec![MINIT; NOMODEL];
2048 let ov = &outl[bi];
2049 if maxabs.is_some() {
2050 gamma::<_, true>(&mut sink, ol, &mut om, 0, ov.len() as u32);
2051 let mut last: i64 = -1;
2052 for &(i, k) in ov {
2053 gamma::<_, true>(&mut sink, ol, &mut om, 32, (i as i64 - last - 1) as u32);
2054 last = i as i64;
2055 sink.raw(ol, (k < 0) as u32, 1);
2056 gamma::<_, true>(&mut sink, ol, &mut om, 64, k.unsigned_abs() - 1);
2057 }
2058 }
2059 let lanes: Vec<Vec<u16>> = sink.syms.iter().map(|s| rans_encode(s)).collect();
2060 let mut w = ByteWriter::new();
2061 for l in &lanes {
2062 w.varint(l.len() as u64);
2063 }
2064 let ib = w.buf.len();
2065 w.varint(escs[bi].len() as u64);
2066 let mut last = 0usize;
2067 for (j, &(i, bits)) in escs[bi].iter().enumerate() {
2068 w.varint(if j == 0 { i } else { i - last } as u64);
2069 last = i;
2070 w.bytes(&bits.to_le_bytes());
2071 }
2072 let eb = w.buf.len() - ib;
2073 if w.buf.len() % 2 == 1 {
2074 w.u8(0);
2075 }
2076 let ob = lanes[ol].len() * 2 + eb;
2077 for l in &lanes {
2078 for &v in l {
2079 w.bytes(&v.to_le_bytes());
2080 }
2081 }
2082 (w.buf, ib, ob)
2083 });
2084 let mut w = ByteWriter::new();
2086 w.bytes(MAGIC);
2087 w.varint(dims.len() as u64);
2088 for &d in dims {
2089 w.varint(d as u64);
2090 }
2091 for &d in &enc.bdims {
2092 w.varint(d as u64);
2093 }
2094 w.varint(cfg.lanes as u64);
2095 w.u8(cfg.adaptive as u8);
2096 w.svarint(enc.e as i64);
2097 w.svarint(enc.mean_fix as i64);
2098 w.f64(dg);
2099 w.bytes(&dl);
2100 w.varint(corr as u64);
2101 for k in used_keys(&shapes) {
2102 match fitted[k] {
2103 Some(p) => {
2104 w.u8(1);
2105 for &t in &p {
2106 w.svarint(t as i64);
2107 }
2108 }
2109 None => w.u8(0),
2110 }
2111 }
2112 write_priors(&mut w, &priors);
2113 for (p, _, _) in &payloads {
2114 w.varint(p.len() as u64);
2115 }
2116 if w.buf.len() % 2 == 1 {
2117 w.u8(0);
2118 }
2119 let header_bytes = w.buf.len();
2120 for (p, _, _) in &payloads {
2121 w.bytes(p);
2122 }
2123 let (se, mx) = {
2124 let (se, _) = enc.errors(&cs);
2125 let mut se = se;
2127 let mut mx = 0.0f64;
2128 for bi in 0..nb {
2129 let mut e = escs[bi].iter().peekable();
2130 for i in 0..cs[bi].len() {
2131 let xv = enc.x[enc.global_index(bi, i)] as f64;
2132 let y =
2133 f32::from_bits(to_f32_bits(cs[bi][i].wrapping_add(enc.mean_fix), scale)) as f64;
2134 if e.peek().is_some_and(|&&(ei, _)| ei == i) {
2135 e.next();
2136 se -= (xv - y) * (xv - y);
2137 continue;
2138 }
2139 mx = mx.max((xv - y).abs());
2140 }
2141 }
2142 (se.max(0.0), mx)
2143 };
2144 let n = enc.x.len();
2145 let st = GpuStats {
2146 bytes: w.buf.len(),
2147 bits_per_value: 8.0 * w.buf.len() as f64 / n as f64,
2148 header_bytes,
2149 index_bytes: payloads.iter().map(|p| p.1).sum(),
2150 outlier_bytes: payloads.iter().map(|p| p.2).sum(),
2151 n_outliers: outl.iter().map(|v| v.len()).sum(),
2152 n_escapes: escs.iter().map(|v| v.len()).sum(),
2153 rmse: (se / n as f64).sqrt(),
2154 max_abs: mx,
2155 delta: dg * g,
2156 };
2157 (w.buf, st)
2158}
2159
2160#[cfg(test)]
2161mod tests {
2162 use super::*;
2163
2164 fn field(d: [usize; 3]) -> Vec<f32> {
2165 let mut v = Vec::new();
2166 for i in 0..d[0] {
2167 for j in 0..d[1] {
2168 for k in 0..d[2] {
2169 let (x, y, z) = (i as f64, j as f64, k as f64);
2170 v.push(
2171 ((0.3 * x).sin() + (0.11 * y * z / 8.0).cos() + 0.01 * x * y
2172 - (k % 7) as f64 * 0.01
2173 + 3.0) as f32,
2174 );
2175 }
2176 }
2177 }
2178 v
2179 }
2180
2181 fn err(x: &[f32], y: &[f32]) -> (f64, f64) {
2182 let mut se = 0.0;
2183 let mut mx = 0.0f64;
2184 for (a, b) in x.iter().zip(y) {
2185 let e = *a as f64 - *b as f64;
2186 se += e * e;
2187 mx = mx.max(e.abs());
2188 }
2189 ((se / x.len() as f64).sqrt(), mx)
2190 }
2191
2192 #[test]
2193 fn rans_round_trip() {
2194 let mut s = RecSink {
2195 syms: vec![Vec::new()],
2196 };
2197 let mut st = 12345u32;
2198 let mut vals = Vec::new();
2199 for i in 0..20000 {
2200 st = st.wrapping_mul(1664525).wrapping_add(1013904223);
2201 if i % 3 == 0 {
2202 let n = 1 + (st >> 28) % 16;
2203 vals.push((1, st >> 7, n));
2204 s.raw(0, st >> 7, n);
2205 } else {
2206 let p = 32 + (st >> 16) % 65000;
2207 let b = (st & 0xFF) < 128;
2208 vals.push((0, b as u32, p));
2209 s.bit(0, b, p);
2210 }
2211 }
2212 let w = rans_encode(&s.syms[0]);
2213 let mut d = RansDec::new(&w);
2214 for &(k, v, n) in &vals {
2215 if k == 1 {
2216 assert_eq!(d.raw(n), v & ((1 << n) - 1));
2217 } else {
2218 assert_eq!(d.bit(n) as u32, v);
2219 }
2220 }
2221 assert!(!d.overrun());
2222 }
2223
2224 #[test]
2225 fn psnr_round_trip_and_bricks() {
2226 let d = [20, 37, 45];
2227 let x = field(d);
2228 for brick in [8, 16, 64] {
2229 for db in [50.0, 90.0] {
2230 let cfg = GpuConfig {
2231 brick,
2232 lanes: 4,
2233 ..GpuConfig::new(ErrorBound::Psnr(db))
2234 };
2235 let (bytes, st) = encode_f32(&x, &d, &cfg);
2236 let (dd, y) = decode_f32(&bytes, 1).unwrap();
2237 assert_eq!(dd, d.to_vec());
2238 let (rmse, mx) = err(&x, &y);
2239 assert!((rmse - st.rmse).abs() <= 1e-12 * rmse, "brick {brick} {db}");
2240 assert_eq!(mx, st.max_abs);
2241 let range = x.iter().fold(f32::NEG_INFINITY, |a, &b| a.max(b))
2242 - x.iter().fold(f32::INFINITY, |a, &b| a.min(b));
2243 assert!(20.0 * (range as f64 / rmse).log10() >= db - 1e-6);
2244 let (_, y4) = decode_f32(&bytes, 4).unwrap();
2245 assert_eq!(
2246 y.iter().map(|v| v.to_bits()).collect::<Vec<_>>(),
2247 y4.iter().map(|v| v.to_bits()).collect::<Vec<_>>()
2248 );
2249 assert_eq!(
2250 encode_f32_mt(&x, &d, &cfg, 3).0,
2251 bytes,
2252 "thread-count independent"
2253 );
2254 }
2255 }
2256 }
2257
2258 #[test]
2259 fn maxabs_and_random_access() {
2260 let d = [24, 30, 33];
2261 let x = field(d);
2262 for rel in [1e-2, 1e-4] {
2263 let b = rel * 2.5;
2264 let cfg = GpuConfig {
2265 brick: 16,
2266 lanes: 8,
2267 ..GpuConfig::new(ErrorBound::MaxAbs(b))
2268 };
2269 let (bytes, st) = encode_f32(&x, &d, &cfg);
2270 let (_, y) = decode_f32(&bytes, 2).unwrap();
2271 let (_, mx) = err(&x, &y);
2272 assert!(mx <= b, "{mx} > {b}");
2273 assert_eq!(mx, st.max_abs);
2274 let (lo, hi) = ([3, 5, 7], [21, 29, 20]);
2275 let sub = decode_box_bits(&bytes, lo, hi, 1).unwrap();
2276 let mut k = 0;
2277 for z in lo[0]..hi[0] {
2278 for yy in lo[1]..hi[1] {
2279 for xx in lo[2]..hi[2] {
2280 assert_eq!(sub[k], y[(z * d[1] + yy) * d[2] + xx].to_bits());
2281 k += 1;
2282 }
2283 }
2284 }
2285 }
2286 }
2287
2288 #[test]
2289 fn two_d_and_one_d() {
2290 let x2: Vec<f32> = (0..70 * 90)
2291 .map(|i| ((i % 90) as f32 * 0.07).sin() * ((i / 90) as f32 * 0.05).cos())
2292 .collect();
2293 let (b, st) = encode_f32(
2294 &x2,
2295 &[70, 90],
2296 &GpuConfig {
2297 brick: 32,
2298 lanes: 8,
2299 ..GpuConfig::new(ErrorBound::Psnr(70.0))
2300 },
2301 );
2302 let (_, y) = decode_f32(&b, 1).unwrap();
2303 assert!((err(&x2, &y).0 - st.rmse).abs() <= 1e-12 * st.rmse);
2304 let x1: Vec<f32> = (0..3000).map(|i| (i as f32 * 0.01).sin()).collect();
2305 let (b, st) = encode_f32(
2306 &x1,
2307 &[3000],
2308 &GpuConfig {
2309 brick: 16,
2310 lanes: 2,
2311 ..GpuConfig::new(ErrorBound::Psnr(70.0))
2312 },
2313 );
2314 let (_, y) = decode_f32(&b, 1).unwrap();
2315 assert!((err(&x1, &y).0 - st.rmse).abs() <= 1e-12 * st.rmse);
2316 }
2317
2318 #[test]
2319 fn lattice_matches_pass_of() {
2320 for (ez, ey) in [(1, 1), (1, 9), (9, 1), (5, 7), (16, 16), (3, 13)] {
2321 let b = BandInfo {
2322 start: [2, 3, 0],
2323 end: [2 + ez, 3 + ey, 4],
2324 class: 0,
2325 parent: None,
2326 pshift: [0; 3],
2327 npass: npass_of([2, 3, 0], [2 + ez, 3 + ey, 4]),
2328 pkey: [0; 8],
2329 m: 1,
2330 sh: 1,
2331 w: 1.0,
2332 org: [2, 3, 0],
2333 raster: false,
2334 ax: false,
2335 nl: 0,
2336 };
2337 let mut got = Vec::new();
2338 for_lines(&b, 3, |p, l, z, y| got.push((p, l, z, y)));
2339 let mut want = Vec::new();
2340 for p in 0..b.npass {
2341 let mut j = 0;
2342 for z in b.start[0]..b.end[0] {
2343 for y in b.start[1]..b.end[1] {
2344 if band_pass(&b, z - b.start[0], y - b.start[1]) == p {
2345 want.push((p, j % 3, z, y));
2346 j += 1;
2347 }
2348 }
2349 }
2350 }
2351 assert_eq!(got, want, "{ez}x{ey}");
2352 }
2353 }
2354
2355 #[test]
2356 fn mulsh_matches_wide() {
2357 let mut s = 7u64;
2358 for _ in 0..10000 {
2359 s = s
2360 .wrapping_mul(6364136223846793005)
2361 .wrapping_add(1442695040888963407);
2362 let a = (s >> 33) as i32;
2363 let b = (s as i32) >> 1;
2364 let sh = 1 + (s >> 58) as u32 % 60;
2365 let w = (a as i128 * b as i128 + (1i128 << (sh - 1))) >> sh;
2366 assert_eq!(mulsh(a, b, sh), w as i64 as i32);
2367 }
2368 }
2369}