Trait constriction::stream::Encode
source · pub trait Encode<const PRECISION: usize>: Code {
type FrontendError: Debug;
type BackendError: Debug;
fn encode_symbol<M>(
&mut self,
symbol: impl Borrow<M::Symbol>,
model: M
) -> Result<(), CoderError<Self::FrontendError, Self::BackendError>>
where
M: EncoderModel<PRECISION>,
M::Probability: Into<Self::Word>,
Self::Word: AsPrimitive<M::Probability>;
fn encode_symbols<S, M>(
&mut self,
symbols_and_models: impl IntoIterator<Item = (S, M)>
) -> Result<(), CoderError<Self::FrontendError, Self::BackendError>>
where
S: Borrow<M::Symbol>,
M: EncoderModel<PRECISION>,
M::Probability: Into<Self::Word>,
Self::Word: AsPrimitive<M::Probability>,
{ ... }
fn try_encode_symbols<S, M, E>(
&mut self,
symbols_and_models: impl IntoIterator<Item = Result<(S, M), E>>
) -> Result<(), TryCodingError<CoderError<Self::FrontendError, Self::BackendError>, E>>
where
S: Borrow<M::Symbol>,
M: EncoderModel<PRECISION>,
M::Probability: Into<Self::Word>,
Self::Word: AsPrimitive<M::Probability>,
{ ... }
fn encode_iid_symbols<S, M>(
&mut self,
symbols: impl IntoIterator<Item = S>,
model: M
) -> Result<(), CoderError<Self::FrontendError, Self::BackendError>>
where
S: Borrow<M::Symbol>,
M: EncoderModel<PRECISION> + Copy,
M::Probability: Into<Self::Word>,
Self::Word: AsPrimitive<M::Probability>,
{ ... }
fn maybe_full(&self) -> bool { ... }
}Expand description
A trait for stream encoders (i.e., compressors)
This trait defines methods for encoding a single symbol or a sequence of symbols.
Naming Convention
This trait is deliberately called Encode and not Encoder. See corresponding comment
for the Code trait for the reasoning.
Required Associated Types§
sourcetype FrontendError: Debug
type FrontendError: Debug
The error type for logical encoding errors.
This is often a DefaultEncoderFrontendError.
Frontend errors are errors that relate to the logical encoding process, such as when a user tries to encode a symbol that has zero probability under the provided entropy model. They are to be distinguished from backend errors, which depend on the used sources and/or sinks of compressed data, and which can be errors like “out of space” or “I/O error”.
sourcetype BackendError: Debug
type BackendError: Debug
The error type for writing out encoded data.
If you stick with the default backend(s) and don’t do anything fancy, then this will
most likely be Infallible, which means that the compiler can optimize away error
checks. You can explicitly express that you expect an Infallible error type by
calling .unwrap_infallible() on a Result<T, Infallible> or on a Result<T, CoderError<Infallible, Infallible>> (you’ll have to bring the trait
UnwrapInfallible into scope).
If you use a custom backend, then the BackendError will typically be the
WriteError type of the of the backend. For example, it could signal an I/O error
if you’re encoding directly to a file or socket rather than to an automatically
growing in-memory buffer.
Required Methods§
sourcefn encode_symbol<M>(
&mut self,
symbol: impl Borrow<M::Symbol>,
model: M
) -> Result<(), CoderError<Self::FrontendError, Self::BackendError>>where
M: EncoderModel<PRECISION>,
M::Probability: Into<Self::Word>,
Self::Word: AsPrimitive<M::Probability>,
fn encode_symbol<M>(
&mut self,
symbol: impl Borrow<M::Symbol>,
model: M
) -> Result<(), CoderError<Self::FrontendError, Self::BackendError>>where
M: EncoderModel<PRECISION>,
M::Probability: Into<Self::Word>,
Self::Word: AsPrimitive<M::Probability>,
Encodes a single symbol with the given entropy model.
This is the most basic encoding method. If you want to encode more than a single
symbol then you may want to call encode_symbols, try_encode_symbols, or
encode_iid_symbols instead.
Note that:
- the
symbolcan be passed either by value or by reference; - the
modelcan also be passed by reference since, ifMimplementsEncoderModel<PRECISION>, then&Mdoes so too; and - the
PRECISIONwill typically be inferred from the entropy model, and it may not be larger thanWord::BITS; this is enforced by run-time assertions (that get optimized away unless they fail) but it will be enforced at compile time in future versions ofconstrictionas soon as the type system allows this.
Errors
Returns Err(CoderError::Frontend(e)) if there was a logic error e during
encoding (such as trying to encode a symbol with zero probability under the provided
entropy model). Returns Err(CoderError::Backend(e)) if writing compressed data
lead to an I/O error e. Otherwise, returns Ok(()).
Example
use constriction::stream::{model::DefaultLeakyQuantizer, stack::DefaultAnsCoder, Encode};
// Create an ANS Coder and an entropy model.
let mut ans_coder = DefaultAnsCoder::new();
let quantizer = DefaultLeakyQuantizer::new(-100i32..=100);
let entropy_model = quantizer.quantize(probability::distribution::Gaussian::new(0.0, 10.0));
// Encode a symbol, passing both the symbol and the entropy model by reference:
ans_coder.encode_symbol(&12, &entropy_model).unwrap();
// Encode a symbol, passing both the symbol and the entropy model by value:
ans_coder.encode_symbol(-8, entropy_model).unwrap();
// Get the compressed bitstring.
let compressed = ans_coder.into_compressed();
dbg!(compressed);Provided Methods§
sourcefn encode_symbols<S, M>(
&mut self,
symbols_and_models: impl IntoIterator<Item = (S, M)>
) -> Result<(), CoderError<Self::FrontendError, Self::BackendError>>where
S: Borrow<M::Symbol>,
M: EncoderModel<PRECISION>,
M::Probability: Into<Self::Word>,
Self::Word: AsPrimitive<M::Probability>,
fn encode_symbols<S, M>(
&mut self,
symbols_and_models: impl IntoIterator<Item = (S, M)>
) -> Result<(), CoderError<Self::FrontendError, Self::BackendError>>where
S: Borrow<M::Symbol>,
M: EncoderModel<PRECISION>,
M::Probability: Into<Self::Word>,
Self::Word: AsPrimitive<M::Probability>,
Encodes a sequence of symbols, each with its individual entropy model.
The provided iterator has to yield pairs (symbol, entropy_model). The default
implemnetation just calls encode_symbol for each item. You can overwrite the
default implementation if your entropy coder can treat a sequence of symbols in a
more efficient way.
This method short-circuits as soon as encoding leads to an error (see discussion of
error states for encode_symbol).
This method encodes the symbols in the order in which they are yielded by the
iterator. This is suitable for an encoder with “queue” semantics, like a
RangeEncoder. If you’re using an encoder with “stack” semantics, such as an
AnsCoder, then you may prefer encoding the symbols in reverse order (see
AnsCoder::encode_symbols_reverse).
Note that:
- the
symbols can be yielded either by value or by reference; - the
models can also be yielded either by value or by reference since, ifMimplementsEncoderModel<PRECISION>, then&Mdoes so too; and - the iterator has to yield models of a fixed type (unless you want to
Boxup each model, which is most likely a bad idea); if you have entropy models of various types then just call either this method orencode_symbolseveral times manually.
See Also
try_encode_symbolsif generating the entropy models may fail; andencode_iid_symbolsif all symbols use the same entropy model.
Example
use constriction::stream::{model::DefaultLeakyQuantizer, queue::DefaultRangeEncoder, Encode};
// Define the symbols we want to encode and the parameters of our entropy models.
let quantizer = DefaultLeakyQuantizer::new(-100i32..=100);
let symbols = [15, 3, -8, 2];
let means = [10.2, 1.5, -3.9, 5.1];
let stds = [7.1, 5.8, 10.9, 6.3];
let entropy_model = quantizer.quantize(probability::distribution::Gaussian::new(0.0, 10.0));
// Encode all symbols using range coding.
let mut encoder1 = DefaultRangeEncoder::new();
encoder1.encode_symbols(
symbols.iter().zip(&means).zip(&stds).map(
|((&symbol, &mean), &std)|
(symbol, quantizer.quantize(probability::distribution::Gaussian::new(mean, std)))
)
).unwrap();
let compressed1 = encoder1.into_compressed();
// The above is equivalent to:
let mut encoder2 = DefaultRangeEncoder::new();
for ((&symbol, &mean), &std) in symbols.iter().zip(&means).zip(&stds) {
let model = quantizer.quantize(probability::distribution::Gaussian::new(mean, std));
encoder2.encode_symbol(symbol, model).unwrap();
}
let compressed2 = encoder2.into_compressed();
assert_eq!(compressed1, compressed2);sourcefn try_encode_symbols<S, M, E>(
&mut self,
symbols_and_models: impl IntoIterator<Item = Result<(S, M), E>>
) -> Result<(), TryCodingError<CoderError<Self::FrontendError, Self::BackendError>, E>>where
S: Borrow<M::Symbol>,
M: EncoderModel<PRECISION>,
M::Probability: Into<Self::Word>,
Self::Word: AsPrimitive<M::Probability>,
fn try_encode_symbols<S, M, E>(
&mut self,
symbols_and_models: impl IntoIterator<Item = Result<(S, M), E>>
) -> Result<(), TryCodingError<CoderError<Self::FrontendError, Self::BackendError>, E>>where
S: Borrow<M::Symbol>,
M: EncoderModel<PRECISION>,
M::Probability: Into<Self::Word>,
Self::Word: AsPrimitive<M::Probability>,
Encodes a sequence of symbols from a fallible iterator.
This method is equivalent to encode_symbols, except that
it takes a fallible iterator (i.e., an iterator that yields Results). It encodes
symbols as long as the iterator yields Ok((symbol, entropy_model)) and encoding
succeeds. The method short-circuits as soon as either
- the iterator yields
Err(e), in which case it returnsErr(TryCodingError::InvalidEntropyModel(e))to the caller; or - encoding fails with
Err(e), in which case it returnsErr(TryCodingError::CodingError(e)).
This method may be useful for parameterized entropy models whose parameters have to satisfy certain constraints (e.g., they have to be positive), but they come from an untrusted source they may violate the constraints.
sourcefn encode_iid_symbols<S, M>(
&mut self,
symbols: impl IntoIterator<Item = S>,
model: M
) -> Result<(), CoderError<Self::FrontendError, Self::BackendError>>where
S: Borrow<M::Symbol>,
M: EncoderModel<PRECISION> + Copy,
M::Probability: Into<Self::Word>,
Self::Word: AsPrimitive<M::Probability>,
fn encode_iid_symbols<S, M>(
&mut self,
symbols: impl IntoIterator<Item = S>,
model: M
) -> Result<(), CoderError<Self::FrontendError, Self::BackendError>>where
S: Borrow<M::Symbol>,
M: EncoderModel<PRECISION> + Copy,
M::Probability: Into<Self::Word>,
Self::Word: AsPrimitive<M::Probability>,
Encodes a sequence of symbols, all with the same entropy model.
This method short-circuits as soon as encoding leads to an error (see discussion of
error states for encode_symbol).
While this method takes model formally by value, you’ll typically want to pass the
EncoderModel by reference (which is possible since any reference to an
EncoderModel implements EncoderModel too). The bound on M: Copy prevents
accidental misuse in this regard. We provide the ability to pass the EncoderModel
by value as an opportunity for microoptimzations when dealing with models that can
be cheaply copied (see, e.g.,
ContiguousCategoricalEntropyModel::as_view).
Note that this method encodes the symbols in the order in which they are yielded by
the iterator. This is suitable for an encoder with “queue” semantics, like a
RangeEncoder. If you’re using an encoder with “stack” semantics, such as an
AnsCoder, then you may prefer encoding the symbols in reverse order (see
AnsCoder::encode_iid_symbols_reverse).
If you want to encode each symbol with its individual entropy model, then consider
calling encode_symbols instead. If you just want to encode a single symbol, then
call encode_symbol instead.
sourcefn maybe_full(&self) -> bool
fn maybe_full(&self) -> bool
Checks if there might not be any room to encode more data.
If this method returns false then encoding one more symbol must not fail due to a
full backend (it may still fail for other reasons). If this method returns true
then it is unknown whether or not encoding one more symbol will overflow the
backend.
The default implementation always returns true, which is always correct albeit not
particularly useful. Consider overwriting the default implementation and call
WriteWords::maybe_full on your backend if appropriate.
Calling this method can be awkward for entropy coders that implement
Encode<PRECISION> for more than one value of PRECISION. The method
Code::encoder_maybe_full is provided as a more convenient forwarding method.