arithmetic_coding_core/model/
one_shot.rs

1//! Helper trait for creating Models which only accept a single symbol
2
3use std::ops::Range;
4
5pub use crate::fixed_length::Wrapper;
6use crate::{fixed_length, BitStore};
7
8/// A [`Model`] is used to calculate the probability of a given symbol occurring
9/// in a sequence.
10///
11/// The [`Model`] is used both for encoding and decoding. A
12/// 'one-shot' only ever encodes a single symbol, and so does
13/// not need to encode an EOF symbol.
14///
15/// A one-shot [`Model`] is a special case of the [`fixed_length::Model`].
16///
17/// A one-shot model can be converted into a regular model using the
18/// convenience [`Wrapper`] type.
19///
20/// The more accurately a [`Model`] is able to predict the next symbol, the
21/// greater the compression ratio will be.
22///
23/// # Example
24///
25/// ```
26/// # use std::convert::Infallible;
27/// # use std::ops::Range;
28/// #
29/// # use arithmetic_coding_core::one_shot;
30///
31/// pub enum Symbol {
32///     A,
33///     B,
34///     C,
35/// }
36///
37/// pub struct MyModel;
38///
39/// impl one_shot::Model for MyModel {
40///     type B = u32;
41///     type Symbol = Symbol;
42///     type ValueError = Infallible;
43///
44///     fn probability(&self, symbol: &Self::Symbol) -> Result<Range<u32>, Infallible> {
45///         Ok(match symbol {
46///             Symbol::A => 0..1,
47///             Symbol::B => 1..2,
48///             Symbol::C => 2..3,
49///         })
50///     }
51///
52///     fn symbol(&self, value: Self::B) -> Self::Symbol {
53///         match value {
54///             0..1 => Symbol::A,
55///             1..2 => Symbol::B,
56///             2..3 => Symbol::C,
57///             _ => unreachable!(),
58///         }
59///     }
60///
61///     fn max_denominator(&self) -> u32 {
62///         3
63///     }
64/// }
65/// ```
66pub trait Model {
67    /// The type of symbol this [`Model`] describes
68    type Symbol;
69
70    /// Invalid symbol error
71    type ValueError: std::error::Error;
72
73    /// The internal representation to use for storing integers
74    type B: BitStore;
75
76    /// Given a symbol, return an interval representing the probability of that
77    /// symbol occurring.
78    ///
79    /// This is given as a range, over the denominator given by
80    /// [`Model::denominator`]. This range should in general include `EOF`,
81    /// which is denoted by `None`.
82    ///
83    /// For example, from the set {heads, tails}, the interval representing
84    /// heads could be `0..1`, and tails would be `1..2`, and `EOF` could be
85    /// `2..3` (with a denominator of `3`).
86    ///
87    /// This is the inverse of the [`Model::symbol`] method
88    ///
89    /// # Errors
90    ///
91    /// This returns a custom error if the given symbol is not valid
92    fn probability(&self, symbol: &Self::Symbol) -> Result<Range<Self::B>, Self::ValueError>;
93
94    /// The maximum denominator used for probability ranges. See
95    /// [`Model::probability`].
96    ///
97    /// This value is used to calculate an appropriate precision for the
98    /// encoding, therefore this value must not change, and
99    /// [`Model::denominator`] must never exceed it.
100    fn max_denominator(&self) -> Self::B;
101
102    /// Given a value, return the symbol whose probability range it falls in.
103    ///
104    /// `None` indicates `EOF`
105    ///
106    /// This is the inverse of the [`Model::probability`] method
107    fn symbol(&self, value: Self::B) -> Self::Symbol;
108}
109
110impl<T> fixed_length::Model for T
111where
112    T: Model,
113{
114    type B = T::B;
115    type Symbol = T::Symbol;
116    type ValueError = T::ValueError;
117
118    fn probability(&self, symbol: &Self::Symbol) -> Result<Range<Self::B>, Self::ValueError> {
119        Model::probability(self, symbol)
120    }
121
122    fn max_denominator(&self) -> Self::B {
123        self.max_denominator()
124    }
125
126    fn symbol(&self, value: Self::B) -> Self::Symbol {
127        Model::symbol(self, value)
128    }
129
130    fn length(&self) -> usize {
131        1
132    }
133
134    fn denominator(&self) -> Self::B {
135        self.max_denominator()
136    }
137}