1use crate::bitio::{unzigzag, zigzag, BitReader, BitWriter, ByteReader, ByteWriter, DecodeError};
27use std::collections::HashMap;
28
29pub const MAGIC: &[u8; 4] = b"TCI1";
31pub const QA_ARM: u32 = 8;
33pub const QA: u32 = 12;
35pub const NFB: usize = 256 >> FB_SHIFT;
37pub const FB_SHIFT: u32 = 3;
39pub const LB_SHIFT: u32 = 3;
41pub const NLB: usize = (2560 >> LB_SHIFT) + 1;
43pub const R: i32 = 31;
45pub const NSYM: usize = (2 * R + 3) as usize;
47pub const PB: u32 = 15;
49const PM: u32 = 1 << PB;
50const RL: u32 = 1 << 16;
51
52pub struct Ccx {
56 pub t: HashMap<String, (Vec<usize>, Vec<f64>)>,
58}
59
60impl Ccx {
61 pub fn parse(b: &[u8]) -> Result<Self, DecodeError> {
63 let mut r = ByteReader::new(b);
64 if r.take(4)? != b"CCX1" {
65 return Err(DecodeError::Invalid("not CCX1"));
66 }
67 let le32 = |r: &mut ByteReader| -> Result<u32, DecodeError> {
68 Ok(u32::from_le_bytes(r.take(4)?.try_into().unwrap()))
69 };
70 let n = le32(&mut r)?;
71 let mut t = HashMap::new();
72 for _ in 0..n {
73 let nl = u16::from_le_bytes(r.take(2)?.try_into().unwrap()) as usize;
74 let name = String::from_utf8_lossy(r.take(nl)?).into_owned();
75 let nd = r.u8()? as usize;
76 let shape: Vec<usize> = (0..nd)
77 .map(|_| le32(&mut r).map(|v| v as usize))
78 .collect::<Result<_, _>>()?;
79 let cnt: usize = shape.iter().product();
80 let data = r
81 .take(cnt * 8)?
82 .as_chunks::<8>()
83 .0
84 .iter()
85 .map(|c| f64::from_le_bytes(*c))
86 .collect();
87 t.insert(name, (shape, data));
88 }
89 Ok(Self { t })
90 }
91 fn get(&self, k: &str) -> &(Vec<usize>, Vec<f64>) {
92 self.t.get(k).unwrap_or_else(|| panic!("ccx: missing {k}"))
93 }
94 fn has(&self, k: &str) -> bool {
95 self.t.contains_key(k)
96 }
97 fn ints(&self, k: &str) -> Vec<i64> {
98 self.get(k).1.iter().map(|&v| v as i64).collect()
99 }
100}
101
102#[derive(Clone, Debug, Default)]
106pub struct QT {
107 pub s: u32,
109 pub k: Vec<i32>,
111}
112
113impl QT {
114 fn from_f64(v: &[f64]) -> Self {
115 let s = (0..=24u32)
116 .find(|&s| v.iter().all(|&x| (x * (1u64 << s) as f64).fract() == 0.0))
117 .unwrap_or(24);
118 Self {
119 s,
120 k: v.iter()
121 .map(|&x| (x * (1u64 << s) as f64).round() as i32)
122 .collect(),
123 }
124 }
125 pub fn fixed(&self, f: u32) -> Vec<i32> {
127 self.k
128 .iter()
129 .map(|&k| {
130 if f >= self.s {
131 k << (f - self.s)
132 } else {
133 let d = self.s - f;
134 let h = 1i32 << (d - 1);
135 if k >= 0 {
136 (k + h) >> d
137 } else {
138 -((-k + h) >> d)
139 }
140 }
141 })
142 .collect()
143 }
144 fn write(&self, w: &mut BitWriter) {
145 eg_put(w, self.s as u64, 0);
146 let zz: Vec<u64> = self.k.iter().map(|&k| zigzag(k as i64)).collect();
148 let cost = |o: u32| zz.iter().map(|&z| eg_len(z, o)).sum::<u64>();
149 let o = (0..12).min_by_key(|&o| cost(o)).unwrap();
150 eg_put(w, o as u64, 0);
151 for &z in &zz {
152 eg_put(w, z, o);
153 }
154 }
155 fn read(r: &mut BitReader, n: usize) -> Result<Self, DecodeError> {
157 let s = eg_get(r, 0)? as u32;
158 if s > 24 {
159 return Err(DecodeError::Invalid("qt exponent"));
160 }
161 let o = eg_get(r, 0)? as u32;
162 let k = (0..n)
163 .map(|_| eg_get(r, o).map(|z| unzigzag(z) as i32))
164 .collect::<Result<_, _>>()?;
165 Ok(Self { s, k })
166 }
167}
168
169const FWMAX: u32 = 16;
171
172fn put_fw(w: &mut BitWriter, fw: u32) {
173 eg_put(w, (FWMAX - fw) as u64, 0);
174}
175
176fn get_fw(r: &mut BitReader) -> Result<u32, DecodeError> {
177 let d = eg_get(r, 0)?;
178 if d > FWMAX as u64 {
179 return Err(DecodeError::Invalid("weight precision"));
180 }
181 Ok(FWMAX - d as u32)
182}
183
184fn eg_len(v: u64, o: u32) -> u64 {
185 let x = (v >> o) + 1;
186 (2 * (63 - x.leading_zeros()) + 1 + o) as u64
187}
188
189fn eg_put(w: &mut BitWriter, v: u64, o: u32) {
191 let x = (v >> o) + 1;
192 let nb = 63 - x.leading_zeros();
193 w.put(0, nb);
194 w.put(1, 1);
195 w.put(x & ((1 << nb) - 1), nb);
196 w.put(v & ((1 << o) - 1), o);
197}
198
199fn eg_get(r: &mut BitReader, o: u32) -> Result<u64, DecodeError> {
200 let mut nb = 0;
201 while r.get(1)? == 0 {
202 nb += 1;
203 if nb > 40 {
204 return Err(DecodeError::Invalid("exp-golomb"));
205 }
206 }
207 let x = (1u64 << nb) | r.get(nb)?;
208 Ok(((x - 1) << o) | r.get(o)?)
209}
210
211#[derive(Clone, Debug)]
213pub struct Lin {
214 pub out: usize,
216 pub inp: usize,
218 pub qw: QT,
220 pub qb: QT,
222 pub fw: u32,
224 pub w: Vec<i32>,
226 pub b: Vec<i32>,
228}
229
230impl Lin {
231 fn new(out: usize, inp: usize, qw: QT, qb: QT) -> Self {
232 assert_eq!(qw.k.len(), out * inp);
233 assert_eq!(qb.k.len(), out);
234 Self {
235 out,
236 inp,
237 qw,
238 qb,
239 fw: 0,
240 w: vec![],
241 b: vec![],
242 }
243 }
244 fn set_fw(&mut self, fw: u32, qa: u32) {
245 self.fw = fw;
246 self.w = self.qw.fixed(fw);
247 self.b = self.qb.fixed(fw + qa);
248 }
249}
250
251#[derive(Default, Debug, Clone, Copy)]
254pub struct Guard {
255 pub max: i64,
257}
258
259impl Guard {
260 #[inline]
261 fn see(&mut self, v: i64) -> i64 {
262 let a = v.abs();
263 if a > self.max {
264 self.max = a;
265 }
266 v
267 }
268 pub fn ok(&self) -> bool {
270 self.max < (1 << 30)
271 }
272}
273
274#[inline]
275fn rshift(acc: i64, f: u32) -> i64 {
276 if f == 0 {
277 acc
278 } else {
279 (acc + (1i64 << (f - 1))) >> f
280 }
281}
282
283#[derive(Clone, Debug)]
287pub struct Mlp {
288 pub layers: Vec<Lin>,
290 pub stab: Option<Lin>,
292 pub residual: bool,
294}
295
296impl Mlp {
297 fn from_ccx(c: &Ccx, p: &str, residual: bool) -> Self {
298 let mut layers = vec![];
299 for i in 0.. {
300 let k = format!("{p}.L{i}.w");
301 if !c.has(&k) {
302 break;
303 }
304 let (sh, w) = c.get(&k);
305 layers.push(Lin::new(
306 sh[0],
307 sh[1],
308 QT::from_f64(w),
309 QT::from_f64(&c.get(&format!("{p}.L{i}.b")).1),
310 ));
311 }
312 let stab = c.has(&format!("{p}.stab.w")).then(|| {
313 let (sh, w) = c.get(&format!("{p}.stab.w"));
314 Lin::new(
315 sh[0],
316 sh[1],
317 QT::from_f64(w),
318 QT::from_f64(&c.get(&format!("{p}.stab.b")).1),
319 )
320 });
321 Self {
322 layers,
323 stab,
324 residual,
325 }
326 }
327 fn set_fw(&mut self, fw: &[u32]) {
328 for (l, &f) in self.layers.iter_mut().zip(fw) {
329 l.set_fw(f, QA_ARM);
330 }
331 if let Some(s) = &mut self.stab {
332 s.set_fw(fw[self.layers.len()], QA_ARM);
333 }
334 }
335 pub fn nin(&self) -> usize {
337 self.layers[0].inp
338 }
339 pub fn nout(&self) -> usize {
341 self.layers.last().unwrap().out
342 }
343 pub fn run(&self, x: &[i32], out: &mut [i32], g: &mut Guard) {
345 let mut a = [0i64; 64];
346 let mut b = [0i64; 64];
347 for i in 0..x.len() {
348 a[i] = x[i] as i64;
349 }
350 let nl = self.layers.len();
351 for (li, l) in self.layers.iter().enumerate() {
352 for o in 0..l.out {
353 let mut acc = l.b[o] as i64;
354 for i in 0..l.inp {
355 acc = g.see(acc + l.w[o * l.inp + i] as i64 * a[i]);
356 }
357 let mut v = g.see(rshift(acc, l.fw));
358 if li + 1 < nl {
359 if self.residual && l.inp == l.out {
360 v = g.see(v + a[o]);
361 }
362 v = v.max(0);
363 }
364 b[o] = v;
365 }
366 std::mem::swap(&mut a, &mut b);
367 }
368 if let Some(s) = &self.stab {
369 for o in 0..s.out {
370 let mut acc = s.b[o] as i64;
371 for i in 0..s.inp {
372 acc = g.see(acc + s.w[o * s.inp + i] as i64 * x[i] as i64);
373 }
374 a[o] = g.see(a[o] + rshift(acc, s.fw));
375 }
376 }
377 for o in 0..out.len() {
378 out[o] = a[o] as i32;
379 }
380 }
381 fn write(&self, w: &mut BitWriter) {
382 eg_put(w, self.layers.len() as u64, 0);
383 eg_put(
384 w,
385 (self.stab.is_some() as u8 | (self.residual as u8) << 1) as u64,
386 0,
387 );
388 eg_put(w, self.nin() as u64, 0);
391 for l in self.layers.iter().chain(self.stab.iter()) {
392 eg_put(w, l.out as u64, 0);
393 put_fw(w, l.fw);
394 l.qw.write(w);
395 l.qb.write(w);
396 }
397 }
398 fn read(r: &mut BitReader) -> Result<Self, DecodeError> {
399 let nl = eg_get(r, 0)? as usize;
400 let fl = eg_get(r, 0)? as u8;
401 let mut ls: Vec<Lin> = vec![];
402 let nin = eg_get(r, 0)? as usize;
403 for li in 0..nl + (fl & 1) as usize {
404 let out = eg_get(r, 0)? as usize;
405 let inp = if li == 0 || li == nl {
406 nin
407 } else {
408 ls[li - 1].out
409 };
410 let fw = get_fw(r)?;
411 if out > 64 || inp > 64 {
412 return Err(DecodeError::Invalid("mlp dims"));
413 }
414 let (qw, qb) = (QT::read(r, out * inp)?, QT::read(r, out)?);
415 let mut l = Lin::new(out, inp, qw, qb);
416 l.set_fw(fw, QA_ARM);
417 ls.push(l);
418 }
419 let stab = if fl & 1 == 1 { ls.pop() } else { None };
420 Ok(Self {
421 layers: ls,
422 stab,
423 residual: fl & 2 != 0,
424 })
425 }
426}
427
428#[derive(Clone, Debug)]
430pub struct Conv {
431 pub lin: Lin,
433 pub k: usize,
435 pub residual: bool,
437 pub relu: bool,
439}
440
441impl Conv {
442 fn from_ccx(c: &Ccx, p: &str) -> Self {
443 let (sh, w) = c.get(&format!("{p}.w"));
444 let meta = &c.get(&format!("{p}.meta")).1;
445 let lin = Lin::new(
446 sh[0],
447 sh[1] * sh[2] * sh[3],
448 QT::from_f64(w),
449 QT::from_f64(&c.get(&format!("{p}.b")).1),
450 );
451 Self {
452 lin,
453 k: sh[2],
454 residual: meta[0] != 0.0,
455 relu: meta[1] != 0.0,
456 }
457 }
458 pub fn cin(&self) -> usize {
460 self.lin.inp / (self.k * self.k)
461 }
462 fn write(&self, w: &mut BitWriter) {
463 eg_put(w, self.lin.out as u64, 0);
464 eg_put(w, self.cin() as u64, 0);
465 eg_put(w, self.k as u64, 0);
466 eg_put(w, (self.residual as u8 | (self.relu as u8) << 1) as u64, 0);
467 put_fw(w, self.lin.fw);
468 self.lin.qw.write(w);
469 self.lin.qb.write(w);
470 }
471 fn read(r: &mut BitReader) -> Result<Self, DecodeError> {
472 let out = eg_get(r, 0)? as usize;
473 let cin = eg_get(r, 0)? as usize;
474 let k = eg_get(r, 0)? as usize;
475 let fl = eg_get(r, 0)? as u8;
476 let fw = get_fw(r)?;
477 if out > 128 || cin > 128 || !(k == 1 || k == 3) {
478 return Err(DecodeError::Invalid("conv dims"));
479 }
480 let (qw, qb) = (QT::read(r, out * cin * k * k)?, QT::read(r, out)?);
481 let mut lin = Lin::new(out, cin * k * k, qw, qb);
482 lin.set_fw(fw, QA);
483 Ok(Self {
484 lin,
485 k,
486 residual: fl & 1 != 0,
487 relu: fl & 2 != 0,
488 })
489 }
490}
491
492#[derive(Clone, Debug)]
494pub struct Filt {
495 pub q: QT,
497 pub fw: u32,
499 pub w: Vec<i32>,
501}
502
503impl Filt {
504 fn new(q: QT, fw: u32) -> Self {
505 let w = q.fixed(fw);
506 Self { q, fw, w }
507 }
508}
509
510#[derive(Clone, Debug)]
514pub struct Model {
515 pub h: usize,
517 pub w: usize,
519 pub sizes: Vec<(usize, usize)>,
521 pub hyper: Vec<bool>,
523 pub ctx: Vec<(i32, i32)>,
525 pub nifce: usize,
527 pub ifce_of: Vec<Option<usize>>,
529 pub arm: Mlp,
531 pub ifces: Vec<Mlp>,
533 pub tconv: Vec<Filt>,
535 pub pconv: Vec<Filt>,
537 pub syn: Vec<Conv>,
539 pub stab: Option<Conv>,
541 pub outt: Conv,
543 pub slope: usize,
545 pub lanes: usize,
547 pub tile_w: usize,
549 pub tile_h: usize,
551}
552
553impl Model {
554 pub fn from_ccx(c: &Ccx, lanes: usize, tile_w: usize, tile_h: usize) -> Self {
557 let isz = c.ints("img_size");
558 let sz = c.ints("sizes");
559 let sizes: Vec<(usize, usize)> = sz
560 .chunks(2)
561 .map(|p| (p[0] as usize, p[1] as usize))
562 .collect();
563 let hyper = c.get("is_hyper").1.iter().map(|&v| v != 0.0).collect();
564 let ms = c.ints("mask_size")[0] as i32;
565 let ctx = c
566 .ints("ctx_index")
567 .iter()
568 .map(|&k| ((k as i32) / ms - ms / 2, (k as i32) % ms - ms / 2))
569 .collect::<Vec<_>>();
570 let nifce = c.ints("n_ifce_out")[0] as usize;
571 let n = sizes.len();
572 let (ifce_of, ifces) = if c.has("ifce.index_to_arm") {
573 let ia = c.ints("ifce.index_to_arm");
574 let nf = c.ints("ifce.input_features");
575 let of = (0..n)
576 .map(|i| (nf[i] > 0 && ia[i] >= 0).then_some(ia[i] as usize))
577 .collect();
578 let na = ia.iter().copied().max().unwrap_or(-1) + 1;
579 (
580 of,
581 (0..na)
582 .map(|j| Mlp::from_ccx(c, &format!("ifce.A{j}"), false))
583 .collect(),
584 )
585 } else {
586 (vec![None; n], vec![])
587 };
588 let filts = |p: &str| {
589 (0..)
590 .map_while(|i| {
591 c.has(&format!("{p}.{i}"))
592 .then(|| Filt::new(QT::from_f64(&c.get(&format!("{p}.{i}")).1), 12))
593 })
594 .collect::<Vec<_>>()
595 };
596 let syn = (0..)
597 .map_while(|i| {
598 c.has(&format!("syn.L{i}.w"))
599 .then(|| Conv::from_ccx(c, &format!("syn.L{i}")))
600 })
601 .collect();
602 let stab = c.has("syn.stab.w").then(|| Conv::from_ccx(c, "syn.stab"));
603 let mut m = Self {
604 h: isz[0] as usize,
605 w: isz[1] as usize,
606 sizes,
607 hyper,
608 slope: 0,
609 ctx,
610 nifce,
611 ifce_of,
612 arm: Mlp::from_ccx(c, "arm", true),
613 ifces,
614 tconv: filts("ups.tconv"),
615 pconv: filts("ups.conv"),
616 syn,
617 stab,
618 outt: Conv::from_ccx(c, "syn.out"),
619 lanes,
620 tile_w,
621 tile_h,
622 };
623 m.slope = slope_of(&m.ctx);
624 m
628 }
629}
630
631pub const CTX_ORDER: [(i32, i32); 40] = {
634 const PRIO: [u8; 40] = [
635 38, 35, 30, 25, 23, 31, 36, 37, 39, 33, 28, 21, 20, 6, 15, 22, 29, 34, 32, 18, 12, 10, 5,
636 9, 14, 19, 27, 24, 13, 8, 2, 1, 3, 11, 17, 26, 16, 7, 4, 0,
637 ];
638 let mut out = [(0i32, 0i32); 40];
639 let mut k = 0;
640 while k < 40 {
641 out[PRIO[k] as usize] = ((k / 9) as i32 - 4, (k % 9) as i32 - 4);
642 k += 1;
643 }
644 out
645};
646
647pub fn slope_of(ctx: &[(i32, i32)]) -> usize {
649 let mut s = 1;
650 for &(dy, dx) in ctx {
651 if dy < 0 {
652 s = s.max((dx.max(0) / -dy + 1) as usize);
653 }
654 }
655 s
656}
657
658pub fn tables() -> &'static Vec<u32> {
663 static T: std::sync::OnceLock<Vec<u32>> = std::sync::OnceLock::new();
664 T.get_or_init(|| {
665 let mut out = Vec::with_capacity(NFB * NLB * (NSYM + 1));
666 for fb in 0..NFB {
667 let fbw = (1 << FB_SHIFT) as f64;
668 let mu = (fb as f64 * fbw - 128.0 + fbw / 2.0) / 256.0;
669 for lb in 0..NLB {
670 let b = ((lb << LB_SHIFT) as f64 / 256.0 - 5.0).exp();
671 let cdf = |x: f64| {
672 let d = x - mu;
673 if d < 0.0 {
674 0.5 * (d / b).exp()
675 } else {
676 1.0 - 0.5 * (-d / b).exp()
677 }
678 };
679 let mut p = vec![0f64; NSYM];
680 p[0] = cdf(-R as f64 - 0.5);
681 for r in -R..=R {
682 p[(r + R + 1) as usize] = cdf(r as f64 + 0.5) - cdf(r as f64 - 0.5);
683 }
684 p[NSYM - 1] = 1.0 - cdf(R as f64 + 0.5);
685 let budget = (PM - NSYM as u32) as f64;
686 let mut f: Vec<u32> = p.iter().map(|&q| 1 + (q * budget).floor() as u32).collect();
687 let tot: u32 = f.iter().sum();
688 let mut best = 0;
689 for i in 1..NSYM {
690 if f[i] > f[best] {
691 best = i;
692 }
693 }
694 f[best] += PM - tot;
695 let mut c = 0;
696 out.push(0);
697 for &x in &f {
698 c += x;
699 out.push(c);
700 }
701 }
702 }
703 out
704 })
705}
706
707#[inline]
709pub fn bucket(mu: i32, ls: i32) -> (i32, usize) {
710 let mu = mu.clamp(-64 * 256, 64 * 256 - 1);
711 let base = (mu + 128) >> 8;
712 let fb = ((mu - (base << 8) + 128) >> FB_SHIFT) as usize;
713 let lb = ((ls + 1280 + (1 << (LB_SHIFT - 1))) >> LB_SHIFT).clamp(0, NLB as i32 - 1) as usize;
714 (base, (fb * NLB + lb) * (NSYM + 1))
715}
716
717struct RansEnc {
720 x: u32,
721 words: Vec<u16>,
722}
723
724impl RansEnc {
725 fn new() -> Self {
726 Self {
727 x: RL,
728 words: vec![],
729 }
730 }
731 fn put(&mut self, start: u32, freq: u32) {
732 let xmax = ((RL >> PB) << 16) * freq;
733 if self.x >= xmax {
734 self.words.push(self.x as u16);
735 self.x >>= 16;
736 }
737 self.x = ((self.x / freq) << PB) + self.x % freq + start;
738 }
739 fn finish(mut self) -> Vec<u16> {
741 self.words.push(self.x as u16);
742 self.words.push((self.x >> 16) as u16);
743 self.words.reverse();
744 self.words
745 }
746}
747
748#[derive(Clone, Copy)]
750pub struct RansDec {
751 pub x: u32,
753 pub pos: usize,
755}
756
757impl RansDec {
758 pub fn new(words: &[u16], pos: usize) -> Self {
760 let x = (words[pos] as u32) << 16 | words[pos + 1] as u32;
761 Self { x, pos: pos + 2 }
762 }
763 #[inline]
764 fn peek(&self) -> u32 {
765 self.x & (PM - 1)
766 }
767 #[inline]
768 fn adv(&mut self, words: &[u16], start: u32, freq: u32) {
769 self.x = freq * (self.x >> PB) + self.peek() - start;
770 if self.x < RL {
771 self.x = self.x << 16 | *words.get(self.pos).unwrap_or(&0) as u32;
772 self.pos += 1;
773 }
774 }
775}
776
777#[inline]
779pub fn dec_sym(d: &mut RansDec, words: &[u16], tab: &[u32], base: i32, off: usize) -> i32 {
780 let cum = &tab[off..off + NSYM + 1];
781 let v = d.peek();
782 let (mut lo, mut hi) = (0usize, NSYM);
783 while hi - lo > 1 {
784 let mid = (lo + hi) / 2;
785 if cum[mid] <= v {
786 lo = mid;
787 } else {
788 hi = mid;
789 }
790 }
791 d.adv(words, cum[lo], cum[lo + 1] - cum[lo]);
792 if lo == 0 || lo == NSYM - 1 {
793 {
794 let mut e = 0u32;
795 for _ in 0..2 {
796 let b = d.peek() >> (PB - 8);
797 d.adv(words, b << (PB - 8), 1 << (PB - 8));
798 e = e << 8 | b;
799 }
800 let e = e as i32;
801 if lo == 0 {
802 base - R - 1 - e
803 } else {
804 base + R + 1 + e
805 }
806 }
807 } else {
808 base + lo as i32 - R - 1
809 }
810}
811
812fn enc_syms(v: i32, base: i32, off: usize, out: &mut Vec<(u32, u32)>) {
814 let tab = tables();
815 let cum = &tab[off..off + NSYM + 1];
816 let r = v - base;
817 let (s, esc) = if r < -R {
818 (0, Some(-R - 1 - r))
819 } else if r > R {
820 (NSYM - 1, Some(r - R - 1))
821 } else {
822 ((r + R + 1) as usize, None)
823 };
824 out.push((cum[s], cum[s + 1] - cum[s]));
825 if let Some(e) = esc {
826 assert!((0..65536).contains(&e), "latent escape out of range");
827 for b in [(e >> 8) as u32, (e & 255) as u32] {
828 out.push((b << (PB - 8), 1 << (PB - 8)));
829 }
830 }
831}
832
833#[derive(Clone, Copy, Debug)]
837pub struct Layout {
838 pub h: usize,
840 pub w: usize,
842 pub th: usize,
844 pub tw: usize,
846 pub ntx: usize,
848 pub nt: usize,
850 pub lanes: usize,
852 pub s: usize,
854 pub steps: usize,
856}
857
858impl Layout {
859 pub fn new(h: usize, w: usize, m: &Model) -> Self {
861 let tw = if m.tile_w == 0 { w } else { m.tile_w.min(w) };
862 let th = if m.tile_h == 0 { h } else { m.tile_h.min(h) };
863 let ntx = w.div_ceil(tw);
864 let nt = ntx * h.div_ceil(th);
865 assert!(nt <= m.lanes, "more tiles than lanes");
866 let lanes = (m.lanes / nt).min(th).max(1);
867 Self {
868 h,
869 w,
870 th,
871 tw,
872 ntx,
873 nt,
874 lanes,
875 s: m.slope,
876 steps: tw + m.slope * (th - 1),
877 }
878 }
879 #[inline]
881 pub fn tile(&self, tile: usize) -> (usize, usize, usize, usize) {
882 let (y0, x0) = ((tile / self.ntx) * self.th, (tile % self.ntx) * self.tw);
883 (y0, x0, self.th.min(self.h - y0), self.tw.min(self.w - x0))
884 }
885 #[inline]
887 pub fn active(&self, l: usize, t: usize, tile: usize, mut f: impl FnMut(usize, usize)) {
888 let (y0, x0, th, tw) = self.tile(tile);
889 let mut y = l;
890 while y < th {
891 let sy = self.s * y;
892 if sy > t {
893 break;
894 }
895 let x = t - sy;
896 if x < tw {
897 f(y0 + y, x0 + x);
898 }
899 y += self.lanes;
900 }
901 }
902}
903
904#[inline]
909#[allow(clippy::too_many_arguments)]
910pub fn arm_input(
911 m: &Model,
912 lay: &Layout,
913 lat: &[i32],
914 ifc: &[i32],
915 y: usize,
916 x: usize,
917 tile: usize,
918 buf: &mut [i32],
919) {
920 let (y0, x0, th, tw) = lay.tile(tile);
921 for (i, &(dy, dx)) in m.ctx.iter().enumerate() {
922 let (yy, xx) = (y as i32 + dy, x as i32 + dx);
923 buf[i] =
924 if yy >= y0 as i32 && yy < (y0 + th) as i32 && xx >= x0 as i32 && xx < (x0 + tw) as i32
925 {
926 lat[yy as usize * lay.w + xx as usize] << QA_ARM
927 } else {
928 0
929 };
930 }
931 let nc = m.ctx.len();
932 for j in 0..m.nifce {
933 buf[nc + j] = if ifc.is_empty() {
934 0
935 } else {
936 ifc[(y * lay.w + x) * m.nifce + j]
937 };
938 }
939}
940
941pub fn ifce_ctx(m: &Model, g: usize, grids: &[Vec<i32>], gd: &mut Guard) -> Vec<i32> {
944 let Some(a) = m.ifce_of[g] else { return vec![] };
945 let mlp = &m.ifces[a];
946 let n = m.sizes.len();
947 let (h1, w1) = m.sizes[g + 1];
950 let mut stack: Vec<Vec<i32>> = vec![];
951 let (mut ch, mut cw) = m.sizes[n - 1];
952 let mut cur: Vec<Vec<i32>> = vec![grids[n - 1].clone()];
953 for k in (g + 1..n - 1).rev() {
954 let (th, tw) = m.sizes[k];
955 if (th, tw) != (ch, cw) {
956 cur = cur
957 .iter()
958 .map(|c| {
959 (0..th * tw)
960 .map(|i| c[(i / tw / 2).min(ch - 1) * cw + (i % tw / 2).min(cw - 1)])
961 .collect()
962 })
963 .collect();
964 (ch, cw) = (th, tw);
965 }
966 let mut nc = vec![grids[k].clone()];
967 nc.extend(cur);
968 cur = nc;
969 }
970 stack.extend(cur);
971 assert_eq!((ch, cw), (h1, w1));
972 assert_eq!(stack.len(), mlp.nin());
973 let (h, w) = m.sizes[g];
974 let mut low = vec![0i32; h1 * w1 * m.nifce];
975 let mut inb = vec![0i32; mlp.nin()];
976 for p in 0..h1 * w1 {
977 for c in 0..stack.len() {
978 inb[c] = stack[c][p] << QA_ARM;
979 }
980 mlp.run(&inb, &mut low[p * m.nifce..(p + 1) * m.nifce], gd);
981 }
982 let mut out = vec![0i32; h * w * m.nifce];
983 for y in 0..h {
984 for x in 0..w {
985 let s = ((y / 2).min(h1 - 1) * w1 + (x / 2).min(w1 - 1)) * m.nifce;
986 out[(y * w + x) * m.nifce..][..m.nifce].copy_from_slice(&low[s..s + m.nifce]);
987 }
988 }
989 out
990}
991
992pub struct Parsed {
996 pub m: Model,
998 pub words: Vec<u16>,
1000 pub starts: Vec<u32>,
1002}
1003
1004fn write_model(m: &Model, w: &mut BitWriter) {
1005 eg_put(w, m.h as u64, 0);
1006 eg_put(w, m.w as u64, 0);
1007 eg_put(w, m.sizes.len() as u64, 0);
1008 for (i, &(h, ww)) in m.sizes.iter().enumerate() {
1009 match (0..31).find(|&d| (h, ww) == (m.h.div_ceil(1 << d), m.w.div_ceil(1 << d))) {
1011 Some(d) => eg_put(w, d as u64, 0),
1012 None => {
1013 eg_put(w, 31, 0);
1014 eg_put(w, h as u64, 0);
1015 eg_put(w, ww as u64, 0);
1016 }
1017 }
1018 eg_put(
1019 w,
1020 (m.hyper[i] as u8 | (m.ifce_of[i].map_or(0, |a| a as u8 + 1) << 1)) as u64,
1021 0,
1022 );
1023 }
1024 let canon = m.ctx.len() <= CTX_ORDER.len() && m.ctx.iter().zip(CTX_ORDER).all(|(a, b)| *a == b);
1026 eg_put(w, (m.ctx.len() << 1 | canon as usize) as u64, 0);
1027 if !canon {
1028 for &(dy, dx) in &m.ctx {
1029 eg_put(w, (((-dy) as u8) << 4 | (dx + 8) as u8) as u64, 0);
1030 }
1031 }
1032 eg_put(w, m.nifce as u64, 0);
1033 eg_put(w, m.lanes as u64, 0);
1034 eg_put(w, m.tile_w as u64, 0);
1035 eg_put(w, m.tile_h as u64, 0);
1036 m.arm.write(w);
1037 eg_put(w, m.ifces.len() as u64, 0);
1038 for f in &m.ifces {
1039 f.write(w);
1040 }
1041 for fs in [&m.tconv, &m.pconv] {
1042 eg_put(w, fs.len() as u64, 0);
1043 for f in fs {
1044 let k = f.q.k.len();
1046 assert!(
1047 (0..k).all(|i| f.q.k[i] == f.q.k[k - 1 - i]),
1048 "upsampling filter not symmetric"
1049 );
1050 eg_put(w, k as u64, 0);
1051 put_fw(w, f.fw);
1052 QT {
1053 s: f.q.s,
1054 k: f.q.k[..k.div_ceil(2)].to_vec(),
1055 }
1056 .write(w);
1057 }
1058 }
1059 eg_put(w, m.syn.len() as u64, 0);
1060 for c in &m.syn {
1061 c.write(w);
1062 }
1063 eg_put(w, (m.stab.is_some() as u8) as u64, 0);
1064 if let Some(s) = &m.stab {
1065 s.write(w);
1066 }
1067 m.outt.write(w);
1068}
1069
1070fn read_model(r: &mut BitReader) -> Result<Model, DecodeError> {
1071 let bad = |s| DecodeError::Invalid(s);
1072 let h = eg_get(r, 0)? as usize;
1073 let w = eg_get(r, 0)? as usize;
1074 let n = eg_get(r, 0)? as usize;
1075 if h == 0 || w == 0 || h * w > 1 << 26 || n == 0 || n > 16 {
1076 return Err(bad("dims"));
1077 }
1078 let (mut sizes, mut hyper, mut ifce_of) = (vec![], vec![], vec![]);
1079 for _ in 0..n {
1080 let d = eg_get(r, 0)?;
1081 let (a, b) = match d {
1082 0..=30 => (h.div_ceil(1 << d), w.div_ceil(1 << d)),
1083 31 => (eg_get(r, 0)? as usize, eg_get(r, 0)? as usize),
1084 _ => return Err(bad("grid size")),
1085 };
1086 if a == 0 || b == 0 || a > h || b > w {
1087 return Err(bad("grid size"));
1088 }
1089 sizes.push((a, b));
1090 let f = eg_get(r, 0)? as u8;
1091 hyper.push(f & 1 != 0);
1092 ifce_of.push((f >> 1 != 0).then(|| (f >> 1) as usize - 1));
1093 }
1094 let nc = eg_get(r, 0)? as usize;
1095 let canon = nc & 1 == 1;
1096 let nc = nc >> 1;
1097 if nc > CTX_ORDER.len() {
1098 return Err(bad("ctx"));
1099 }
1100 let ctx = if canon {
1101 CTX_ORDER[..nc].to_vec()
1102 } else {
1103 (0..nc)
1104 .map(|_| eg_get(r, 0).map(|b| (-((b >> 4) as i32), (b & 15) as i32 - 8)))
1105 .collect::<Result<Vec<_>, _>>()?
1106 };
1107 let nifce = eg_get(r, 0)? as usize;
1108 let lanes = eg_get(r, 0)? as usize;
1109 let tile_w = eg_get(r, 0)? as usize;
1110 let tile_h = eg_get(r, 0)? as usize;
1111 if nifce > 16 || lanes == 0 || lanes > 1024 {
1112 return Err(bad("lanes"));
1113 }
1114 let arm = Mlp::read(r)?;
1115 let ni = eg_get(r, 0)? as usize;
1116 let ifces = (0..ni.min(16))
1117 .map(|_| Mlp::read(r))
1118 .collect::<Result<Vec<_>, _>>()?;
1119 let mut fl = vec![];
1120 for _ in 0..2 {
1121 let k = eg_get(r, 0)? as usize;
1122 let mut v = vec![];
1123 for _ in 0..k.min(32) {
1124 let k = eg_get(r, 0)? as usize;
1125 let fw = get_fw(r)?;
1126 if !(2..=16).contains(&k) {
1127 return Err(bad("filter"));
1128 }
1129 let mut q = QT::read(r, k.div_ceil(2))?;
1130 for i in (0..k / 2).rev() {
1131 let v = q.k[i];
1132 q.k.push(v);
1133 }
1134 v.push(Filt::new(q, fw));
1135 }
1136 fl.push(v);
1137 }
1138 let ns = eg_get(r, 0)? as usize;
1139 let syn = (0..ns.min(16))
1140 .map(|_| Conv::read(r))
1141 .collect::<Result<Vec<_>, _>>()?;
1142 let stab = if (eg_get(r, 0)? as u8) != 0 {
1143 Some(Conv::read(r)?)
1144 } else {
1145 None
1146 };
1147 let outt = Conv::read(r)?;
1148 let pconv = fl.pop().unwrap();
1149 let tconv = fl.pop().unwrap();
1150 let slope = slope_of(&ctx);
1151 let m = Model {
1152 h,
1153 w,
1154 sizes,
1155 hyper,
1156 ctx,
1157 nifce,
1158 ifce_of,
1159 arm,
1160 ifces,
1161 tconv,
1162 pconv,
1163 syn,
1164 stab,
1165 outt,
1166 slope,
1167 lanes,
1168 tile_w,
1169 tile_h,
1170 };
1171 if m.arm.nin() != m.ctx.len() + m.nifce
1172 || m.arm.nout() != 2
1173 || m.ifce_of.iter().flatten().any(|&a| a >= m.ifces.len())
1174 {
1175 return Err(bad("model shape"));
1176 }
1177 Ok(m)
1178}
1179
1180pub fn parse(bytes: &[u8]) -> Result<Parsed, DecodeError> {
1182 let mut r = ByteReader::new(bytes);
1183 if r.take(4)? != MAGIC {
1184 return Err(DecodeError::Invalid("not TCI1"));
1185 }
1186 let mb = r.block()?;
1187 let m = read_model(&mut BitReader::new(mb))?;
1188 let mut starts = vec![];
1189 let mut acc = 0u32;
1190 for _ in 0..m.lanes {
1191 starts.push(acc);
1192 acc = acc
1193 .checked_add(r.varint()? as u32)
1194 .ok_or(DecodeError::Invalid("lanes"))?;
1195 }
1196 let raw = r.take(acc as usize * 2)?;
1197 let words = raw
1198 .as_chunks::<2>()
1199 .0
1200 .iter()
1201 .map(|c| u16::from_le_bytes(*c))
1202 .collect();
1203 for g in 0..m.sizes.len() {
1204 let lay = Layout::new(m.sizes[g].0, m.sizes[g].1, &m);
1205 if lay.nt > m.lanes {
1206 return Err(DecodeError::Invalid("tiles > lanes"));
1207 }
1208 }
1209 Ok(Parsed { m, words, starts })
1210}
1211
1212pub fn decode_latents(p: &Parsed, gd: &mut Guard) -> Vec<Vec<i32>> {
1217 let m = &p.m;
1218 let n = m.sizes.len();
1219 let tab = tables();
1220 let mut grids: Vec<Vec<i32>> = vec![vec![]; n];
1221 let mut inb = vec![0i32; m.arm.nin()];
1222 let mut o = [0i32; 2];
1223 let mut decs: Vec<RansDec> = p
1224 .starts
1225 .iter()
1226 .map(|&s| RansDec::new(&p.words, s as usize))
1227 .collect();
1228 for g in (0..n).rev() {
1229 let (h, w) = m.sizes[g];
1230 let lay = Layout::new(h, w, m);
1231 let ifc = ifce_ctx(m, g, &grids, gd);
1232 let mut lat = vec![0i32; h * w];
1233 for tile in 0..lay.nt {
1234 for t in 0..lay.steps {
1235 for l in 0..lay.lanes {
1236 let d = &mut decs[tile * lay.lanes + l];
1237 lay.active(l, t, tile, |y, x| {
1238 arm_input(m, &lay, &lat, &ifc, y, x, tile, &mut inb);
1239 m.arm.run(&inb, &mut o, gd);
1240 let (base, off) = bucket(o[0], o[1]);
1241 lat[y * w + x] = dec_sym(d, &p.words, tab, base, off);
1242 });
1243 }
1244 }
1245 }
1246 grids[g] = lat;
1247 }
1248 grids
1249}
1250
1251fn tconv_1d(
1254 x: &[i64],
1255 n: usize,
1256 stride: usize,
1257 f: &Filt,
1258 out: &mut [i64],
1259 ostride: usize,
1260 gd: &mut Guard,
1261) {
1262 let k = f.w.len();
1263 let p0 = (k / 2) as i64;
1264 let c = 2 * p0 - 1 + p0;
1265 for m in 0..2 * n {
1266 let mut acc = 0i64;
1267 let jlo = ((m as i64 + c - k as i64 + 1) + 1).div_euclid(2).max(0);
1269 let jhi = (m as i64 + c).div_euclid(2);
1270 for j in jlo..=jhi {
1271 let t = m as i64 + c - 2 * j;
1272 if t < 0 || t >= k as i64 {
1273 continue;
1274 }
1275 let src = (j - p0).clamp(0, n as i64 - 1) as usize;
1276 acc = gd.see(acc + f.w[t as usize] as i64 * x[src * stride]);
1277 }
1278 out[m * ostride] = gd.see(rshift(acc, f.fw));
1279 }
1280}
1281
1282fn tconv2d(x: &[i64], h: usize, w: usize, f: &Filt, gd: &mut Guard) -> Vec<i64> {
1284 let mut t = vec![0i64; h * 2 * w];
1285 for y in 0..h {
1286 tconv_1d(&x[y * w..], w, 1, f, &mut t[y * 2 * w..], 1, gd);
1287 }
1288 let mut o = vec![0i64; 4 * h * w];
1289 for xx in 0..2 * w {
1290 tconv_1d(&t[xx..], h, 2 * w, f, &mut o[xx..], 2 * w, gd);
1291 }
1292 o
1293}
1294
1295fn pconv2d(x: &[i64], h: usize, w: usize, f: &Filt, gd: &mut Guard) -> Vec<i64> {
1297 let k = f.w.len();
1298 let p = (k / 2) as i64;
1299 let mut t = vec![0i64; h * w];
1300 for y in 0..h {
1301 for xx in 0..w {
1302 let mut acc = 0i64;
1303 for i in 0..k {
1304 let sx = xx as i64 + i as i64 - p;
1305 if sx >= 0 && sx < w as i64 {
1306 acc = gd.see(acc + f.w[i] as i64 * x[y * w + sx as usize]);
1307 }
1308 }
1309 t[y * w + xx] = gd.see(rshift(acc, f.fw));
1310 }
1311 }
1312 let mut o = vec![0i64; h * w];
1313 for y in 0..h {
1314 for xx in 0..w {
1315 let mut acc = 0i64;
1316 for i in 0..k {
1317 let sy = y as i64 + i as i64 - p;
1318 if sy >= 0 && sy < h as i64 {
1319 acc = gd.see(acc + f.w[i] as i64 * t[sy as usize * w + xx]);
1320 }
1321 }
1322 o[y * w + xx] = gd.see(rshift(acc, f.fw) + x[y * w + xx]);
1323 }
1324 }
1325 o
1326}
1327
1328pub fn upsample(m: &Model, grids: &[Vec<i32>], gd: &mut Guard) -> Vec<Vec<i64>> {
1330 let idx: Vec<usize> = (0..m.sizes.len()).filter(|&i| !m.hyper[i]).collect();
1331 let mut it = idx.iter().rev();
1332 let &g0 = it.next().unwrap();
1333 let (mut ch, mut cw) = m.sizes[g0];
1334 let mut up: Vec<Vec<i64>> = vec![grids[g0].iter().map(|&v| (v as i64) << QA).collect()];
1335 for (k, &g) in it.enumerate() {
1336 let (th, tw) = m.sizes[g];
1337 let f = &m.tconv[k % m.tconv.len()];
1338 let ups: Vec<Vec<i64>> = up
1339 .iter()
1340 .map(|c| {
1341 let full = tconv2d(c, ch, cw, f, gd);
1342 (0..th * tw)
1343 .map(|i| full[(i / tw) * 2 * cw + i % tw])
1344 .collect()
1345 })
1346 .collect();
1347 let tgt: Vec<i64> = grids[g].iter().map(|&v| (v as i64) << QA).collect();
1348 let hi = pconv2d(&tgt, th, tw, &m.pconv[k % m.pconv.len()], gd);
1349 up = std::iter::once(hi).chain(ups).collect();
1350 (ch, cw) = (th, tw);
1351 }
1352 assert_eq!((ch, cw), (m.h, m.w));
1353 up
1354}
1355
1356#[allow(clippy::too_many_arguments)]
1357fn conv_px(
1358 c: &Conv,
1359 inp: &[Vec<i64>],
1360 h: usize,
1361 w: usize,
1362 y: usize,
1363 x: usize,
1364 o: usize,
1365 gd: &mut Guard,
1366) -> i64 {
1367 let l = &c.lin;
1368 let cin = c.cin();
1369 let k = c.k;
1370 let p = (k / 2) as i64;
1371 let mut acc = l.b[o] as i64;
1372 for ci in 0..cin {
1373 for dy in 0..k {
1374 let sy = (y as i64 + dy as i64 - p).clamp(0, h as i64 - 1) as usize;
1375 for dx in 0..k {
1376 let sx = (x as i64 + dx as i64 - p).clamp(0, w as i64 - 1) as usize;
1377 acc = gd.see(
1378 acc + l.w[((o * cin + ci) * k + dy) * k + dx] as i64 * inp[ci][sy * w + sx],
1379 );
1380 }
1381 }
1382 }
1383 let mut v = gd.see(rshift(acc, l.fw));
1384 if c.residual {
1385 v = gd.see(v + inp[o][y * w + x]);
1386 }
1387 if c.relu {
1388 v = v.max(0);
1389 }
1390 v
1391}
1392
1393fn conv_all(c: &Conv, inp: &[Vec<i64>], h: usize, w: usize, gd: &mut Guard) -> Vec<Vec<i64>> {
1394 (0..c.lin.out)
1395 .map(|o| {
1396 (0..h * w)
1397 .map(|i| conv_px(c, inp, h, w, i / w, i % w, o, gd))
1398 .collect()
1399 })
1400 .collect()
1401}
1402
1403pub fn synthesize(m: &Model, dense: &[Vec<i64>], gd: &mut Guard) -> Vec<u8> {
1405 let (h, w) = (m.h, m.w);
1406 let mut x = dense.to_vec();
1407 for c in &m.syn {
1408 x = conv_all(c, &x, h, w, gd);
1409 }
1410 if let Some(s) = &m.stab {
1411 let sb = conv_all(s, &dense[..s.cin()], h, w, gd);
1412 for (a, b) in x.iter_mut().zip(sb) {
1413 for (p, q) in a.iter_mut().zip(b) {
1414 *p = gd.see(*p + q);
1415 }
1416 }
1417 }
1418 let y = conv_all(&m.outt, &x, h, w, gd);
1419 let mut out = vec![0u8; h * w * 3];
1420 for i in 0..h * w {
1421 for c in 0..3 {
1422 out[i * 3 + c] = rshift(gd.see(y[c][i] * 255), QA).clamp(0, 255) as u8;
1423 }
1424 }
1425 out
1426}
1427
1428pub fn decode(bytes: &[u8]) -> Result<(usize, usize, Vec<u8>), DecodeError> {
1431 let p = parse(bytes)?;
1432 let mut gd = Guard::default();
1433 let grids = decode_latents(&p, &mut gd);
1434 let dense = upsample(&p.m, &grids, &mut gd);
1435 let rgb = synthesize(&p.m, &dense, &mut gd);
1436 if !gd.ok() {
1437 return Err(DecodeError::Invalid("i32 overflow"));
1438 }
1439 Ok((p.m.h, p.m.w, rgb))
1440}
1441
1442#[derive(Debug, Clone, Default)]
1446pub struct Stats {
1447 pub bytes: usize,
1449 pub model_bytes: usize,
1451 pub latent_bytes: usize,
1453 pub grid_bits: Vec<f64>,
1455 pub ideal_bits: f64,
1457}
1458
1459pub fn encode(c: &Ccx, lanes: usize, tile_w: usize, tile_h: usize) -> (Vec<u8>, Stats) {
1461 let mut m = Model::from_ccx(c, lanes, tile_w, tile_h);
1462 let n = m.sizes.len();
1463 let grids: Vec<Vec<i32>> = (0..n)
1464 .map(|g| {
1465 c.ints(&format!("latent.{g}"))
1466 .iter()
1467 .map(|&v| v as i32)
1468 .collect()
1469 })
1470 .collect();
1471 for g in 0..n {
1472 assert_eq!(grids[g].len(), m.sizes[g].0 * m.sizes[g].1);
1473 }
1474 let fit_all = |m: &mut Model, cap: u32| {
1477 let ws = vec![cap; m.arm.layers.len() + 1];
1478 m.arm.set_fw(&ws);
1479 for f in &mut m.ifces {
1480 let ws = vec![cap; f.layers.len() + 1];
1481 f.set_fw(&ws);
1482 }
1483 for f in m.tconv.iter_mut().chain(m.pconv.iter_mut()) {
1484 *f = Filt::new(f.q.clone(), cap.min(14));
1485 }
1486 for cv in m
1487 .syn
1488 .iter_mut()
1489 .chain(m.stab.iter_mut())
1490 .chain(std::iter::once(&mut m.outt))
1491 {
1492 cv.lin.set_fw(cap.min(14), QA);
1493 }
1494 };
1495 let mut cap = 16;
1496 loop {
1497 fit_all(&mut m, cap);
1498 let mut gd = Guard::default();
1499 let mut ok = true;
1501 let mut inb = vec![0i32; m.arm.nin()];
1502 let mut o = [0i32; 2];
1503 for g in (0..n).rev() {
1504 let (h, w) = m.sizes[g];
1505 let lay = Layout::new(h, w, &m);
1506 let ifc = ifce_ctx(&m, g, &grids, &mut gd);
1507 for tile in 0..lay.nt {
1508 let (y0, x0, th, tw) = lay.tile(tile);
1509 for y in y0..y0 + th {
1510 for x in x0..x0 + tw {
1511 arm_input(&m, &lay, &grids[g], &ifc, y, x, tile, &mut inb);
1512 m.arm.run(&inb, &mut o, &mut gd);
1513 }
1514 }
1515 }
1516 }
1517 if gd.ok() {
1518 let dense = upsample(&m, &grids, &mut gd);
1519 let _ = synthesize(&m, &dense, &mut gd);
1520 }
1521 ok &= gd.ok();
1522 if ok || cap <= 6 {
1523 break;
1524 }
1525 cap -= 1;
1526 }
1527 let mut w = ByteWriter::new();
1529 w.bytes(MAGIC);
1530 let mut bw = BitWriter::new();
1531 write_model(&m, &mut bw);
1532 w.block(&bw.finish());
1533 let model_bytes = w.buf.len();
1534 let mut st = Stats {
1535 model_bytes,
1536 grid_bits: vec![0.0; n],
1537 ..Default::default()
1538 };
1539 let mut gd = Guard::default();
1540 let mut inb = vec![0i32; m.arm.nin()];
1541 let mut o = [0i32; 2];
1542 let mut syms: Vec<Vec<(u32, u32)>> = vec![vec![]; m.lanes];
1543 for g in (0..n).rev() {
1544 let (h, ww) = m.sizes[g];
1545 let lay = Layout::new(h, ww, &m);
1546 let ifc = ifce_ctx(&m, g, &grids, &mut gd);
1547 let lat = &grids[g];
1548 for tile in 0..lay.nt {
1549 for t in 0..lay.steps {
1550 for l in 0..lay.lanes {
1551 let sl = &mut syms[tile * lay.lanes + l];
1552 lay.active(l, t, tile, |y, x| {
1553 arm_input(&m, &lay, lat, &ifc, y, x, tile, &mut inb);
1554 m.arm.run(&inb, &mut o, &mut gd);
1555 let (base, off) = bucket(o[0], o[1]);
1556 let v = lat[y * ww + x];
1557 let k0 = sl.len();
1558 enc_syms(v, base, off, sl);
1559 for &(_, f) in &sl[k0..] {
1560 st.grid_bits[g] += PB as f64 - (f as f64).log2();
1561 }
1562 });
1563 }
1564 }
1565 }
1566 }
1567 st.ideal_bits = st.grid_bits.iter().sum();
1568 let lanes: Vec<Vec<u16>> = syms
1569 .iter()
1570 .map(|s| {
1571 let mut e = RansEnc::new();
1572 for &(a, f) in s.iter().rev() {
1573 e.put(a, f);
1574 }
1575 e.finish()
1576 })
1577 .collect();
1578 for l in &lanes {
1579 w.varint(l.len() as u64);
1580 }
1581 for l in &lanes {
1582 for v in l {
1583 w.bytes(&v.to_le_bytes());
1584 }
1585 }
1586 st.bytes = w.buf.len();
1587 st.latent_bytes = st.bytes - model_bytes;
1588 (w.buf, st)
1589}
1590
1591pub fn psnr(a: &[u8], b: &[u8]) -> f64 {
1593 let mse: f64 = a
1594 .iter()
1595 .zip(b)
1596 .map(|(&x, &y)| (x as f64 - y as f64).powi(2))
1597 .sum::<f64>()
1598 / a.len() as f64;
1599 10.0 * (255.0f64 * 255.0 / mse).log10()
1600}
1601
1602use tang_expr::int::{IId, IType, IntGraph};
1605
1606fn g_layer(g: &mut IntGraph, l: &Lin, inp: &[IId], residual: bool, relu: bool) -> Vec<IId> {
1607 let zero = g.i32(0);
1608 (0..l.out)
1609 .map(|o| {
1610 let mut acc = g.i32(l.b[o]);
1611 for i in 0..l.inp {
1612 let w = l.w[o * l.inp + i];
1613 if w != 0 {
1614 let wc = g.i32(w);
1615 let t = g.mul(wc, inp[i]);
1616 acc = g.add(acc, t);
1617 }
1618 }
1619 let mut v = g_rshift(g, acc, l.fw);
1620 if residual {
1621 v = g.add(v, inp[o]);
1622 }
1623 if relu {
1624 v = g.max(v, zero);
1625 }
1626 v
1627 })
1628 .collect()
1629}
1630
1631fn g_rshift(g: &mut IntGraph, v: IId, f: u32) -> IId {
1632 if f == 0 {
1633 return v;
1634 }
1635 let h = g.i32(1 << (f - 1));
1636 let s = g.u32(f);
1637 let t = g.add(v, h);
1638 g.shr(t, s)
1639}
1640
1641impl Mlp {
1642 pub fn graph(&self) -> (IntGraph, Vec<IId>) {
1644 let mut g = IntGraph::new();
1645 let x: Vec<IId> = (0..self.nin())
1646 .map(|i| g.param(i as u16, IType::I32))
1647 .collect();
1648 let mut a = x.clone();
1649 let nl = self.layers.len();
1650 for (li, l) in self.layers.iter().enumerate() {
1651 let hidden = li + 1 < nl;
1652 a = g_layer(
1653 &mut g,
1654 l,
1655 &a,
1656 hidden && self.residual && l.inp == l.out,
1657 hidden,
1658 );
1659 }
1660 if let Some(s) = &self.stab {
1661 let sb = g_layer(&mut g, s, &x, false, false);
1662 a = a.iter().zip(sb).map(|(&p, q)| g.add(p, q)).collect();
1663 }
1664 (g, a)
1665 }
1666}
1667
1668pub fn segment_graph(m: &Model, convs: &[&Conv], last: bool) -> (IntGraph, Vec<IId>) {
1674 let mut g = IntGraph::new();
1675 let c0 = convs[0];
1676 let nt = c0.lin.inp;
1677 let mut np = 0u16;
1678 let mut par = |g: &mut IntGraph| {
1679 let p = g.param(np, IType::I32);
1680 np += 1;
1681 p
1682 };
1683 let taps: Vec<IId> = (0..nt).map(|_| par(&mut g)).collect();
1684 let centre: Vec<IId> = if c0.residual {
1685 (0..c0.cin()).map(|_| par(&mut g)).collect()
1686 } else {
1687 vec![]
1688 };
1689 let mut a = {
1690 let zero = g.i32(0);
1691 let l = &c0.lin;
1692 (0..l.out)
1693 .map(|o| {
1694 let mut acc = g.i32(l.b[o]);
1695 for i in 0..l.inp {
1696 let w = l.w[o * l.inp + i];
1697 if w != 0 {
1698 let wc = g.i32(w);
1699 let t = g.mul(wc, taps[i]);
1700 acc = g.add(acc, t);
1701 }
1702 }
1703 let mut v = g_rshift(&mut g, acc, l.fw);
1704 if c0.residual {
1705 v = g.add(v, centre[o]);
1706 }
1707 if c0.relu {
1708 v = g.max(v, zero);
1709 }
1710 v
1711 })
1712 .collect::<Vec<_>>()
1713 };
1714 for c in &convs[1..] {
1715 assert_eq!(c.k, 1);
1716 a = g_layer(&mut g, &c.lin, &a, c.residual, c.relu);
1717 }
1718 if last {
1719 if let Some(s) = &m.stab {
1720 let si: Vec<IId> = (0..s.cin()).map(|_| par(&mut g)).collect();
1721 let sb = g_layer(&mut g, &s.lin, &si, false, false);
1722 a = a.iter().zip(sb).map(|(&p, q)| g.add(p, q)).collect();
1723 }
1724 a = g_layer(&mut g, &m.outt.lin, &a, m.outt.residual, m.outt.relu);
1725 let (k255, lo, hi) = (g.i32(255), g.i32(0), g.i32(255));
1726 a = a
1727 .iter()
1728 .map(|&v| {
1729 let t = g.mul(v, k255);
1730 let t = g_rshift(&mut g, t, QA);
1731 g.clamp(t, lo, hi)
1732 })
1733 .collect();
1734 }
1735 (g, a)
1736}
1737
1738pub fn segments(m: &Model) -> Vec<Vec<&Conv>> {
1740 let mut segs: Vec<Vec<&Conv>> = vec![];
1741 for c in &m.syn {
1742 if c.k != 1 || segs.is_empty() {
1743 segs.push(vec![c]);
1744 } else {
1745 segs.last_mut().unwrap().push(c);
1746 }
1747 }
1748 segs
1749}
1750
1751#[cfg(test)]
1752pub(crate) mod tests {
1753 use super::*;
1754 use tang_expr::int::Program;
1755
1756 struct Rng(u64);
1757 impl Rng {
1758 fn next(&mut self) -> u64 {
1759 self.0 ^= self.0 << 13;
1760 self.0 ^= self.0 >> 7;
1761 self.0 ^= self.0 << 17;
1762 self.0
1763 }
1764 fn q(&mut self, a: i64) -> f64 {
1766 ((self.next() % (2 * a as u64 + 1)) as i64 - a) as f64 / 64.0
1767 }
1768 }
1769
1770 fn put(t: &mut HashMap<String, (Vec<usize>, Vec<f64>)>, k: &str, sh: &[usize], v: Vec<f64>) {
1771 assert_eq!(sh.iter().product::<usize>(), v.len());
1772 t.insert(k.into(), (sh.to_vec(), v));
1773 }
1774
1775 pub(crate) fn synth(seed: u64) -> Ccx {
1777 let mut r = Rng(seed);
1778 let mut t = HashMap::new();
1779 let sizes = [(16usize, 24usize), (8, 12), (4, 6), (4, 6)];
1780 put(&mut t, "img_size", &[2], vec![16.0, 24.0]);
1781 put(
1782 &mut t,
1783 "sizes",
1784 &[4, 2],
1785 sizes
1786 .iter()
1787 .flat_map(|&(a, b)| [a as f64, b as f64])
1788 .collect(),
1789 );
1790 put(&mut t, "is_hyper", &[4], vec![0.0, 0.0, 0.0, 1.0]);
1791 let ctx = [
1792 (0, -1),
1793 (-1, 0),
1794 (-1, -1),
1795 (-1, 1),
1796 (0, -2),
1797 (-2, 0),
1798 (-1, 2),
1799 ];
1800 put(
1801 &mut t,
1802 "ctx_index",
1803 &[ctx.len()],
1804 ctx.iter()
1805 .map(|&(dy, dx): &(i32, i32)| ((dy + 4) * 9 + dx + 4) as f64)
1806 .collect(),
1807 );
1808 put(&mut t, "mask_size", &[1], vec![9.0]);
1809 put(&mut t, "n_ifce_out", &[1], vec![2.0]);
1810 put(
1811 &mut t,
1812 "ifce.input_features",
1813 &[4],
1814 vec![3.0, 0.0, 0.0, 0.0],
1815 );
1816 put(
1817 &mut t,
1818 "ifce.index_to_arm",
1819 &[4],
1820 vec![0.0, -1.0, -1.0, -1.0],
1821 );
1822 let lin = |t: &mut HashMap<_, _>, r: &mut Rng, p: &str, o: usize, i: usize, a: i64| {
1823 put(
1824 t,
1825 &format!("{p}.w"),
1826 &[o, i],
1827 (0..o * i).map(|_| r.q(a)).collect(),
1828 );
1829 put(t, &format!("{p}.b"), &[o], (0..o).map(|_| r.q(a)).collect());
1830 };
1831 lin(&mut t, &mut r, "ifce.A0.L0", 2, 3, 40);
1832 let nin = ctx.len() + 2;
1833 lin(&mut t, &mut r, "arm.L0", nin, nin, 20);
1834 lin(&mut t, &mut r, "arm.L1", nin, nin, 20);
1835 lin(&mut t, &mut r, "arm.L2", 2, nin, 30);
1836 lin(&mut t, &mut r, "arm.stab", 2, nin, 10);
1837 for i in 0..2 {
1838 let a = [0.0351562, 0.1054687, -0.2617187, -0.8789063]
1839 .map(|v: f64| -((v * 64.0).round() / 64.0));
1840 put(
1841 &mut t,
1842 &format!("ups.tconv.{i}"),
1843 &[8],
1844 [a[0], a[1], a[2], a[3], a[3], a[2], a[1], a[0]].to_vec(),
1845 );
1846 let h: Vec<f64> = (0..4).map(|k| if k == 3 { 0.25 } else { r.q(4) }).collect();
1847 put(
1848 &mut t,
1849 &format!("ups.conv.{i}"),
1850 &[7],
1851 vec![h[0], h[1], h[2], h[3], h[2], h[1], h[0]],
1852 );
1853 }
1854 let conv = |t: &mut HashMap<_, _>,
1855 r: &mut Rng,
1856 p: &str,
1857 o: usize,
1858 i: usize,
1859 k: usize,
1860 res: bool,
1861 relu: bool| {
1862 put(
1863 t,
1864 &format!("{p}.w"),
1865 &[o, i, k, k],
1866 (0..o * i * k * k).map(|_| r.q(30)).collect(),
1867 );
1868 put(
1869 t,
1870 &format!("{p}.b"),
1871 &[o],
1872 (0..o).map(|_| r.q(30)).collect(),
1873 );
1874 put(
1875 t,
1876 &format!("{p}.meta"),
1877 &[2],
1878 vec![res as u8 as f64, relu as u8 as f64],
1879 );
1880 };
1881 conv(&mut t, &mut r, "syn.L0", 8, 3, 1, false, true);
1882 conv(&mut t, &mut r, "syn.L1", 3, 8, 1, false, false);
1883 conv(&mut t, &mut r, "syn.L2", 3, 3, 3, true, true);
1884 conv(&mut t, &mut r, "syn.stab", 3, 3, 1, false, false);
1885 put(
1886 &mut t,
1887 "syn.out.w",
1888 &[3, 3, 1, 1],
1889 vec![1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0],
1890 );
1891 put(&mut t, "syn.out.b", &[3], vec![0.5; 3]);
1892 put(&mut t, "syn.out.meta", &[2], vec![0.0, 0.0]);
1893 for (g, &(h, w)) in sizes.iter().enumerate() {
1894 let v = (0..h * w)
1896 .map(|_| match r.next() % 40 {
1897 0 => 40.0,
1898 1 => -37.0,
1899 k => (k % 5) as f64 - 2.0,
1900 })
1901 .collect();
1902 put(&mut t, &format!("latent.{g}"), &[h, w], v);
1903 }
1904 Ccx { t }
1905 }
1906
1907 #[test]
1908 fn tables_are_normalized() {
1909 let t = tables();
1910 for c in t.chunks(NSYM + 1) {
1911 assert_eq!(c[0], 0);
1912 assert_eq!(c[NSYM], PM);
1913 assert!(c.windows(2).all(|w| w[1] > w[0]));
1914 }
1915 }
1916
1917 #[test]
1918 fn roundtrip_layouts() {
1919 let c = synth(7);
1920 let n = 4;
1921 let truth: Vec<Vec<i32>> = (0..n)
1922 .map(|g| {
1923 c.ints(&format!("latent.{g}"))
1924 .iter()
1925 .map(|&v| v as i32)
1926 .collect()
1927 })
1928 .collect();
1929 let mut first: Option<Vec<u8>> = None;
1930 for (lanes, tw, th) in [
1931 (1, 0, 0),
1932 (4, 0, 0),
1933 (16, 0, 0),
1934 (16, 8, 0),
1935 (16, 0, 4),
1936 (32, 8, 8),
1937 ] {
1938 let (bytes, st) = encode(&c, lanes, tw, th);
1939 assert_eq!(st.bytes, bytes.len());
1940 let p = parse(&bytes).unwrap();
1941 let mut gd = Guard::default();
1942 assert_eq!(
1943 decode_latents(&p, &mut gd),
1944 truth,
1945 "lanes {lanes} tile {tw}x{th}"
1946 );
1947 let (h, w, rgb) = decode(&bytes).unwrap();
1948 assert_eq!((h, w), (16, 24));
1949 match &first {
1951 None => first = Some(rgb),
1952 Some(f) => assert_eq!(f, &rgb),
1953 }
1954 }
1955 }
1956
1957 #[test]
1958 fn graphs_match_native() {
1959 let c = synth(11);
1960 let (bytes, _) = encode(&c, 4, 0, 0);
1961 let p = parse(&bytes).unwrap();
1962 let m = &p.m;
1963 let mut r = Rng(3);
1964 for mlp in std::iter::once(&m.arm).chain(&m.ifces) {
1965 let (g, o) = mlp.graph();
1966 let mut prog = Program::new(&g, &o);
1967 for _ in 0..200 {
1968 let x: Vec<i32> = (0..mlp.nin())
1969 .map(|_| (r.next() % 2049) as i32 - 1024)
1970 .collect();
1971 let mut want = vec![0i32; mlp.nout()];
1972 mlp.run(&x, &mut want, &mut Guard::default());
1973 let xin: Vec<u32> = x.iter().map(|&v| v as u32).collect();
1974 let mut got = vec![0u32; mlp.nout()];
1975 prog.run(&xin, &[], &mut got);
1976 assert_eq!(got.iter().map(|&v| v as i32).collect::<Vec<_>>(), want);
1977 }
1978 }
1979 let segs = segments(m);
1981 assert!(!segs.is_empty());
1982 }
1983
1984 #[test]
1985 fn rejects_garbage() {
1986 assert!(parse(b"TCI1").is_err());
1987 let (mut bytes, _) = encode(&synth(5), 4, 0, 0);
1988 bytes.truncate(bytes.len() / 2);
1989 assert!(parse(&bytes).is_err());
1990 }
1991}