Asymmetric Numeral Systems

Asymmetric Numeral Systems (ANS) [1] is a family of entropy coding methods used in data compression since 2014[2] for example in the Facebook Zstandard compressor[3] and Apple LZFSE compressor,[4] due to improved performance compared to the previously used methods: it allows combination of the compression ratio of arithmetic coding (uses nearly accurate probability distribution), with a processing cost similar to Huffman coding (tANS variant constructs finite state machine to operate on large alphabet without using multiplication).

The basic concept is to directly encode information into a single natural number , increased approximately times while adding information from symbol of probability . For the encoding rule, the set of natural numbers is split into disjoint subsets corresponding to different symbols - like into even and odd numbers, but with densities corresponding to the probability distribution of symbols to encode. Then to add information from symbol into information already stored in the current number , we go to number being position of -th appearances from -th subset.

There are alternative ways to apply it in practice - direct mathematical formulas for encoding and decoding steps (uABS and rANS variants), or one can put the entire behavior into a table (tANS variant). Renormalization is used to prevent going to infinity - transferring accumulated bits to or from the bitstream.

Basic concepts

Comparison of the concept of arithmetic coding (left) and ANS (right). Both can be seen as generalization of standard numeral systems, optimal for uniform probability distribution of digits, into optimized for some chosen probability distribution. Arithmetic or range coding corresponds to adding new information in the most significant position, while ANS generalizes adding information in the least significant position. Its coding rule is "x goes to x-th appearance of subset of natural numbers corresponding to currently encoded symbol". In the presented example, sequence (01111) is encoded into a natural number 18, which is smaller than 45 obtained by using standard binary system, due to better agreement with frequencies of sequence to encode. The advantage of ANS is storing information in a single natural number, in contrast to two defining a range.

Imagine there is some information stored in a natural number , for example as bit sequence of its binary expansion. To add information from a binary variable , we can use coding function , which shifts all bits one position up, and place the new bit in the least significant position. Now decoding function allows to retrieve the previous and this added bit: . We can start with initial state, then use the function on the successive bits of a finite bit sequence to obtain a final number storing this entire sequence. Then using function multiple times until allows to retrieve the bit sequence in reversed order.

The above procedure is optimal for uniform (symmetric) probability distribution of symbols . ANS generalize it to make it optimal for any chosen (asymmetric) probability distribution of symbols: . While in the above example was choosing between even and odd , in ANS this even/odd division of natural numbers is replaced with division into subsets having densities corresponding to the assumed probability distribution : up to position , there is approximately occurrences of symbol .

The coding function returns the -th appearance from such subset corresponding to symbol . The density assumption is equivalent to condition . Assuming that a natural number contains bits information, . Hence the symbol of probability is encoded as containing bits of information as it is required from entropy coders.

Uniform binary variant (uABS)

Let us start with binary alphabet and probability distribution . Up to position we want approximately analogues of odd numbers (for ). We can choose this number of appearances as , getting . This is called uABS variant and leads to the following decoding and encoding functions:[5]

Decoding:

s = ceil((x+1)*p) - ceil(x*p)  // 0 if fract(x*p) < 1-p, else 1
if s = 0 then new_x = x - ceil(x*p)   // D(x) = (new_x, 0)
if s = 1 then new_x = ceil(x*p)  // D(x) = (new_x, 1)

Encoding:

if s = 0 then new_x = ceil((x+1)/(1-p)) - 1 // C(x,0) = new_x
if s = 1 then new_x = floor(x/p)  // C(x,1) = new_x

For it becomes standard binary system (with switched 0 and 1), for a different it becomes optimal for this given probability distribution. For example, for these formulas lead to table for small values of :

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13
0 1 2 3 4 5 6

Symbol corresponds to subset of natural numbers of density , which in this case are positions . As , these positions increase by 3 or 4. Because here, the pattern of symbols repeats every 10 positions.

The can be found by taking row corresponding to a given symbol , and take given in this row. Then top row provides . For example, from the middle to top row.

Imagine we would like to encode '0100' sequence starting from . First takes us to , then to , then to , then to . By using decoding function on this final , we can retrieve the symbol sequence. Using the table for this purpose, in first row determines column, then nonempty row and the written value determine correspondingly and .

Range variants (rANS) and streaming

Range variant also uses arithmetic formulas, but allows to operate on large alphabet. Intuitively, it divides the set of natural numbers into size ranges, and split each of them in identical way into subranges of proportions given by the assumed probability distribution.

We start with quanization of probability distribution to denominator, where is chosen (usually 8-12 bits): for some natural numbers (sizes of subranges).

Denote , cumulative distribution function: .

For denote function (usually tabled)

symbol(y) = s such that CDF[s] <= y < CDF[s+1] .

Now coding function is:

C(x,s) = floor(x / f[s]) << n) + (x % f[s]) + CDF[s]

Decoding: s = symbol(x & mask)

D(x) = (f[s] * (x >> n) + (x & mask ) - CDF[s], s)

This way we can encode a sequence of symbols into a large natural number . To avoid using large number arithmetic, in practice stream variants are used: which enforce by renormalization: sending the least significant bits of to or from the bitstream (usually and are powers of 2).

In rANS variant is for example 32 bit. For 16 bit renormalization, , decoder refills the least significant bits from the bitstream when needed:

if(x < (1 << 16)) x = (x << 16) + read16bits()

Tabled variant (tANS)

Simple example of 4 state ANS automaton for Pr(a) = 3/4, Pr(b) = 1/4 probability distribution. Symbol b contains −lg(1/4) = 2 bits of information and so it always produces two bits. In contrast, symbol a contains −lg(3/4) ~ 0.415 bits of information, hence sometimes it produces one bit (from state 6 and 7), sometimes 0 bits (from state 4 and 5), only increasing the state, which acts as buffer containing fractional number of bits: lg(x). The number of states in practice is for example 2048, for 256 size alphabet (to directly encode bytes).

tANS variant puts the entire behavior (including renormalization) for into a table, getting finite state machine avoiding the need of multiplication.

Finally step of decoding loop can be written as:

t = decodingTable(x);  
x = t.newX + readBits(t.nbBits); //state transition
writeSymbol(t.symbol); //decoded symbol

Step of encoding loop:

s = ReadSymbol();
nbBits = (x + ns[s]) >> r;  // # of bits for renormalization
writeBits(x, nbBits);  // send youngest bits to bitstream
x = encodingTable[start[s] + (x >> nbBits)];

A specific tANS coding is determined by assigning a symbol to every position, their number of appearances should be proportional to the assumed probabilities. For example one could choose "abdacdac" assignment for Pr(a)=3/8, Pr(b)=1/8, Pr(c)=2/8, Pr(d)=2/8 probability distribution. If symbols are assigned in ranges of lengths being powers of 2, we would get Huffman coding. For example a->0, b->100, c->101, d->11 prefix code would be obtained for tANS with "aaaabcdd" symbol assignment.

Remarks

As for Huffman coding, modifying the probability distribution of tANS is costly, hence they are used in static situations, usually with some Lempel–Ziv scheme (ZSTD, LZFSE). In this case, the file is divided into blocks and static probability distribution for each block is stored in its header.

In contrast, rANS is usually used as faster replacement for range coding. It requires multiplication, but is more memory efficient and is appropriate for dynamically adapting probability distributions.

Encoding and decoding of ANS are performed in opposite directions. This inconvenience is usually resolved by encoding in backward direction, thanks of it decoding can made forward. For context-dependence, like Markov model, the encoder needs to use context from the perspective of decoder. For adaptivity, the encoder should first go forward to find probabilities which will be used by decoder and store them in a buffer, then encode in backward direction using the found probabilities.

The final state of encoding is required to start decoding, hence it needs to be stored in the compressed file. This cost can be compensated by storing some information in the initial state of encoder.

See also

References

  1. J. Duda, K. Tahboub, N. J. Gadil, E. J. Delp, The use of asymmetric numeral systems as an accurate replacement for Huffman coding, Picture Coding Symposium, 2015.
  2. List of compressors using ANS, implementations and other materials
  3. Smaller and faster data compression with Zstandard, Facebook, August 2016
  4. Apple Open-Sources its New Compression Algorithm LZFSE, InfoQ, July 2016
  5. Data Compression Explained, Matt Mahoney

External links

This article is issued from Wikipedia - version of the 11/29/2016. The text is available under the Creative Commons Attribution/Share Alike but additional terms may apply for the media files.