Skip to main content

cram_codec/
abac.rs

1//! Adaptive binary arithmetic coding — integer only, bit-exact everywhere.
2//!
3//! A carry-propagating 32-bit range coder (the LZMA construction) driven by
4//! 16-bit probabilities. Everything from a probability to an output byte is
5//! integer arithmetic, so any backend that feeds the same probabilities
6//! produces and consumes the same bytes. Probabilities come either from
7//! [`BitModel`] (two-rate adaptive counter) or straight from a model (e.g. the
8//! fixed-point network in [`crate::learned`]) via [`Encoder::encode_p`].
9
10/// Probability scale: `p1 ∈ [P_MIN, ONE − P_MIN]` means `P(bit = 1) = p1 / ONE`.
11pub const ONE: u32 = 1 << 16;
12/// Smallest probability either symbol may get.
13pub const P_MIN: u32 = 32;
14const TOP: u32 = 1 << 24;
15
16/// Clamp a probability of a one into the codable range.
17#[inline]
18pub fn clamp_p(p1: u32) -> u32 {
19    p1.clamp(P_MIN, ONE - P_MIN)
20}
21
22/// Two-rate adaptive bit model (fast + slow exponential counters, averaged).
23#[derive(Clone, Copy, Debug)]
24pub struct BitModel {
25    fast: u16,
26    slow: u16,
27}
28
29impl Default for BitModel {
30    fn default() -> Self {
31        Self::new(ONE / 2)
32    }
33}
34
35impl BitModel {
36    /// Model starting at `P(1) = p1 / 2^16`.
37    pub fn new(p1: u32) -> Self {
38        let p = clamp_p(p1) as u16;
39        Self { fast: p, slow: p }
40    }
41    /// `fast | slow << 16` (the GPU decoder's model word).
42    pub fn packed(&self) -> u32 {
43        self.fast as u32 | (self.slow as u32) << 16
44    }
45    /// Current `P(1)` in 16-bit fixed point.
46    #[inline]
47    pub fn p1(&self) -> u32 {
48        clamp_p((self.fast as u32 + self.slow as u32) >> 1)
49    }
50    /// Adapt towards `bit`.
51    #[inline]
52    pub fn update(&mut self, bit: bool) {
53        if bit {
54            self.fast += (65535 - self.fast) >> 4;
55            self.slow += (65535 - self.slow) >> 7;
56        } else {
57            self.fast -= self.fast >> 4;
58            self.slow -= self.slow >> 7;
59        }
60    }
61}
62
63/// Range encoder.
64#[derive(Debug)]
65pub struct Encoder {
66    low: u64,
67    range: u32,
68    cache: u8,
69    cache_size: u64,
70    out: Vec<u8>,
71}
72
73impl Default for Encoder {
74    fn default() -> Self {
75        Self::new()
76    }
77}
78
79impl Encoder {
80    /// Fresh encoder.
81    pub fn new() -> Self {
82        Self {
83            low: 0,
84            range: u32::MAX,
85            cache: 0,
86            cache_size: 1,
87            out: Vec::new(),
88        }
89    }
90
91    fn shift_low(&mut self) {
92        if self.low < 0xFF00_0000 || self.low > 0xFFFF_FFFF {
93            let carry = (self.low >> 32) as u8;
94            let mut temp = self.cache;
95            loop {
96                self.out.push(temp.wrapping_add(carry));
97                temp = 0xFF;
98                self.cache_size -= 1;
99                if self.cache_size == 0 {
100                    break;
101                }
102            }
103            self.cache = ((self.low >> 24) & 0xFF) as u8;
104        }
105        self.cache_size += 1;
106        self.low = (self.low & 0x00FF_FFFF) << 8;
107    }
108
109    /// Code `bit` with `P(1) = p1 / 2^16` (clamped).
110    #[inline]
111    pub fn encode_p(&mut self, bit: bool, p1: u32) {
112        let p0 = ONE - clamp_p(p1);
113        let bound = (self.range >> 16) * p0;
114        if bit {
115            self.low += bound as u64;
116            self.range -= bound;
117        } else {
118            self.range = bound;
119        }
120        while self.range < TOP {
121            self.range <<= 8;
122            self.shift_low();
123        }
124    }
125
126    /// Code `bit` with an adaptive model, then adapt it.
127    #[inline]
128    pub fn encode(&mut self, bit: bool, m: &mut BitModel) {
129        self.encode_p(bit, m.p1());
130        m.update(bit);
131    }
132
133    /// `n` raw (equiprobable) bits of `v`, MSB first.
134    pub fn encode_raw(&mut self, v: u64, n: u32) {
135        for i in (0..n).rev() {
136            self.encode_p((v >> i) & 1 == 1, ONE / 2);
137        }
138    }
139
140    /// Flush and return the bytes.
141    pub fn finish(mut self) -> Vec<u8> {
142        for _ in 0..5 {
143            self.shift_low();
144        }
145        // The first byte is always the initial zero cache; drop it.
146        self.out.remove(0);
147        self.out
148    }
149}
150
151/// Range decoder over a byte slice (reads past the end as zeros).
152#[derive(Debug)]
153pub struct Decoder<'a> {
154    code: u32,
155    range: u32,
156    buf: &'a [u8],
157    pos: usize,
158}
159
160impl<'a> Decoder<'a> {
161    /// Start decoding `buf` (as produced by [`Encoder::finish`]).
162    pub fn new(buf: &'a [u8]) -> Self {
163        let mut d = Self {
164            code: 0,
165            range: u32::MAX,
166            buf,
167            pos: 0,
168        };
169        for _ in 0..4 {
170            d.code = (d.code << 8) | d.next() as u32;
171        }
172        d
173    }
174
175    #[inline]
176    fn next(&mut self) -> u8 {
177        let b = self.buf.get(self.pos).copied().unwrap_or(0);
178        self.pos += 1;
179        b
180    }
181
182    /// Decode a bit coded with `P(1) = p1 / 2^16`.
183    #[inline]
184    pub fn decode_p(&mut self, p1: u32) -> bool {
185        let p0 = ONE - clamp_p(p1);
186        let bound = (self.range >> 16) * p0;
187        let bit = if self.code < bound {
188            self.range = bound;
189            false
190        } else {
191            self.code -= bound;
192            self.range -= bound;
193            true
194        };
195        while self.range < TOP {
196            self.range <<= 8;
197            self.code = (self.code << 8) | self.next() as u32;
198        }
199        bit
200    }
201
202    /// Decode with an adaptive model, then adapt it.
203    #[inline]
204    pub fn decode(&mut self, m: &mut BitModel) -> bool {
205        let b = self.decode_p(m.p1());
206        m.update(b);
207        b
208    }
209
210    /// `n` raw bits, MSB first.
211    pub fn decode_raw(&mut self, n: u32) -> u64 {
212        let mut v = 0;
213        for _ in 0..n {
214            v = (v << 1) | self.decode_p(ONE / 2) as u64;
215        }
216        v
217    }
218
219    /// Whether the decoder consumed more than the buffer (corrupt stream).
220    pub fn overrun(&self) -> bool {
221        self.pos > self.buf.len() + 4
222    }
223}
224
225/// Adaptive Elias-gamma style coder for unbounded non-negative integers:
226/// unary bucket `k = ⌊log₂(v+1)⌋` with one model per bucket position, then
227/// the `k` mantissa bits (top `MODELED` with models, the rest raw).
228#[derive(Clone, Debug)]
229pub struct UintModel {
230    unary: Vec<BitModel>,
231    mant: Vec<BitModel>,
232}
233
234const UBITS: usize = 40;
235const MODELED: usize = 2;
236
237impl Default for UintModel {
238    fn default() -> Self {
239        Self {
240            unary: vec![BitModel::default(); UBITS],
241            mant: vec![BitModel::default(); UBITS * MODELED],
242        }
243    }
244}
245
246impl UintModel {
247    /// Encode `v`.
248    pub fn encode(&mut self, e: &mut Encoder, v: u64) {
249        let w = v + 1;
250        let k = 63 - w.leading_zeros() as usize;
251        for i in 0..k {
252            e.encode(true, &mut self.unary[i]);
253        }
254        if k < UBITS - 1 {
255            e.encode(false, &mut self.unary[k]);
256        }
257        for (j, i) in (0..k).rev().enumerate() {
258            let bit = (w >> i) & 1 == 1;
259            if j < MODELED {
260                e.encode(bit, &mut self.mant[k * MODELED + j]);
261            } else {
262                e.encode_p(bit, ONE / 2);
263            }
264        }
265    }
266    /// Decode one value.
267    pub fn decode(&mut self, d: &mut Decoder) -> u64 {
268        let mut k = 0;
269        while k < UBITS - 1 && d.decode(&mut self.unary[k]) {
270            k += 1;
271        }
272        let mut w = 1u64;
273        for j in 0..k {
274            let bit = if j < MODELED {
275                d.decode(&mut self.mant[k * MODELED + j])
276            } else {
277                d.decode_p(ONE / 2)
278            };
279            w = (w << 1) | bit as u64;
280        }
281        w - 1
282    }
283}
284
285/// Ideal code length in bits of coding `bit` at `P(1) = p1 / 2^16`.
286#[inline]
287pub fn cost_bits(bit: bool, p1: u32) -> f64 {
288    let p = clamp_p(p1) as f64 / ONE as f64;
289    -(if bit { p } else { 1.0 - p }).log2()
290}
291
292#[cfg(test)]
293mod tests {
294    use super::*;
295
296    fn lcg(s: &mut u64) -> u64 {
297        *s = s
298            .wrapping_mul(6364136223846793005)
299            .wrapping_add(1442695040888963407);
300        *s >> 33
301    }
302
303    #[test]
304    fn round_trip_models_and_raw() {
305        let mut s = 7;
306        let bits: Vec<bool> = (0..200_000)
307            .map(|i| lcg(&mut s) % 100 < if i % 3 == 0 { 3 } else { 60 })
308            .collect();
309        let vals: Vec<u64> = (0..5000).map(|_| lcg(&mut s) % 3000).collect();
310        let mut e = Encoder::new();
311        let mut ms = [BitModel::default(); 3];
312        for (i, &b) in bits.iter().enumerate() {
313            e.encode(b, &mut ms[i % 3]);
314        }
315        let mut um = UintModel::default();
316        for &v in &vals {
317            um.encode(&mut e, v);
318        }
319        e.encode_raw(0xDEAD_BEEF, 32);
320        e.encode_p(true, 1);
321        e.encode_p(false, 70000);
322        let buf = e.finish();
323        let mut d = Decoder::new(&buf);
324        let mut ms = [BitModel::default(); 3];
325        for (i, &b) in bits.iter().enumerate() {
326            assert_eq!(d.decode(&mut ms[i % 3]), b, "bit {i}");
327        }
328        let mut um = UintModel::default();
329        for &v in &vals {
330            assert_eq!(um.decode(&mut d), v);
331        }
332        assert_eq!(d.decode_raw(32), 0xDEAD_BEEF);
333        assert!(d.decode_p(1));
334        assert!(!d.decode_p(70000));
335        // adaptive coding lands near the empirical entropy
336        let mut e = Encoder::new();
337        let mut m = BitModel::default();
338        let skew: Vec<bool> = (0..100_000).map(|_| lcg(&mut s) % 100 < 5).collect();
339        for &b in &skew {
340            e.encode(b, &mut m);
341        }
342        let h = -(0.05f64 * 0.05f64.log2() + 0.95 * 0.95f64.log2()) * 100_000.0;
343        let got = e.finish().len() as f64 * 8.0;
344        assert!(got < h * 1.05, "{got} vs {h}");
345    }
346
347    #[test]
348    fn carry_heavy_stream() {
349        // long runs of highly probable ones push `low` into carries
350        let mut e = Encoder::new();
351        for i in 0..100_000 {
352            e.encode_p(i % 997 != 0, ONE - P_MIN);
353        }
354        let buf = e.finish();
355        let mut d = Decoder::new(&buf);
356        for i in 0..100_000 {
357            assert_eq!(d.decode_p(ONE - P_MIN), i % 997 != 0);
358        }
359    }
360}