1use crate::abac::{BitModel, Decoder, Encoder, UintModel};
22use crate::bitio::{ByteReader, ByteWriter, DecodeError};
23use crate::codec::Decoded;
24use crate::interp::{quant, rate_control, ESC};
25
26pub const MAGIC: &[u8; 4] = b"TCL1";
28
29const ACT: usize = 9;
30const CLS: usize = 4;
32
33struct Models {
34 zero: Vec<BitModel>,
35 sign: Vec<BitModel>,
36 mag: Vec<UintModel>,
37}
38
39impl Models {
40 fn new() -> Self {
41 Self {
42 zero: vec![BitModel::default(); CLS * CLS * ACT],
43 sign: vec![BitModel::default(); 3],
44 mag: vec![UintModel::default(); CLS * CLS],
45 }
46 }
47}
48
49#[derive(Clone, Copy)]
51struct Ctx {
52 up: usize,
53 side: usize,
54 act: usize,
55 sgn: usize,
57}
58
59fn record(q: i64, esc: bool) -> u8 {
61 let c = if esc || q.unsigned_abs() > 1 {
62 2
63 } else {
64 q.unsigned_abs() as u8
65 };
66 c | ((q < 0) as u8) << 2
67}
68
69fn strides(dims: &[usize]) -> Vec<usize> {
70 let mut st = vec![1usize; dims.len()];
71 for j in (0..dims.len().saturating_sub(1)).rev() {
72 st[j] = st[j + 1] * dims[j + 1];
73 }
74 st
75}
76
77fn modes(nd: usize) -> u8 {
79 if nd == 1 {
80 1
81 } else {
82 nd as u8 + 1
83 }
84}
85
86fn walk(
89 dims: &[usize],
90 mode: u8,
91 b: f64,
92 r: &mut [f32],
93 rec: &mut [u8],
94 mut f: impl FnMut(usize, f64, Ctx) -> (f32, u8),
95) {
96 let nd = dims.len();
97 let st = strides(dims);
98 let k = if mode == 0 { 0 } else { mode as usize - 1 };
100 let side = if k == nd - 1 {
101 nd.checked_sub(2)
102 } else {
103 Some(nd - 1)
104 };
105 let step = 2.0 * b;
106 let n: usize = dims.iter().product();
107 let mut c = vec![0usize; nd];
108 for i in 0..n {
109 let along = c[k] > 0;
110 let pred = if along && mode != 0 {
111 r[i - st[k]] as f64
112 } else {
113 let live: Vec<usize> = (0..nd).filter(|&j| c[j] > 0).map(|j| st[j]).collect();
115 let mut p = 0f64;
116 for m in 1u32..(1 << live.len()) {
117 let off: usize = (0..live.len())
118 .filter(|&t| m >> t & 1 == 1)
119 .map(|t| live[t])
120 .sum();
121 let v = r[i - off] as f64;
122 p += if m.count_ones() % 2 == 1 { v } else { -v };
123 }
124 p
125 };
126 let (up, sgn, act) = if along {
127 let u = rec[i - st[k]];
128 let act = if c[k] > 1 {
129 let d = (r[i - st[k]] as f64 - r[i - 2 * st[k]] as f64).abs() / step;
130 let u = d as u64;
131 ((u64::BITS - u.leading_zeros()) as usize).min(ACT - 2)
132 } else {
133 ACT - 1
134 };
135 let sgn = if u & 3 == 0 { 0 } else { 1 + (u >> 2) as usize };
136 ((u & 3) as usize, sgn, act)
137 } else {
138 (CLS - 1, 0, ACT - 1)
139 };
140 let sd = match side {
141 Some(s) if c[s] > 0 => (rec[i - st[s]] & 3) as usize,
142 _ => CLS - 1,
143 };
144 let (v, q) = f(
145 i,
146 pred,
147 Ctx {
148 up,
149 side: sd,
150 act,
151 sgn,
152 },
153 );
154 r[i] = v;
155 rec[i] = q;
156 for j in (0..nd).rev() {
157 c[j] += 1;
158 if c[j] < dims[j] {
159 break;
160 }
161 c[j] = 0;
162 }
163 }
164}
165
166fn put(e: &mut Encoder, m: &mut Models, cx: Ctx, q: i64, raw: Option<f32>) {
167 let z = (cx.up * CLS + cx.side) * ACT + cx.act;
168 if q == 0 && raw.is_none() {
169 e.encode(false, &mut m.zero[z]);
170 return;
171 }
172 e.encode(true, &mut m.zero[z]);
173 e.encode(q < 0, &mut m.sign[cx.sgn]);
174 let mc = cx.up * CLS + cx.side;
175 match raw {
176 Some(v) => {
177 m.mag[mc].encode(e, ESC - 1);
178 e.encode_raw(v.to_bits() as u64, 32);
179 }
180 None => m.mag[mc].encode(e, q.unsigned_abs() - 1),
181 }
182}
183
184fn get(d: &mut Decoder, m: &mut Models, cx: Ctx) -> Result<i64, f32> {
186 let z = (cx.up * CLS + cx.side) * ACT + cx.act;
187 if !d.decode(&mut m.zero[z]) {
188 return Ok(0);
189 }
190 let neg = d.decode(&mut m.sign[cx.sgn]);
191 let a = m.mag[cx.up * CLS + cx.side].decode(d) + 1;
192 if a >= ESC {
193 return Err(f32::from_bits(d.decode_raw(32) as u32));
194 }
195 Ok(if neg { -(a as i64) } else { a as i64 })
196}
197
198fn encode_sse(x: &[f32], dims: &[usize], b: f64, mode: u8) -> (Vec<u8>, f64) {
200 let n = x.len();
201 let mut r = vec![0f32; n];
202 let mut rc = vec![0u8; n];
203 let mut m = Models::new();
204 let mut e = Encoder::new();
205 let step = 2.0 * b;
206 walk(dims, mode, b, &mut r, &mut rc, |i, p, cx| {
207 let (q, v, esc) = quant(x[i], p, step, b);
208 put(&mut e, &mut m, cx, q, esc.then_some(x[i]));
209 (v, record(q, esc))
210 });
211 let mut w = ByteWriter::new();
212 w.bytes(MAGIC);
213 w.u8(dims.len() as u8);
214 for &d in dims {
215 w.varint(d as u64);
216 }
217 w.f64(b);
218 w.u8(mode);
219 w.bytes(&e.finish());
220 let sse = x
221 .iter()
222 .zip(&r)
223 .map(|(&a, &b)| (a as f64 - b as f64).powi(2))
224 .sum();
225 (w.buf, sse)
226}
227
228fn check(x: &[f32], dims: &[usize]) {
229 assert_eq!(
230 x.len(),
231 dims.iter().product::<usize>(),
232 "dims do not match data"
233 );
234 assert!(!dims.is_empty() && dims.len() <= 8);
235}
236
237fn best_mode(x: &[f32], dims: &[usize], b: f64) -> (u8, Vec<u8>) {
239 (0..modes(dims.len()))
240 .map(|md| (md, encode_sse(x, dims, b, md).0))
241 .min_by_key(|(_, s)| s.len())
242 .unwrap()
243}
244
245pub fn encode_f32(x: &[f32], dims: &[usize], b: f64) -> Vec<u8> {
248 check(x, dims);
249 assert!(b > 0.0);
250 best_mode(x, dims, b).1
251}
252
253pub fn encode_rmse_f32(x: &[f32], dims: &[usize], rmse: f64) -> Vec<u8> {
258 check(x, dims);
259 assert!(rmse > 0.0);
260 let (mode, _) = best_mode(x, dims, rmse * 3f64.sqrt());
261 rate_control(x.len(), rmse, |b| encode_sse(x, dims, b, mode))
262}
263
264pub fn encode_psnr_f32(x: &[f32], dims: &[usize], psnr: f64) -> Vec<u8> {
266 let (lo, hi) = x
267 .iter()
268 .fold((f64::INFINITY, f64::NEG_INFINITY), |(a, b), &v| {
269 (a.min(v as f64), b.max(v as f64))
270 });
271 let range = if hi > lo { hi - lo } else { 1.0 };
272 encode_rmse_f32(x, dims, range / 10f64.powf(psnr / 20.0))
273}
274
275pub fn decode(bytes: &[u8]) -> Result<Decoded, DecodeError> {
277 let mut rd = ByteReader::new(bytes);
278 if rd.take(4)? != MAGIC {
279 return Err(DecodeError::Invalid("magic"));
280 }
281 let nd = rd.u8()? as usize;
282 let dims = (0..nd)
283 .map(|_| rd.varint().map(|v| v as usize))
284 .collect::<Result<Vec<_>, _>>()?;
285 if nd == 0
286 || nd > 8
287 || dims.contains(&0)
288 || dims
289 .iter()
290 .try_fold(1usize, |a, &d| a.checked_mul(d))
291 .is_none_or(|n| n as u64 > 1 << 34)
292 {
293 return Err(DecodeError::Invalid("dims"));
294 }
295 let b = rd.f64()?;
296 let mode = rd.u8()?;
297 if b.is_nan() || b <= 0.0 {
298 return Err(DecodeError::Invalid("bound"));
299 }
300 if mode >= modes(nd) {
301 return Err(DecodeError::Invalid("mode"));
302 }
303 let mut d = Decoder::new(&bytes[rd.position()..]);
304 let mut m = Models::new();
305 let n: usize = dims.iter().product();
306 let mut r = vec![0f32; n];
307 let mut rc = vec![0u8; n];
308 let step = 2.0 * b;
309 walk(&dims, mode, b, &mut r, &mut rc, |_, p, cx| {
310 match get(&mut d, &mut m, cx) {
311 Ok(q) => ((p + q as f64 * step) as f32, record(q, false)),
312 Err(v) => (v, record(0, true)),
313 }
314 });
315 if d.overrun() {
316 return Err(DecodeError::Invalid("truncated"));
317 }
318 Ok(Decoded::F32 { dims, data: r })
319}
320
321#[cfg(test)]
322mod tests {
323 use super::*;
324
325 fn field(d: &[usize]) -> Vec<f32> {
326 let n: usize = d.iter().product();
327 (0..n)
328 .map(|i| {
329 let t = i as f32 / n as f32;
330 (t * 40.0).sin() * 3.0
331 + ((i * 7919) % 13) as f32 * 0.4
332 + if i % 997 == 0 { 50.0 } else { 0.0 }
333 })
334 .collect()
335 }
336
337 #[test]
338 fn round_trips_within_bound_in_every_mode() {
339 for d in [
340 vec![1000],
341 vec![33, 70],
342 vec![17, 9, 31],
343 vec![1, 1, 5],
344 vec![1],
345 ] {
346 let x = field(&d);
347 for b in [1e-1, 1e-3, 1e-6] {
348 for md in 0..modes(d.len()) {
349 let (bytes, sse) = encode_sse(&x, &d, b, md);
350 let Decoded::F32 { data, dims } = decode(&bytes).unwrap() else {
351 panic!()
352 };
353 assert_eq!(dims, d);
354 let mut got = 0f64;
355 for (a, c) in x.iter().zip(&data) {
356 assert!(((a - c) as f64).abs() <= b, "{d:?} b={b} m={md} {a} {c}");
357 got += (*a as f64 - *c as f64).powi(2);
358 }
359 assert_eq!(got, sse);
360 }
361 }
362 }
363 }
364
365 #[test]
366 fn psnr_targets_are_met() {
367 let d = [64, 50];
368 let x = field(&d);
369 let (lo, hi) = x
370 .iter()
371 .fold((f64::INFINITY, f64::NEG_INFINITY), |(a, b), &v| {
372 (a.min(v as f64), b.max(v as f64))
373 });
374 for p in [40.0, 70.0, 100.0] {
375 let s = encode_psnr_f32(&x, &d, p);
376 let Decoded::F32 { data: y, .. } = decode(&s).unwrap() else {
377 panic!()
378 };
379 let mse = x
380 .iter()
381 .zip(&y)
382 .map(|(&a, &b)| (a as f64 - b as f64).powi(2))
383 .sum::<f64>()
384 / x.len() as f64;
385 assert!(20.0 * ((hi - lo) / mse.sqrt()).log10() >= p);
386 }
387 }
388
389 #[test]
390 fn picks_the_repeating_axis() {
391 let d = [64, 64];
394 let x: Vec<f32> = (0..64 * 64)
395 .map(|i| {
396 let (t, p) = (i / 64, i % 64);
397 ((p * 2654435761usize) % 1000) as f32 * 0.01
398 + (((p + 64 * ((t + p) / 8)) * 40503) % 97) as f32 * 0.05
399 })
400 .collect();
401 let (mode, _) = best_mode(&x, &d, 1e-3);
402 assert_eq!(mode, 1);
403 }
404}