1use crate::gpuwav::{Feats, Sink};
20use crate::learned::{lg_q8, Net, NF, NO};
21use std::sync::OnceLock;
22use tang_expr::int::{IId, IType, IntGraph, Program};
23
24pub const NFL: usize = 28;
26pub const ZM: i32 = 16 * 256;
28
29pub fn tables() -> &'static (Vec<u32>, Vec<u32>) {
31 static T: OnceLock<(Vec<u32>, Vec<u32>)> = OnceLock::new();
32 T.get_or_init(|| {
33 let x = 1.0f64 / 256.0;
34 let (mut term, mut em) = (1.0f64, 1.0f64);
35 for k in 1..20 {
36 term = term * (-x) / k as f64;
37 em += term;
38 }
39 let mut sig = Vec::with_capacity(ZM as usize + 1);
40 let mut p = 1.0f64;
41 for _ in 0..=ZM {
42 sig.push((65536.0 / (1.0 + p)).round() as u32);
43 p *= em;
44 }
45 let mut r = 2.0f64;
46 for _ in 0..8 {
47 r = r.sqrt();
48 }
49 let mut pw = Vec::with_capacity(257);
50 let mut v = 1.0f64;
51 for _ in 0..=256 {
52 pw.push((v * 65536.0).round() as u32);
53 v *= r;
54 }
55 (sig, pw)
56 })
57}
58
59#[inline]
60fn slg(v: i32) -> i32 {
61 if v < 0 {
62 -lg_q8(v.unsigned_abs())
63 } else {
64 lg_q8(v as u32)
65 }
66}
67
68pub fn feat_vec3(f: &Feats, class: usize) -> [i32; NF] {
70 let r = &f.raw;
71 let mut x = [0i32; NF];
72 for i in 0..7 {
73 x[i] = slg(r[i]);
74 }
75 for i in 7..14 {
76 x[i] = lg_q8(r[i] as u32);
77 }
78 x[14] = r[14] * 64;
79 x[15] = r[15] * 32;
80 x[16] = r[16] * 32;
81 x[17] = r[17] * 256;
82 x[18 + class.min(9)] = 256;
83 x
84}
85
86#[derive(Clone, Debug)]
88pub struct Net32 {
89 pub sizes: Vec<usize>,
91 pub w: Vec<Vec<i32>>,
93 pub b: Vec<Vec<i32>>,
95}
96
97impl Net32 {
98 pub fn new(net: &Net) -> Self {
100 assert_eq!(net.sizes[0], NF);
101 assert_eq!(*net.sizes.last().unwrap(), NO);
102 let mut sizes = net.sizes.clone();
103 sizes[0] = NFL;
104 let w = (0..sizes.len() - 1)
105 .map(|l| {
106 let (ni_full, ni, no) = (net.sizes[l], sizes[l], sizes[l + 1]);
107 (0..no)
108 .flat_map(|o| (0..ni).map(move |i| (o, i)))
109 .map(|(o, i)| net.wq[l][o * ni_full + i].clamp(-2047, 2047))
110 .collect()
111 })
112 .collect();
113 let b = net
114 .bq
115 .iter()
116 .map(|v| v.iter().map(|&x| x.clamp(-(1 << 24), 1 << 24)).collect())
117 .collect();
118 Self { sizes, w, b }
119 }
120
121 pub fn infer(&self, x: &[i32; NF]) -> [i32; NO] {
123 let mut a = [0i32; 64];
124 let mut nb = [0i32; 64];
125 for i in 0..NFL {
126 a[i] = x[i].clamp(-(1 << 14), 1 << 14);
127 }
128 let nl = self.sizes.len() - 1;
129 for l in 0..nl {
130 let (ni, no) = (self.sizes[l], self.sizes[l + 1]);
131 for o in 0..no {
132 let mut acc = self.b[l][o];
133 for i in 0..ni {
134 acc = acc.wrapping_add(self.w[l][o * ni + i].wrapping_mul(a[i]));
135 }
136 let v = acc.wrapping_add(128) >> 8;
137 nb[o] = if l + 1 < nl {
138 v.clamp(0, 1 << 14)
139 } else {
140 v.clamp(-(1 << 14), 1 << 14)
141 };
142 }
143 std::mem::swap(&mut a, &mut nb);
144 }
145 [a[0], a[1], a[2], a[3], a[4]]
146 }
147
148 pub fn graph(&self) -> (IntGraph, Vec<IId>) {
154 let mut g = IntGraph::new();
155 let mut a: Vec<IId> = (0..NFL).map(|i| g.param(i as u16, IType::I32)).collect();
156 let nl = self.sizes.len() - 1;
157 let (r, sh) = (g.i32(128), g.u32(8));
158 for l in 0..nl {
159 let (ni, no) = (self.sizes[l], self.sizes[l + 1]);
160 let (lo, hi) = if l + 1 < nl {
161 (g.i32(0), g.i32(1 << 14))
162 } else {
163 (g.i32(-(1 << 14)), g.i32(1 << 14))
164 };
165 a = (0..no)
166 .map(|o| {
167 let mut acc = g.i32(self.b[l][o]);
168 for (i, &ai) in a.iter().enumerate().take(ni) {
169 let w = self.w[l][o * ni + i];
170 if w != 0 {
171 let w = g.i32(w);
172 let t = g.mul(w, ai);
173 acc = g.add(acc, t);
174 }
175 }
176 let v = g.add(acc, r);
177 let v = g.shr(v, sh);
178 g.clamp(v, lo, hi)
179 })
180 .collect();
181 }
182 (g, a)
183 }
184
185 pub fn program(&self) -> Program {
187 let (g, o) = self.graph();
188 Program::new(&g, &o)
189 }
190
191 pub fn infer_ir(&self, p: &mut Program, x: &[i32; NF]) -> [i32; NO] {
193 let mut inp = [0u32; NFL];
194 for i in 0..NFL {
195 inp[i] = x[i].clamp(-(1 << 14), 1 << 14) as u32;
196 }
197 let mut o = [0u32; NO];
198 p.run(&inp, &[], &mut o);
199 o.map(|v| v as i32)
200 }
201
202 pub fn flat(&self) -> Vec<u32> {
204 let mut v = vec![(self.sizes.len() - 1) as u32];
205 v.extend(self.sizes.iter().map(|&s| s as u32));
206 for l in 0..self.sizes.len() - 1 {
207 v.extend(self.w[l].iter().map(|&x| x as u32));
208 v.extend(self.b[l].iter().map(|&x| x as u32));
209 }
210 v
211 }
212}
213
214#[inline]
216pub fn sig16(z: i32) -> u32 {
217 let (s, _) = tables();
218 let a = z.unsigned_abs().min(ZM as u32) as usize;
219 if z >= 0 {
220 s[a]
221 } else {
222 65536 - s[a]
223 }
224}
225
226#[inline]
230pub fn zval(d: i32, ls: i32) -> i32 {
231 let (_, pw) = tables();
232 let ls = ls.clamp(-16 * 256, 24 * 256);
233 let i = ls.div_euclid(256);
234 let f = ls.rem_euclid(256);
235 let m = pw[(256 - f) as usize] as i32;
236 let t = crate::gpuwav::mulsh(d.clamp(-(1 << 25), 1 << 25), m, 16);
237 let sh = i + 1;
238 if sh >= 0 {
239 t >> sh.min(31)
240 } else {
241 let k = -sh;
242 let lim = (ZM + 1) >> k;
243 if t > lim {
244 ZM + 1
245 } else if t < -lim {
246 -(ZM + 1)
247 } else {
248 t << k
249 }
250 }
251}
252
253#[derive(Clone, Copy, Debug)]
255pub struct Mix3 {
256 pi15: u32,
257 mu: [i32; 2],
258 ls: [i32; 2],
259}
260
261impl Mix3 {
262 pub fn new(o: &[i32; NO]) -> Self {
264 Self {
265 pi15: sig16(o[0]) >> 1,
266 mu: [o[1], o[2]],
267 ls: [o[3], o[4]],
268 }
269 }
270
271 #[inline]
273 pub fn cdf(&self, m: i32) -> u32 {
274 let t = m.clamp(-65535, 65535) * 256 + 128;
275 let c = |k: usize| sig16(zval(t - self.mu[k], self.ls[k]));
276 (self.pi15 * c(0) + (32768 - self.pi15) * c(1)) >> 15
277 }
278}
279
280#[inline]
282pub fn ratio16(num: u32, den: u32) -> u32 {
283 let p = (num.min(den) * 65535).checked_div(den).unwrap_or(32768);
284 p.clamp(32, 65504)
285}
286
287pub fn stretch_tab() -> &'static Vec<i32> {
290 static T: OnceLock<Vec<i32>> = OnceLock::new();
291 T.get_or_init(|| {
292 let mut z = -ZM;
293 (0..4096u32)
294 .map(|i| {
295 let p = 16 * i + 8;
296 while z < ZM && sig16(z) < p {
297 z += 1;
298 }
299 z
300 })
301 .collect()
302 })
303}
304
305#[derive(Clone, Copy, Debug, PartialEq, Eq)]
307pub struct AdCfg {
308 pub wa: u32,
310 pub lim: u32,
312 pub mask: u32,
314}
315
316pub const AB: usize = 17;
318pub const AC: usize = 8;
320
321pub fn ad_init() -> [u32; AC * AB] {
324 std::array::from_fn(|i| sig16(((i % AB) as i32 - 8) * 256) << 8)
325}
326
327#[derive(Clone, Debug)]
331pub struct Adapt {
332 pub c: AdCfg,
334 t: [u32; AC * AB],
335 n: [u8; AC * AB],
336}
337
338impl Adapt {
339 pub fn new(c: AdCfg) -> Self {
341 let t = std::array::from_fn(|i| sig16(((i % AB) as i32 - 8) * 256));
342 Self {
343 c,
344 t,
345 n: [0; AC * AB],
346 }
347 }
348
349 #[inline]
351 fn bit<S: Sink>(&mut self, s: &mut S, lane: usize, ctx: usize, bit: bool, p1: u32) -> bool {
352 let grp = match ctx {
353 0 | 1 => ctx,
354 2..=5 => 2,
355 _ => 3,
356 };
357 if self.c.wa == 0 || (self.c.mask >> grp) & 1 == 0 {
358 return s.bit(lane, bit, p1);
359 }
360 let st = stretch_tab()[(p1 >> 4) as usize].clamp(-2048, 2047) + 2048;
361 let (j, w) = ((st >> 8) as usize, (st & 255) as u32);
362 let b = ctx * AB + j;
363 let pr = (self.t[b] * (256 - w) + self.t[b + 1] * w) >> 8;
364 let pf = (pr * self.c.wa + p1 * (16 - self.c.wa)) >> 4;
365 let got = s.bit(lane, bit, pf.clamp(32, 65504));
366 let k = if w < 128 { b } else { b + 1 };
367 let tgt = if got { 65535 } else { 0 };
368 let d = tgt - self.t[k] as i32;
369 self.t[k] =
371 (self.t[k] as i32 + (d >> (31 - (self.n[k] as u32 + 2).leading_zeros()))) as u32;
372 if (self.n[k] as u32) < self.c.lim {
373 self.n[k] += 1;
374 }
375 got
376 }
377}
378
379pub fn code_learned<S: Sink>(s: &mut S, lane: usize, mx: &Mix3, r: i32) -> i32 {
381 let mut ad = Adapt::new(AdCfg {
382 wa: 0,
383 lim: 0,
384 mask: 0,
385 });
386 code_learned_ad(s, lane, mx, r, &mut ad)
387}
388
389pub fn code_learned_ad<S: Sink>(s: &mut S, lane: usize, mx: &Mix3, r: i32, ad: &mut Adapt) -> i32 {
391 let c0 = mx.cdf(0);
392 let cm1 = mx.cdf(-1);
393 let pz = c0.saturating_sub(cm1);
394 if !ad.bit(s, lane, 0, r != 0, ratio16(65536 - pz, 65536)) {
395 return 0;
396 }
397 let negm = cm1;
398 let posm = 65536 - c0;
399 let neg = ad.bit(s, lane, 1, r < 0, ratio16(negm, negm + posm));
400 let tail = |m: u32| -> u32 {
401 if m > 1 << 30 {
402 return 0;
403 }
404 if neg {
405 mx.cdf(-(m as i32))
406 } else {
407 65536 - mx.cdf(m as i32 - 1)
408 }
409 };
410 let mag = r.unsigned_abs();
411 let mut k = 0u32;
412 while k < 30 {
413 let a = tail(1 << k);
414 let bb = tail(1 << (k + 1));
415 if !ad.bit(
416 s,
417 lane,
418 2 + k.min(3) as usize,
419 mag >= 1 << (k + 1),
420 ratio16(bb, a),
421 ) {
422 break;
423 }
424 k += 1;
425 }
426 let (mut lo, mut hi) = (1u32 << k, ((1u64 << (k + 1)) - 1) as u32);
427 let mut first = true;
428 while lo < hi {
429 let mid = lo + (hi - lo).div_ceil(2);
430 let end = if hi == u32::MAX { 0 } else { tail(hi + 1) };
431 let up = tail(mid).saturating_sub(end);
432 let all = tail(lo).saturating_sub(end);
433 let ctx = if first { 6 } else { 7 };
434 first = false;
435 if ad.bit(s, lane, ctx, mag >= mid, ratio16(up, all)) {
436 lo = mid;
437 } else {
438 hi = mid - 1;
439 }
440 }
441 if neg {
442 (lo as i32).wrapping_neg()
443 } else {
444 lo as i32
445 }
446}
447
448#[cfg(test)]
449mod tests {
450 use super::*;
451 use crate::gpuwav::{rans_encode, DecSink, RansDec, RecSink};
452
453 #[test]
454 fn ir_graph_matches_infer() {
455 let mut st = 7u64;
456 let mut rnd = || {
457 st = st
458 .wrapping_mul(6364136223846793005)
459 .wrapping_add(1442695040888963407);
460 (st >> 33) as i32
461 };
462 for sizes in [vec![NFL, 16, NO], vec![NFL, 32, 16, NO]] {
463 let w = (0..sizes.len() - 1)
464 .map(|l| {
465 (0..sizes[l] * sizes[l + 1])
466 .map(|k| if k % 5 == 0 { 0 } else { rnd() % 4095 - 2047 })
467 .collect()
468 })
469 .collect();
470 let b = (1..sizes.len())
471 .map(|l| {
472 (0..sizes[l])
473 .map(|_| rnd() % (1 << 25) - (1 << 24))
474 .collect()
475 })
476 .collect();
477 let net = Net32 { sizes, w, b };
478 let mut p = net.program();
479 for k in 0..5000 {
480 let mut x = [0i32; NF];
481 for v in x.iter_mut() {
482 *v = match k % 3 {
483 0 => rnd() % 40000 - 20000,
484 1 => rnd() % 512,
485 _ => [16384, -16384, i32::MAX, i32::MIN][(rnd() & 3) as usize],
486 };
487 }
488 assert_eq!(net.infer_ir(&mut p, &x), net.infer(&x));
489 }
490 }
491 }
492
493 #[test]
494 fn learned_round_trip() {
495 let mut st = 99u64;
496 let mut rnd = || {
497 st = st
498 .wrapping_mul(6364136223846793005)
499 .wrapping_add(1442695040888963407);
500 (st >> 33) as i32
501 };
502 let cases: Vec<(Mix3, i32)> = (0..20000)
503 .map(|i| {
504 let o = [
505 rnd() % 2000,
506 rnd() % 3000,
507 rnd() % 600,
508 rnd() % 4000 - 600,
509 rnd() % 2500,
510 ];
511 let r = match i % 5 {
512 0 => 0,
513 1 => rnd() % 7 - 3,
514 2 => rnd() % 300 - 150,
515 3 => rnd() % 200000 - 100000,
516 _ => [i32::MAX, i32::MIN + 1, 65536, -65537][(i / 5) % 4],
517 };
518 (Mix3::new(&o), r)
519 })
520 .collect();
521 let mut s = RecSink {
522 syms: vec![Vec::new()],
523 };
524 for (m, r) in &cases {
525 assert_eq!(code_learned(&mut s, 0, m, *r), *r);
526 }
527 let w = rans_encode(&s.syms[0]);
528 let mut d = DecSink {
529 lanes: vec![RansDec::new(&w)],
530 };
531 for (m, r) in &cases {
532 assert_eq!(code_learned(&mut d, 0, m, 0), *r);
533 }
534 }
535}